From kde-commits Mon Jul 31 21:34:17 2017 From: Matthieu Gallien Date: Mon, 31 Jul 2017 21:34:17 +0000 To: kde-commits Subject: [elisa] /: introduce elisa_local_file kcm module to configure path for elisa music indexer Message-Id: X-MARC-Message: https://marc.info/?l=kde-commits&m=150153687120868 Git commit f47e0047fde2ee1cbcd34a24547d7ab70e67264a by Matthieu Gallien. Committed on 31/07/2017 at 21:33. Pushed by mgallien into branch 'master'. introduce elisa_local_file kcm module to configure path for elisa music ind= exer allow to configure the paths searched by elisa local music files indexer M +2 -2 CMakeLists.txt M +38 -8 autotests/CMakeLists.txt M +0 -4 config-upnp-qt.h.cmake M +10 -14 src/CMakeLists.txt M +10 -1 src/MediaServer.qml M +18 -6 src/abstractfile/abstractfilelistener.cpp M +10 -2 src/abstractfile/abstractfilelistener.h M +5 -0 src/abstractfile/abstractfilelisting.cpp M +6 -2 src/abstractfile/abstractfilelisting.h M +5 -0 src/allalbumsmodel.cpp M +2 -0 src/allalbumsmodel.h M +4 -1 src/baloo/baloolistener.cpp M +2 -0 src/baloo/localbaloofilelisting.cpp M +164 -57 src/databaseinterface.cpp M +4 -0 src/databaseinterface.h M +19 -7 src/elisaapplication.cpp M +6 -0 src/elisaapplication.h M +14 -1 src/file/filelistener.cpp M +5 -2 src/file/filelistener.h M +8 -7 src/file/localfilelisting.cpp M +2 -0 src/file/localfilelisting.h A +31 -0 src/localFileConfiguration/CMakeLists.txt A +13 -0 src/localFileConfiguration/kcm_elisa_local_file.desktop A +117 -0 src/localFileConfiguration/localfileconfiguration.cpp [L= icense: LGPL (v3+)] C +23 -22 src/localFileConfiguration/localfileconfiguration.h [from: s= rc/file/localfilelisting.h - 057% similarity] A +154 -0 src/localFileConfiguration/package/contents/ui/main.qml = [License: LGPL (v3+)] A +16 -0 src/localFileConfiguration/package/metadata.desktop M +108 -28 src/musiclistenersmanager.cpp M +8 -0 src/musiclistenersmanager.h M +7 -0 src/upnpControl.cpp https://commits.kde.org/elisa/f47e0047fde2ee1cbcd34a24547d7ab70e67264a diff --git a/CMakeLists.txt b/CMakeLists.txt index 523ff0c..c8ce6d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,10 +27,10 @@ find_package(KF5Baloo ${REQUIRED_KF5_VERSION} CONFIG QU= IET) find_package(KF5FileMetaData ${REQUIRED_KF5_VERSION} CONFIG QUIET) find_package(KF5DocTools ${REQUIRED_KF5_VERSION} CONFIG QUIET) find_package(KF5XmlGui ${REQUIRED_KF5_VERSION} CONFIG QUIET) -find_package(KF5ConfigWidgets ${REQUIRED_KF5_VERSION} CONFIG QUIET) -find_package(KF5Config ${REQUIRED_KF5_VERSION} CONFIG QUIET) +find_package(KF5Config ${REQUIRED_KF5_VERSION} CONFIG REQUIRED QUIET) find_package(KF5Crash ${REQUIRED_KF5_VERSION} CONFIG QUIET) find_package(KF5DBusAddons ${REQUIRED_KF5_VERSION} CONFIG QUIET) +find_package(KF5KCMUtils ${REQUIRED_KF5_VERSION} CONFIG REQUIRED QUIET) = find_package(UPNPQT CONFIG QUIET) set_package_properties(UPNPQT PROPERTIES diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index 453c6cb..d41e359 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -1,6 +1,7 @@ enable_testing() = include_directories(${elisa_BINARY_DIR}) +include_directories(${elisa_BINARY_DIR}/src) = set(databaseInterfaceTest_SOURCES ../src/databaseinterface.cpp @@ -60,9 +61,15 @@ if (KF5FileMetaData_FOUND) ) endif() = +kconfig_add_kcfg_files(playListControlerTest_SOURCES ../src/elisa_settings= .kcfgc ) +set(playListControlerTest_SOURCES + ${playListControlerTest_SOURCES} + ../src/elisa_core.kcfg +) + add_executable(playListControlerTest ${playListControlerTest_SOURCES}) = -target_link_libraries(playListControlerTest Qt5::Test Qt5::Core Qt5::Sql K= F5::I18n) +target_link_libraries(playListControlerTest Qt5::Test Qt5::Core Qt5::Sql K= F5::I18n KF5::ConfigCore KF5::ConfigGui) if (KF5Baloo_FOUND) target_link_libraries(playListControlerTest KF5::Baloo Qt5::DBus) endif() @@ -121,9 +128,15 @@ if (KF5FileMetaData_FOUND) ) endif() = +kconfig_add_kcfg_files(managemediaplayercontrolTest_SOURCES ../src/elisa_s= ettings.kcfgc ) +set(managemediaplayercontrolTest_SOURCES + ${managemediaplayercontrolTest_SOURCES} + ../src/elisa_core.kcfg +) + add_executable(managemediaplayercontrolTest ${managemediaplayercontrolTest= _SOURCES}) = -target_link_libraries(managemediaplayercontrolTest Qt5::Test Qt5::Core Qt5= ::Sql KF5::I18n) +target_link_libraries(managemediaplayercontrolTest Qt5::Test Qt5::Core Qt5= ::Sql KF5::I18n KF5::ConfigCore KF5::ConfigGui) if (KF5Baloo_FOUND) target_link_libraries(managemediaplayercontrolTest KF5::Baloo Qt5::DBu= s) endif() @@ -183,9 +196,15 @@ if (KF5FileMetaData_FOUND) ) endif() = +kconfig_add_kcfg_files(manageheaderbarTest_SOURCES ../src/elisa_settings.k= cfgc ) +set(manageheaderbarTest_SOURCES + ${manageheaderbarTest_SOURCES} + ../src/elisa_core.kcfg +) + add_executable(manageheaderbarTest ${manageheaderbarTest_SOURCES}) = -target_link_libraries(manageheaderbarTest Qt5::Test Qt5::Core Qt5::Sql Qt5= ::Gui KF5::I18n) +target_link_libraries(manageheaderbarTest Qt5::Test Qt5::Core Qt5::Sql Qt5= ::Gui KF5::I18n KF5::ConfigCore KF5::ConfigGui) if (KF5Baloo_FOUND) target_link_libraries(manageheaderbarTest KF5::Baloo Qt5::DBus) endif() @@ -253,9 +272,15 @@ if (KF5FileMetaData_FOUND) ) endif() = +kconfig_add_kcfg_files(mediaplaylistTest_SOURCES ../src/elisa_settings.kcf= gc ) +set(mediaplaylistTest_SOURCES + ${mediaplaylistTest_SOURCES} + ../src/elisa_core.kcfg +) + add_executable(mediaplaylistTest ${mediaplaylistTest_SOURCES}) = -target_link_libraries(mediaplaylistTest Qt5::Test Qt5::Core Qt5::Sql Qt5::= Gui KF5::I18n) +target_link_libraries(mediaplaylistTest Qt5::Test Qt5::Core Qt5::Sql Qt5::= Gui KF5::I18n KF5::ConfigCore KF5::ConfigGui) if (KF5Baloo_FOUND) target_link_libraries(mediaplaylistTest KF5::Baloo Qt5::DBus) endif() @@ -333,11 +358,16 @@ if (KF5FileMetaData_FOUND) localfilelistingtest.cpp ) = + kconfig_add_kcfg_files(localfilelistingtest_SOURCES ../src/elisa_setti= ngs.kcfgc ) + set(localfilelistingtest_SOURCES + ${localfilelistingtest_SOURCES} + ../src/elisa_core.kcfg + ) + add_executable(localfilelistingtest ${localfilelistingtest_SOURCES}) - target_link_libraries(localfilelistingtest Qt5::Test Qt5::Core Qt5::Sq= l KF5::I18n) - if (KF5FileMetaData_FOUND) - target_link_libraries(localfilelistingtest KF5::FileMetaData) - endif() + target_link_libraries(localfilelistingtest Qt5::Test Qt5::Core Qt5::Sq= l KF5::I18n KF5::ConfigCore KF5::ConfigGui KF5::FileMetaData) + target_include_directories(localfilelistingtest PRIVATE ${CMAKE_SOURCE= _DIR}/src) add_test(localfilelistingtest localfilelistingtest) + endif() diff --git a/config-upnp-qt.h.cmake b/config-upnp-qt.h.cmake index 6628774..80316c5 100644 --- a/config-upnp-qt.h.cmake +++ b/config-upnp-qt.h.cmake @@ -8,10 +8,6 @@ = #cmakedefine01 KF5XmlGui_FOUND = -#cmakedefine01 KF5ConfigWidgets_FOUND - -#cmakedefine01 KF5Config_FOUND - #cmakedefine01 KF5Crash_FOUND = #cmakedefine01 KF5FileMetaData_FOUND diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6f21bfd..aec7d54 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -101,6 +101,12 @@ if (Qt5Quick_FOUND AND Qt5Widgets_FOUND) ) endif() = + kconfig_add_kcfg_files(elisa_SOURCES elisa_settings.kcfgc) + set(elisa_SOURCES + ${elisa_SOURCES} + elisa_core.kcfg + ) + qt5_add_resources(elisa_SOURCES upnpControl.qrc) = add_executable(elisa ${elisa_SOURCES}) @@ -119,6 +125,8 @@ if (Qt5Quick_FOUND AND Qt5Widgets_FOUND) Qt5::Xml Qt5::Sql KF5::I18n + KF5::ConfigCore + KF5::KCMUtils ) = if (Qt5DBus_FOUND) @@ -170,20 +178,6 @@ if (Qt5Quick_FOUND AND Qt5Widgets_FOUND) ) endif() = - if (KF5ConfigWidgets_FOUND) - target_link_libraries(elisa - LINK_PRIVATE - KF5::ConfigWidgets - ) - endif() - - if (KF5Config_FOUND) - target_link_libraries(elisa - LINK_PRIVATE - KF5::ConfigCore - ) - endif() - if (KF5Crash_FOUND) target_link_libraries(elisa LINK_PRIVATE @@ -208,3 +202,5 @@ if (Qt5Quick_FOUND AND Qt5Widgets_FOUND) endif() = install(TARGETS elisa ${INSTALL_TARGETS_DEFAULT_ARGS}) + +add_subdirectory(localFileConfiguration) diff --git a/src/MediaServer.qml b/src/MediaServer.qml index b7caf65..7eb98f0 100644 --- a/src/MediaServer.qml +++ b/src/MediaServer.qml @@ -46,6 +46,7 @@ ApplicationWindow { property var reportBugAction: elisa.action("help_report_bug") property var aboutAppAction: elisa.action("help_about_app") property var configureShortcutsAction: elisa.action("options_configure= _keybinding") + property var configureAction: elisa.action("options_configure") = SystemPalette { id: myPalette @@ -328,6 +329,14 @@ ApplicationWindow { } = MenuItem { + text: configureAction.text + shortcut: configureAction.shortcut + iconName: 'configure' + onTriggered: configureAction.trigger() + visible: configureAction.text !=3D=3D "" + } + + MenuItem { text: configureShortcutsAction.text shortcut: configureShortcutsAction.shortcut iconName: elisa.iconName(configureShortcutsAction.icon) @@ -336,7 +345,7 @@ ApplicationWindow { } = MenuSeparator { - visible: configureShortcutsAction.text !=3D=3D "" + visible: configureAction.text !=3D=3D "" || configureShortcuts= Action.text !=3D=3D "" } = MenuItem { diff --git a/src/abstractfile/abstractfilelistener.cpp b/src/abstractfile/a= bstractfilelistener.cpp index a4cc4b5..132c5ef 100644 --- a/src/abstractfile/abstractfilelistener.cpp +++ b/src/abstractfile/abstractfilelistener.cpp @@ -28,25 +28,23 @@ class AbstractFileListenerPrivate { public: = - explicit AbstractFileListenerPrivate(AbstractFileListing *aFileListing= ) : mFileListing(aFileListing) + explicit AbstractFileListenerPrivate() { } = QThread mFileQueryThread; = - AbstractFileListing *mFileListing; + AbstractFileListing *mFileListing =3D nullptr; = }; = -AbstractFileListener::AbstractFileListener(AbstractFileListing *aFileListi= ng, QObject *parent) : QObject(parent), d(new AbstractFileListenerPrivate(a= FileListing)) +AbstractFileListener::AbstractFileListener(QObject *parent) + : QObject(parent), d(new AbstractFileListenerPrivate) { - d->mFileQueryThread.start(); - d->mFileListing->moveToThread(&d->mFileQueryThread); } = AbstractFileListener::~AbstractFileListener() { - delete d->mFileListing; delete d; } = @@ -78,10 +76,24 @@ void AbstractFileListener::applicationAboutToQuit() d->mFileQueryThread.wait(); } = +void AbstractFileListener::setFileListing(AbstractFileListing *fileIndexer) +{ + d->mFileListing =3D fileIndexer; + d->mFileQueryThread.start(); + d->mFileListing->moveToThread(&d->mFileQueryThread); + connect(fileIndexer, &AbstractFileListing::indexingFinished, + this, &AbstractFileListener::indexingFinished); +} + AbstractFileListing *AbstractFileListener::fileListing() const { return d->mFileListing; } = +void AbstractFileListener::performInitialScan() +{ + d->mFileListing->refreshContent(); +} + = #include "moc_abstractfilelistener.cpp" diff --git a/src/abstractfile/abstractfilelistener.h b/src/abstractfile/abs= tractfilelistener.h index d033084..aa34a24 100644 --- a/src/abstractfile/abstractfilelistener.h +++ b/src/abstractfile/abstractfilelistener.h @@ -39,12 +39,14 @@ class AbstractFileListener : public QObject NOTIFY databaseInterfaceChanged) = public: - explicit AbstractFileListener(AbstractFileListing *aFileListing, QObje= ct *parent =3D 0); + explicit AbstractFileListener(QObject *parent =3D 0); = virtual ~AbstractFileListener(); = DatabaseInterface* databaseInterface() const; = + AbstractFileListing* fileListing() const; + Q_SIGNALS: = void databaseInterfaceChanged(); @@ -53,15 +55,21 @@ Q_SIGNALS: = void newTrackFile(const MusicAudioTrack &newTrack); = + void indexingFinished(); + + void configurationChanged(); + public Q_SLOTS: = + void performInitialScan(); + void setDatabaseInterface(DatabaseInterface* databaseInterface); = void applicationAboutToQuit(); = protected: = - AbstractFileListing* fileListing() const; + void setFileListing(AbstractFileListing *fileIndexer); = private: = diff --git a/src/abstractfile/abstractfilelisting.cpp b/src/abstractfile/ab= stractfilelisting.cpp index e0ee14f..d768edc 100644 --- a/src/abstractfile/abstractfilelisting.cpp +++ b/src/abstractfile/abstractfilelisting.cpp @@ -428,5 +428,10 @@ void AbstractFileListing::removeFile(const QUrl &oneRe= movedTrack, QList &a } } = +void AbstractFileListing::setSourceName(const QString &name) +{ + d->mSourceName =3D name; +} + = #include "moc_abstractfilelisting.cpp" diff --git a/src/abstractfile/abstractfilelisting.h b/src/abstractfile/abst= ractfilelisting.h index 9ba4344..4b2561a 100644 --- a/src/abstractfile/abstractfilelisting.h +++ b/src/abstractfile/abstractfilelisting.h @@ -44,6 +44,8 @@ public: = virtual void applicationAboutToQuit(); = + const QString &sourceName() const; + Q_SIGNALS: = void tracksList(const QList &tracks, const QHash &covers, const QString &musicSource); @@ -52,6 +54,8 @@ Q_SIGNALS: = void modifyTracksList(const QList &modifiedTracks, co= nst QHash &covers); = + void indexingFinished(); + public Q_SLOTS: = void refreshContent(); @@ -76,8 +80,6 @@ protected: = void scanDirectory(QList &newFiles, const QUrl &path); = - const QString &sourceName() const; - virtual MusicAudioTrack scanOneFile(const QUrl &scanFile); = void watchPath(const QString &pathName); @@ -96,6 +98,8 @@ protected: = void removeFile(const QUrl &oneRemovedTrack, QList &allRemovedFi= les); = + void setSourceName(const QString &name); + private: = std::unique_ptr d; diff --git a/src/allalbumsmodel.cpp b/src/allalbumsmodel.cpp index 39e4fbc..fc28181 100644 --- a/src/allalbumsmodel.cpp +++ b/src/allalbumsmodel.cpp @@ -51,6 +51,11 @@ AllAlbumsModel::~AllAlbumsModel() delete d; } = +int AllAlbumsModel::albumCount() const +{ + return rowCount({}); +} + int AllAlbumsModel::rowCount(const QModelIndex &parent) const { auto albumCount =3D 0; diff --git a/src/allalbumsmodel.h b/src/allalbumsmodel.h index 62f2a42..c29e13b 100644 --- a/src/allalbumsmodel.h +++ b/src/allalbumsmodel.h @@ -58,6 +58,8 @@ public: = virtual ~AllAlbumsModel(); = + Q_INVOKABLE int albumCount() const; + int rowCount(const QModelIndex &parent =3D QModelIndex()) const overri= de; = QHash roleNames() const override; diff --git a/src/baloo/baloolistener.cpp b/src/baloo/baloolistener.cpp index be8d878..4d54bdd 100644 --- a/src/baloo/baloolistener.cpp +++ b/src/baloo/baloolistener.cpp @@ -28,10 +28,13 @@ class BalooListenerPrivate { public: = + LocalBalooFileListing mBalooFileIndexer; + }; = -BalooListener::BalooListener(QObject *parent) : AbstractFileListener(new L= ocalBalooFileListing, parent), d(new BalooListenerPrivate) +BalooListener::BalooListener(QObject *parent) : AbstractFileListener(paren= t), d(new BalooListenerPrivate) { + setFileListing(&d->mBalooFileIndexer); } = BalooListener::~BalooListener() diff --git a/src/baloo/localbaloofilelisting.cpp b/src/baloo/localbaloofile= listing.cpp index 9288238..a93d429 100644 --- a/src/baloo/localbaloofilelisting.cpp +++ b/src/baloo/localbaloofilelisting.cpp @@ -126,6 +126,8 @@ void LocalBalooFileListing::triggerRefreshOfContent() if (!newFiles.isEmpty() && d->mStopRequest =3D=3D 0) { emitNewFiles(newFiles); } + + Q_EMIT indexingFinished(); } = MusicAudioTrack LocalBalooFileListing::scanOneFile(const QUrl &scanFile) diff --git a/src/databaseinterface.cpp b/src/databaseinterface.cpp index ab19e50..45f738f 100644 --- a/src/databaseinterface.cpp +++ b/src/databaseinterface.cpp @@ -57,7 +57,8 @@ public: mInitialUpdateTracksValidity(mTracksDatabase), mUpdateTrackMappi= ng(mTracksDatabase), mSelectTracksMapping(mTracksDatabase), mSelectTracksMappingPrior= ity(mTracksDatabase), mUpdateAlbumArtUriFromAlbumIdQuery(mTracksDatabase), mUpdateAlbu= mArtistFromAlbumIdQuery(mTracksDatabase), - mInsertAlbumWithoutArtistQuery(mTracksDatabase), mSelectTracksMa= ppingPriorityByTrackId(mTracksDatabase) + mInsertAlbumWithoutArtistQuery(mTracksDatabase), mSelectTracksMa= ppingPriorityByTrackId(mTracksDatabase), + mSelectAllTrackFilesFromSourceQuery(mTracksDatabase) { } = @@ -137,6 +138,8 @@ public: = QSqlQuery mSelectTracksMappingPriorityByTrackId; = + QSqlQuery mSelectAllTrackFilesFromSourceQuery; + qulonglong mAlbumId =3D 1; = qulonglong mArtistId =3D 1; @@ -273,6 +276,13 @@ QList DatabaseInterface::allTracksFro= mSource(const QString &mus qDebug() << "DatabaseInterface::allAlbums" << d->mSelectAllTracksF= romSourceQuery.boundValues(); qDebug() << "DatabaseInterface::allAlbums" << d->mSelectAllTracksF= romSourceQuery.lastError(); = + d->mSelectAllTracksFromSourceQuery.finish(); + + transactionResult =3D finishTransaction(); + if (!transactionResult) { + return result; + } + return result; } = @@ -586,6 +596,81 @@ void DatabaseInterface::applicationAboutToQuit() d->mStopRequest =3D 1; } = +void DatabaseInterface::removeAllTracksFromSource(const QString &sourceNam= e) +{ + auto transactionResult =3D startTransaction(); + if (!transactionResult) { + return; + } + + d->mSelectMusicSource.bindValue(QStringLiteral(":name"), sourceName); + + auto queryResult =3D d->mSelectMusicSource.exec(); + + if (!queryResult || !d->mSelectMusicSource.isSelect() || !d->mSelectMu= sicSource.isActive()) { + qDebug() << "DatabaseInterface::insertMusicSource" << d->mSelectMu= sicSource.lastQuery(); + qDebug() << "DatabaseInterface::insertMusicSource" << d->mSelectMu= sicSource.boundValues(); + qDebug() << "DatabaseInterface::insertMusicSource" << d->mSelectMu= sicSource.lastError(); + + d->mSelectMusicSource.finish(); + + transactionResult =3D finishTransaction(); + if (!transactionResult) { + return; + } + + return; + } + + if (!d->mSelectMusicSource.next()) { + transactionResult =3D finishTransaction(); + if (!transactionResult) { + return; + } + + return; + } + + qulonglong sourceId =3D d->mSelectMusicSource.record().value(0).toULon= gLong(); + + d->mSelectMusicSource.finish(); + + d->mSelectAllTrackFilesFromSourceQuery.bindValue(QStringLiteral(":disc= overId"), sourceId); + + queryResult =3D d->mSelectAllTrackFilesFromSourceQuery.exec(); + + if (!queryResult || !d->mSelectAllTrackFilesFromSourceQuery.isSelect()= || !d->mSelectAllTrackFilesFromSourceQuery.isActive()) { + qDebug() << "DatabaseInterface::insertMusicSource" << d->mSelectAl= lTrackFilesFromSourceQuery.lastQuery(); + qDebug() << "DatabaseInterface::insertMusicSource" << d->mSelectAl= lTrackFilesFromSourceQuery.boundValues(); + qDebug() << "DatabaseInterface::insertMusicSource" << d->mSelectAl= lTrackFilesFromSourceQuery.lastError(); + + d->mSelectAllTrackFilesFromSourceQuery.finish(); + + transactionResult =3D finishTransaction(); + if (!transactionResult) { + return; + } + + return; + } + + QList allFileNames; + + while(d->mSelectAllTrackFilesFromSourceQuery.next()) { + auto fileName =3D d->mSelectAllTrackFilesFromSourceQuery.record().= value(0).toUrl(); + allFileNames.push_back(fileName); + } + + d->mSelectAllTrackFilesFromSourceQuery.finish(); + + internalRemoveTracksList(allFileNames); + + transactionResult =3D finishTransaction(); + if (!transactionResult) { + return; + } +} + void DatabaseInterface::insertTracksList(const QList &tra= cks, const QHash &covers, const QString &musicSource) { if (d->mStopRequest =3D=3D 1) { @@ -668,62 +753,7 @@ void DatabaseInterface::removeTracksList(const QList &removedTracks) return; } = - QList willRemoveTrack; - - for (const auto &removedTrackFileName : removedTracks) { - d->mSelectTrackFromFilePathQuery.bindValue(QStringLiteral(":filePa= th"), removedTrackFileName.toString()); - - auto result =3D d->mSelectTrackFromFilePathQuery.exec(); - - if (!result || !d->mSelectTrackFromFilePathQuery.isSelect() || !d-= >mSelectTrackFromFilePathQuery.isActive()) { - qDebug() << "DatabaseInterface::removeTracksList" << d->mSelec= tTrackFromFilePathQuery.lastQuery(); - qDebug() << "DatabaseInterface::removeTracksList" << d->mSelec= tTrackFromFilePathQuery.boundValues(); - qDebug() << "DatabaseInterface::removeTracksList" << d->mSelec= tTrackFromFilePathQuery.lastError(); - - continue; - } - - while (d->mSelectTrackFromFilePathQuery.next()) { - const auto ¤tRecord =3D d->mSelectTrackFromFilePathQuery= .record(); - - willRemoveTrack.push_back(buildTrackFromDatabaseRecord(current= Record)); - } - - d->mSelectTrackFromFilePathQuery.finish(); - } - - QSet modifiedAlbums; - - for (const auto &oneRemovedTrack : willRemoveTrack) { - removeTrackInDatabase(oneRemovedTrack.databaseId()); - Q_EMIT trackRemoved(oneRemovedTrack.databaseId()); - - const auto &modifiedAlbumId =3D internalAlbumIdFromTitle(oneRemove= dTrack.albumName()); - const auto &allArtistTracks =3D internalTracksFromAuthor(oneRemove= dTrack.artist()); - const auto &removedArtistId =3D internalArtistIdFromName(oneRemove= dTrack.artist()); - const auto &removedArtist =3D internalArtistFromId(removedArtistId= ); - - if (updateTracksCount(modifiedAlbumId)) { - modifiedAlbums.insert(modifiedAlbumId); - } - updateAlbumFromId(modifiedAlbumId, oneRemovedTrack.albumCover(), o= neRemovedTrack); - - if (allArtistTracks.isEmpty()) { - removeArtistInDatabase(removedArtistId); - Q_EMIT artistRemoved(removedArtist); - } - } - - for (auto modifiedAlbumId : modifiedAlbums) { - auto modifiedAlbum =3D internalAlbumFromId(modifiedAlbumId); - - if (modifiedAlbum.isValid() && !modifiedAlbum.isEmpty()) { - Q_EMIT albumModified(modifiedAlbum, modifiedAlbumId); - } else { - removeAlbumInDatabase(modifiedAlbum.databaseId()); - Q_EMIT albumRemoved(modifiedAlbum, modifiedAlbumId); - } - } + internalRemoveTracksList(removedTracks); = transactionResult =3D finishTransaction(); if (!transactionResult) { @@ -1400,6 +1430,21 @@ void DatabaseInterface::initRequest() } = { + auto selectAllTrackFilesFromSourceQueryText =3D QStringLiteral("SE= LECT " + "trac= ksMapping.`FileName` " + "FROM= " + "`Tra= cksMapping` tracksMapping " + "WHER= E " + "trac= ksMapping.`DiscoverID` =3D :discoverId"); + + auto result =3D d->mSelectAllTrackFilesFromSourceQuery.prepare(sel= ectAllTrackFilesFromSourceQueryText); + + if (!result) { + qDebug() << "DatabaseInterface::initRequest" << d->mSelectAllT= rackFilesFromSourceQuery.lastError(); + } + } + + { auto insertMusicSourceQueryText =3D QStringLiteral("INSERT OR IGNO= RE INTO `DiscoverSource` (`ID`, `Name`) " "VALUES (:discoverId, := name)"); = @@ -2052,6 +2097,68 @@ MusicAudioTrack DatabaseInterface::buildTrackFromDat= abaseRecord(const QSqlRecord return result; } = +void DatabaseInterface::internalRemoveTracksList(const QList &remove= dTracks) +{ + QList willRemoveTrack; + + qDebug() << "DatabaseInterface::internalRemoveTracksList" << removedTr= acks; + + for (const auto &removedTrackFileName : removedTracks) { + d->mSelectTrackFromFilePathQuery.bindValue(QStringLiteral(":filePa= th"), removedTrackFileName.toString()); + + auto result =3D d->mSelectTrackFromFilePathQuery.exec(); + + if (!result || !d->mSelectTrackFromFilePathQuery.isSelect() || !d-= >mSelectTrackFromFilePathQuery.isActive()) { + qDebug() << "DatabaseInterface::removeTracksList" << d->mSelec= tTrackFromFilePathQuery.lastQuery(); + qDebug() << "DatabaseInterface::removeTracksList" << d->mSelec= tTrackFromFilePathQuery.boundValues(); + qDebug() << "DatabaseInterface::removeTracksList" << d->mSelec= tTrackFromFilePathQuery.lastError(); + + continue; + } + + while (d->mSelectTrackFromFilePathQuery.next()) { + const auto ¤tRecord =3D d->mSelectTrackFromFilePathQuery= .record(); + + willRemoveTrack.push_back(buildTrackFromDatabaseRecord(current= Record)); + } + + d->mSelectTrackFromFilePathQuery.finish(); + } + + QSet modifiedAlbums; + + for (const auto &oneRemovedTrack : willRemoveTrack) { + removeTrackInDatabase(oneRemovedTrack.databaseId()); + Q_EMIT trackRemoved(oneRemovedTrack.databaseId()); + + const auto &modifiedAlbumId =3D internalAlbumIdFromTitle(oneRemove= dTrack.albumName()); + const auto &allArtistTracks =3D internalTracksFromAuthor(oneRemove= dTrack.artist()); + const auto &removedArtistId =3D internalArtistIdFromName(oneRemove= dTrack.artist()); + const auto &removedArtist =3D internalArtistFromId(removedArtistId= ); + + if (updateTracksCount(modifiedAlbumId)) { + modifiedAlbums.insert(modifiedAlbumId); + } + updateAlbumFromId(modifiedAlbumId, oneRemovedTrack.albumCover(), o= neRemovedTrack); + + if (allArtistTracks.isEmpty()) { + removeArtistInDatabase(removedArtistId); + Q_EMIT artistRemoved(removedArtist); + } + } + + for (auto modifiedAlbumId : modifiedAlbums) { + auto modifiedAlbum =3D internalAlbumFromId(modifiedAlbumId); + + if (modifiedAlbum.isValid() && !modifiedAlbum.isEmpty()) { + Q_EMIT albumModified(modifiedAlbum, modifiedAlbumId); + } else { + removeAlbumInDatabase(modifiedAlbum.databaseId()); + Q_EMIT albumRemoved(modifiedAlbum, modifiedAlbumId); + } + } +} + qulonglong DatabaseInterface::internalArtistIdFromName(const QString &name) { auto result =3D qulonglong(0); diff --git a/src/databaseinterface.h b/src/databaseinterface.h index cbc7947..0498a83 100644 --- a/src/databaseinterface.h +++ b/src/databaseinterface.h @@ -75,6 +75,8 @@ public: = void applicationAboutToQuit(); = + void removeAllTracksFromSource(const QString &sourceName); + Q_SIGNALS: = void artistAdded(const MusicArtist &newArtist); @@ -169,6 +171,8 @@ private: = MusicAudioTrack buildTrackFromDatabaseRecord(const QSqlRecord &trackRe= cord) const; = + void internalRemoveTracksList(const QList &removedTracks); + DatabaseInterfacePrivate *d; = }; diff --git a/src/elisaapplication.cpp b/src/elisaapplication.cpp index 1725c5e..9f06881 100644 --- a/src/elisaapplication.cpp +++ b/src/elisaapplication.cpp @@ -20,6 +20,8 @@ = #include "elisaapplication.h" = +#include "elisa_settings.h" + #if defined KF5XmlGui_FOUND && KF5XmlGui_FOUND #include #include @@ -27,13 +29,8 @@ #include #endif = -#if defined KF5ConfigWidgets_FOUND && KF5ConfigWidgets_FOUND #include -#endif - -#if defined KF5Config_FOUND && KF5Config_FOUND #include -#endif = #if defined KF5CoreAddons_FOUND && KF5CoreAddons_FOUND #include @@ -55,6 +52,8 @@ ElisaApplication::ElisaApplication(QObject *parent) : QOb= ject(parent) #endif { setupActions(); + + mConfigurationDialog.addModule(QStringLiteral("kcm_elisa_local_file")); } = void ElisaApplication::setupActions() @@ -78,8 +77,15 @@ void ElisaApplication::setupActions() mCollection.addAction(mAboutAppAction->objectName(), mAboutAppActi= on); } = - auto mKeyBindignsAction =3D KStandardAction::keyBindings(this, &ElisaA= pplication::configureShortcuts, this); - mCollection.addAction(mKeyBindignsAction->objectName(), mKeyBindignsAc= tion); + if (KAuthorized::authorizeAction(QStringLiteral("options_configure")))= { + auto mPreferencesAction =3D KStandardAction::preferences(this, &El= isaApplication::configureElisa, this); + mCollection.addAction(mPreferencesAction->objectName(), mPreferenc= esAction); + } + + if (KAuthorized::authorizeAction(QStringLiteral("options_configure_key= binding"))) { + auto mKeyBindignsAction =3D KStandardAction::keyBindings(this, &El= isaApplication::configureShortcuts, this); + mCollection.addAction(mKeyBindignsAction->objectName(), mKeyBindig= nsAction); + } = mCollection.readSettings(); #endif @@ -124,6 +130,12 @@ void ElisaApplication::configureShortcuts() #endif } = +void ElisaApplication::configureElisa() +{ + mConfigurationDialog.setModal(true); + mConfigurationDialog.show(); +} + QAction * ElisaApplication::action(const QString& name) { #if defined KF5XmlGui_FOUND && KF5XmlGui_FOUND diff --git a/src/elisaapplication.h b/src/elisaapplication.h index 46c06b2..81610ba 100644 --- a/src/elisaapplication.h +++ b/src/elisaapplication.h @@ -26,6 +26,8 @@ #include #endif = +#include + #include #include = @@ -56,12 +58,16 @@ public Q_SLOTS: = void configureShortcuts(); = + void configureElisa(); + private: = #if defined KF5XmlGui_FOUND && KF5XmlGui_FOUND KActionCollection mCollection; #endif = + KCMultiDialog mConfigurationDialog; + }; = #endif // ELISAAPPLICATION_H diff --git a/src/file/filelistener.cpp b/src/file/filelistener.cpp index cabcbe2..a8ba8e3 100644 --- a/src/file/filelistener.cpp +++ b/src/file/filelistener.cpp @@ -28,10 +28,13 @@ class FileListenerPrivate { public: = + LocalFileListing mLocalFileIndexer; + }; = -FileListener::FileListener(QObject *parent) : AbstractFileListener(new Loc= alFileListing, parent), d(new FileListenerPrivate) +FileListener::FileListener(QObject *parent) : AbstractFileListener(parent)= , d(new FileListenerPrivate) { + setFileListing(&d->mLocalFileIndexer); } = FileListener::~FileListener() @@ -39,5 +42,15 @@ FileListener::~FileListener() delete d; } = +const LocalFileListing& FileListener::localFileIndexer() const +{ + return d->mLocalFileIndexer; +} + +void FileListener::setRootPath(const QString &rootPath) +{ + d->mLocalFileIndexer.setRootPath(rootPath); +} + = #include "moc_filelistener.cpp" diff --git a/src/file/filelistener.h b/src/file/filelistener.h index c5e4fa7..47a4a31 100644 --- a/src/file/filelistener.h +++ b/src/file/filelistener.h @@ -27,8 +27,7 @@ #include = class FileListenerPrivate; -class DatabaseInterface; -class MusicAudioTrack; +class LocalFileListing; = class FileListener : public AbstractFileListener { @@ -39,10 +38,14 @@ public: = virtual ~FileListener(); = + const LocalFileListing& localFileIndexer() const; + Q_SIGNALS: = public Q_SLOTS: = + void setRootPath(const QString &rootPath); + private: = FileListenerPrivate *d =3D nullptr; diff --git a/src/file/localfilelisting.cpp b/src/file/localfilelisting.cpp index 92a7692..7553717 100644 --- a/src/file/localfilelisting.cpp +++ b/src/file/localfilelisting.cpp @@ -49,13 +49,6 @@ public: = LocalFileListing::LocalFileListing(QObject *parent) : AbstractFileListing(= QStringLiteral("local"), parent), d(new LocalFileListingPrivate) { - const auto &musicLocations(QStandardPaths::standardLocations(QStandard= Paths::MusicLocation)); - - if (musicLocations.isEmpty()) { - return; - } - - d->mRootPath =3D musicLocations.first(); } = LocalFileListing::~LocalFileListing() @@ -75,11 +68,19 @@ void LocalFileListing::setRootPath(const QString &rootP= ath) = d->mRootPath =3D rootPath; Q_EMIT rootPathChanged(); + + setSourceName(rootPath); +} + +void LocalFileListing::executeInit() +{ } = void LocalFileListing::triggerRefreshOfContent() { scanDirectoryTree(d->mRootPath); + + Q_EMIT indexingFinished(); } = = diff --git a/src/file/localfilelisting.h b/src/file/localfilelisting.h index 0fb59cb..fe68ccd 100644 --- a/src/file/localfilelisting.h +++ b/src/file/localfilelisting.h @@ -56,6 +56,8 @@ public Q_SLOTS: = private: = + void executeInit() override; + void triggerRefreshOfContent() override; = std::unique_ptr d; diff --git a/src/localFileConfiguration/CMakeLists.txt b/src/localFileConfi= guration/CMakeLists.txt new file mode 100644 index 0000000..468cc89 --- /dev/null +++ b/src/localFileConfiguration/CMakeLists.txt @@ -0,0 +1,31 @@ +set(KCM_ELISA_LOCAL_FILE_SRCS + localfileconfiguration.cpp + kcm_elisa_local_file.desktop + package/contents/ui/main.qml + package/metadata.desktop +) + +kconfig_add_kcfg_files(KCM_ELISA_LOCAL_FILE_SRCS ../elisa_settings.kcfgc ) +set(KCM_ELISA_LOCAL_FILE_SRCS + ${KCM_ELISA_LOCAL_FILE_SRCS} + ../elisa_core.kcfg +) + +add_library(kcm_elisa_local_file MODULE ${KCM_ELISA_LOCAL_FILE_SRCS}) + +target_link_libraries(kcm_elisa_local_file + KF5::ConfigCore + KF5::CoreAddons + KF5::Declarative + KF5::I18n + KF5::QuickAddons + KF5::ConfigWidgets +) + +kcoreaddons_desktop_to_json(kcm_elisa_local_file "kcm_elisa_local_file.des= ktop") + +install(FILES kcm_elisa_local_file.desktop DESTINATION ${SERVICES_INSTALL_= DIR}) +install(TARGETS kcm_elisa_local_file DESTINATION ${PLUGIN_INSTALL_DIR}/kcm= s) + +kpackage_install_package(package kcm_elisa_local_file kcms) + diff --git a/src/localFileConfiguration/kcm_elisa_local_file.desktop b/src/= localFileConfiguration/kcm_elisa_local_file.desktop new file mode 100644 index 0000000..fdb3b90 --- /dev/null +++ b/src/localFileConfiguration/kcm_elisa_local_file.desktop @@ -0,0 +1,13 @@ +[Desktop Entry] +Type=3DService +Icon=3Dalarm +Exec=3Dkcmshell5 kcm_elisa_local_file + +X-KDE-Library=3Dkcm_elisa_local_file +X-KDE-ServiceTypes=3DKCModule +X-KDE-ParentComponents=3Delisa +X-KDE-PluginKeyword=3Dkcm_elisa_local_file + +Name=3DElisa Local Files Indexer +Comment=3DA configuration tool for Elisa music player local files indexer +X-KDE-Keywords=3DElisa diff --git a/src/localFileConfiguration/localfileconfiguration.cpp b/src/lo= calFileConfiguration/localfileconfiguration.cpp new file mode 100644 index 0000000..508e78a --- /dev/null +++ b/src/localFileConfiguration/localfileconfiguration.cpp @@ -0,0 +1,117 @@ +/* + * Copyright 2017 Matthieu Gallien + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public Licen= se + * along with this library; 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 "localfileconfiguration.h" + +#include "elisa_settings.h" + +#include +#include +#include + +#include + +K_PLUGIN_FACTORY_WITH_JSON(KCMElisaLocalFileFactory, + "kcm_elisa_local_file.json", + registerPlugin();) + +KCMElisaLocalFile::KCMElisaLocalFile(QObject* parent, const QVariantList &= args) + : ConfigModule(parent, args) +{ + KAboutData *about =3D new KAboutData(QStringLiteral("kcm_elisa_local_f= ile"), + i18n("Elisa Local Files Indexer Con= figuration"), + QStringLiteral("0.1"), {}, KAboutLi= cense::LGPL_V3, + i18n("Copyright 20017 Matthieu Gall= ien ")); + + about->addAuthor(i18n("Matthieu Gallien"),i18n("Author"), QStringLiter= al("mgallien@mgallien.fr")); + setAboutData(about); + + auto configurationFileName =3D QStandardPaths::writableLocation(QStand= ardPaths::ConfigLocation); + configurationFileName +=3D QStringLiteral("/elisarc"); + Elisa::ElisaConfiguration::instance(configurationFileName); + + connect(Elisa::ElisaConfiguration::self(), &Elisa::ElisaConfiguration:= :configChanged, + this, &KCMElisaLocalFile::configChanged); + + setRootPath(Elisa::ElisaConfiguration::rootPath()); + Elisa::ElisaConfiguration::setRootPath(mRootPath); + Elisa::ElisaConfiguration::self()->save(); +} + +KCMElisaLocalFile::~KCMElisaLocalFile() +{ +} + +QStringList KCMElisaLocalFile::rootPath() const +{ + return mRootPath; +} + +void KCMElisaLocalFile::defaults() +{ + setRootPath(QStandardPaths::standardLocations(QStandardPaths::MusicLoc= ation)); +} + +void KCMElisaLocalFile::load() +{ + setRootPath(Elisa::ElisaConfiguration::rootPath()); +} + +void KCMElisaLocalFile::save() +{ + Elisa::ElisaConfiguration::setRootPath(mRootPath); + Elisa::ElisaConfiguration::self()->save(); +} + +void KCMElisaLocalFile::setRootPath(QStringList rootPath) +{ + if (mRootPath =3D=3D rootPath) { + return; + } + + mRootPath.clear(); + for (const auto &onePath : rootPath) { + if (onePath.startsWith(QStringLiteral("file:///"))) { + mRootPath.push_back(onePath.mid(7)); + } else if (onePath.startsWith(QStringLiteral("file:/"))) { + mRootPath.push_back(onePath.mid(5)); + } else { + mRootPath.push_back(onePath); + } + } + + if (mRootPath.isEmpty()) { + for (const auto &musicPath : QStandardPaths::standardLocations(QSt= andardPaths::MusicLocation)) { + mRootPath.push_back(musicPath); + } + } + + Q_EMIT rootPathChanged(mRootPath); + + setNeedsSave(true); + Q_EMIT needsSaveChanged(); +} + +void KCMElisaLocalFile::configChanged() +{ + setRootPath(Elisa::ElisaConfiguration::rootPath()); +} + + +#include "localfileconfiguration.moc" diff --git a/src/file/localfilelisting.h b/src/localFileConfiguration/local= fileconfiguration.h similarity index 57% copy from src/file/localfilelisting.h copy to src/localFileConfiguration/localfileconfiguration.h index 0fb59cb..878d26d 100644 --- a/src/file/localfilelisting.h +++ b/src/localFileConfiguration/localfileconfiguration.h @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 Matthieu Gallien + * Copyright 2017 Matthieu Gallien * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -17,51 +17,52 @@ * Boston, MA 02110-1301, USA. */ = -#ifndef LOCALFILELISTING_H -#define LOCALFILELISTING_H +#if !defined LOCALFILECONFIGURATION_H_ +#define LOCALFILECONFIGURATION_H_ = -#include "../abstractfile/abstractfilelisting.h" +#include +#include = -#include - -#include - -class LocalFileListingPrivate; - -class LocalFileListing : public AbstractFileListing +class KCMElisaLocalFile : public KQuickAddons::ConfigModule { = Q_OBJECT = - Q_PROPERTY(QString rootPath + Q_PROPERTY(QStringList rootPath READ rootPath WRITE setRootPath NOTIFY rootPathChanged) = public: = - explicit LocalFileListing(QObject *parent =3D 0); + explicit KCMElisaLocalFile(QObject *parent, const QVariantList &args); = - virtual ~LocalFileListing(); + virtual ~KCMElisaLocalFile(); = - QString rootPath() const; + QStringList rootPath() const; = Q_SIGNALS: = - void rootPathChanged(); + void rootPathChanged(QStringList rootPath); = public Q_SLOTS: = - void setRootPath(const QString &rootPath); + void defaults() override final; = -private: + void load() override final; = - void triggerRefreshOfContent() override; + void save() override final; = - std::unique_ptr d; + void setRootPath(QStringList rootPath); = -}; +private Q_SLOTS: = + void configChanged(); = +private: + + QStringList mRootPath; + +}; = -#endif // LOCALFILELISTING_H +#endif diff --git a/src/localFileConfiguration/package/contents/ui/main.qml b/src/= localFileConfiguration/package/contents/ui/main.qml new file mode 100644 index 0000000..5d09733 --- /dev/null +++ b/src/localFileConfiguration/package/contents/ui/main.qml @@ -0,0 +1,154 @@ +/* + * Copyright 2017 Matthieu Gallien + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public Licen= se + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.2 +import QtQml.Models 2.3 +import org.kde.kcm 1.0 +import org.kde.plasma.core 2.0 as PlasmaCore + +Item { + //implicitWidth and implicitHeight will be used as initial size + //when loaded in kcmshell5 + implicitWidth: units.gridUnit * 20 + implicitHeight: units.gridUnit * 20 + + ConfigModule.buttons: ConfigModule.Help|ConfigModule.Apply + + SystemPalette { + id: myPalette + colorGroup: SystemPalette.Active + } + + Component { + id: highlightBar + + Rectangle { + width: 200; height: 50 + color: myPalette.highlight + } + } + + Component { + id: pathDelegate + + Item { + id: delegateItem + + height: 3 * units.gridUnit + + width: pathList.width + + Rectangle { + anchors.fill: parent + anchors.margins: 0.1 * units.gridUnit + + color: myPalette.base + + MouseArea { + anchors.fill: parent + + hoverEnabled: true + + onEntered: pathList.currentIndex =3D delegateItem.Dele= gateModel.itemsIndex + + Label { + text: modelData + + anchors.centerIn: parent + } + + ToolButton { + iconName: 'list-remove' + + anchors.top: parent.top + anchors.right: parent.right + + onClicked: + { + var oldPaths =3D kcm.rootPath + oldPaths.splice(delegateItem.DelegateModel.ite= msIndex, 1) + kcm.rootPath =3D oldPaths + } + } + } + } + } + } + + RowLayout { + spacing: 0 + + anchors.fill: parent + + ScrollView { + flickableItem.boundsBehavior: Flickable.StopAtBounds + + Layout.fillWidth: true + Layout.fillHeight: true + + ListView { + id:pathList + + anchors.fill: parent + + model: DelegateModel { + model: kcm.rootPath + + delegate: pathDelegate + } + + highlight: highlightBar + } + } + + ColumnLayout { + Layout.fillHeight: true + Layout.leftMargin: 0.3 * units.gridUnit + + Button { + text: 'Add new path' + onClicked: fileDialog.open() + + Layout.alignment: Qt.AlignTop | Qt.AlignLeft + + FileDialog { + id: fileDialog + title: "Please choose a file" + folder: shortcuts.home + selectFolder: true + + visible: false + + onAccepted: { + var oldPaths =3D kcm.rootPath + oldPaths.push(fileDialog.fileUrls) + kcm.rootPath =3D oldPaths + } + } + } + + Item { + Layout.fillHeight: true + } + } + } +} diff --git a/src/localFileConfiguration/package/metadata.desktop b/src/loca= lFileConfiguration/package/metadata.desktop new file mode 100644 index 0000000..7ffb54b --- /dev/null +++ b/src/localFileConfiguration/package/metadata.desktop @@ -0,0 +1,16 @@ +[Desktop Entry] +Name=3DElisa +Comment=3DConfigure Local Files Indexer of Elisa Music Player +Icon=3Delisa +Type=3DService +X-KDE-ParentApp=3D +X-KDE-PluginInfo-Author=3DMatthieu Gallien +X-KDE-PluginInfo-Email=3Dmatthieu_gallien@yahoo.fr +X-KDE-PluginInfo-License=3DLGPLv3 +X-KDE-PluginInfo-Name=3Dkcm_elisa_local_file +X-KDE-PluginInfo-Version=3D +X-KDE-PluginInfo-Website=3D +X-KDE-ServiceTypes=3DPlasma/Generic + +X-Plasma-MainScript=3Dui/main.qml +X-Plasma-RemoteLocation=3D diff --git a/src/musiclistenersmanager.cpp b/src/musiclistenersmanager.cpp index 1f82789..69483ea 100644 --- a/src/musiclistenersmanager.cpp +++ b/src/musiclistenersmanager.cpp @@ -32,13 +32,19 @@ #include "databaseinterface.h" #include "mediaplaylist.h" #include "file/filelistener.h" +#include "file/localfilelisting.h" #include "trackslistener.h" +#include "elisa_settings.h" = #include #include #include #include #include +#include +#include +#include +#include = class MusicListenersManagerPrivate { @@ -51,15 +57,17 @@ public: #endif = #if defined KF5Baloo_FOUND && KF5Baloo_FOUND - BalooListener mBalooListener; + QScopedPointer mBalooListener; #endif = -#if (!defined KF5Baloo_FOUND || !KF5Baloo_FOUND) && defined KF5FileMetaDat= a_FOUND && KF5FileMetaData_FOUND - FileListener mFileListener; +#if defined KF5FileMetaData_FOUND && KF5FileMetaData_FOUND + QList> mFileListener; #endif = DatabaseInterface mDatabaseInterface; = + QFileSystemWatcher mConfigFileWatcher; + }; = MusicListenersManager::MusicListenersManager(QObject *parent) @@ -106,6 +114,24 @@ MusicListenersManager::MusicListenersManager(QObject *= parent) = connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &MusicListenersManager::applicationAboutToQuit); + + connect(Elisa::ElisaConfiguration::self(), &Elisa::ElisaConfiguration:= :configChanged, + this, &MusicListenersManager::configChanged); + + connect(&d->mConfigFileWatcher, &QFileSystemWatcher::fileChanged, + this, &MusicListenersManager::configChanged); + + auto initialRootPath =3D Elisa::ElisaConfiguration::rootPath(); + if (initialRootPath.isEmpty()) { + for (const auto &musicPath : QStandardPaths::standardLocations(QSt= andardPaths::MusicLocation)) { + initialRootPath.push_back(musicPath); + } + + Elisa::ElisaConfiguration::setRootPath(initialRootPath); + Elisa::ElisaConfiguration::self()->save(); + } + + d->mConfigFileWatcher.addPath(Elisa::ElisaConfiguration::self()->confi= g()->name()); } = MusicListenersManager::~MusicListenersManager() @@ -137,31 +163,7 @@ void MusicListenersManager::subscribeForTracks(MediaPl= ayList *client) = void MusicListenersManager::databaseReady() { -#if defined KF5Baloo_FOUND && KF5Baloo_FOUND - d->mBalooListener.setDatabaseInterface(&d->mDatabaseInterface); - d->mBalooListener.moveToThread(&d->mDatabaseThread); - connect(this, &MusicListenersManager::applicationIsTerminating, - &d->mBalooListener, &BalooListener::applicationAboutToQuit, Qt= ::BlockingQueuedConnection); - connect(this, &MusicListenersManager::databaseIsReady, - &d->mBalooListener, &BalooListener::databaseReady); -#endif -#if defined UPNPQT_FOUND && UPNPQT_FOUND - d->mUpnpListener.setDatabaseInterface(&d->mDatabaseInterface); - d->mUpnpListener.moveToThread(&d->mDatabaseThread); - connect(this, &MusicListenersManager::applicationIsTerminating, - &d->mUpnpListener, &UpnpListener::applicationAboutToQuit, Qt::= BlockingQueuedConnection); - connect(this, &MusicListenersManager::databaseIsReady, - &d->mUpnpListener, &UpnpListener::databaseReady); -#endif - -#if (!defined KF5Baloo_FOUND || !KF5Baloo_FOUND) && defined KF5FileMetaDat= a_FOUND && KF5FileMetaData_FOUND - d->mFileListener.setDatabaseInterface(&d->mDatabaseInterface); - d->mFileListener.moveToThread(&d->mDatabaseThread); - connect(this, &MusicListenersManager::applicationIsTerminating, - &d->mFileListener, &FileListener::applicationAboutToQuit, Qt::= BlockingQueuedConnection); - connect(this, &MusicListenersManager::databaseIsReady, - &d->mFileListener, &FileListener::databaseReady); -#endif + configChanged(); = Q_EMIT databaseIsReady(); } @@ -176,5 +178,83 @@ void MusicListenersManager::applicationAboutToQuit() d->mDatabaseThread.wait(); } = +void MusicListenersManager::showConfiguration() +{ +} + +void MusicListenersManager::configChanged() +{ + auto currentConfiguration =3D Elisa::ElisaConfiguration::self(); + + d->mConfigFileWatcher.addPath(currentConfiguration->config()->name()); + + currentConfiguration->load(); + +#if defined KF5Baloo_FOUND && KF5Baloo_FOUND + if (currentConfiguration->balooIndexer() && !d->mBalooListener) { + d->mBalooListener.reset(new BalooListener); + d->mBalooListener->setDatabaseInterface(&d->mDatabaseInterface); + d->mBalooListener->moveToThread(&d->mDatabaseThread); + connect(this, &MusicListenersManager::applicationIsTerminating, + d->mBalooListener.data(), &BalooListener::applicationAbout= ToQuit, Qt::BlockingQueuedConnection); + connect(this, &MusicListenersManager::databaseIsReady, + d->mBalooListener.data(), &BalooListener::databaseReady); + connect(d->mBalooListener.data(), &BalooListener::indexingFinished, + this, &MusicListenersManager::indexingFinished); + } else if (!currentConfiguration->balooIndexer() && d->mBalooListener)= { + d->mBalooListener.reset(); + } +#endif +#if defined UPNPQT_FOUND && UPNPQT_FOUND + d->mUpnpListener.setDatabaseInterface(&d->mDatabaseInterface); + d->mUpnpListener.moveToThread(&d->mDatabaseThread); + connect(this, &MusicListenersManager::applicationIsTerminating, + &d->mUpnpListener, &UpnpListener::applicationAboutToQuit, Qt::= BlockingQueuedConnection); + connect(this, &MusicListenersManager::databaseIsReady, + &d->mUpnpListener, &UpnpListener::databaseReady); +#endif + +#if defined KF5FileMetaData_FOUND && KF5FileMetaData_FOUND + if (currentConfiguration->elisaFilesIndexer()) + { + const auto &allRootPaths =3D currentConfiguration->rootPath(); + for (auto itFileListener =3D d->mFileListener.begin(); itFileListe= ner !=3D d->mFileListener.end(); ) { + const auto ¤tRootPath =3D (*itFileListener)->localFileIn= dexer().rootPath(); + auto itPath =3D std::find(allRootPaths.begin(), allRootPaths.e= nd(), currentRootPath); + + if (itPath =3D=3D allRootPaths.end()) { + d->mDatabaseInterface.removeAllTracksFromSource((*itFileLi= stener)->fileListing()->sourceName()); + itFileListener =3D d->mFileListener.erase(itFileListener); + } else { + ++itFileListener; + } + } + + for (const auto &oneRootPath : allRootPaths) { + auto itPath =3D std::find_if(d->mFileListener.begin(), d->mFil= eListener.end(), + [&oneRootPath](auto value)->bool {r= eturn value->localFileIndexer().rootPath() =3D=3D oneRootPath;}); + if (itPath =3D=3D d->mFileListener.end()) { + auto newFileIndexer =3D new FileListener; + + newFileIndexer->setDatabaseInterface(&d->mDatabaseInterfac= e); + newFileIndexer->moveToThread(&d->mDatabaseThread); + connect(this, &MusicListenersManager::applicationIsTermina= ting, + newFileIndexer, &FileListener::applicationAboutToQ= uit, Qt::BlockingQueuedConnection); + connect(this, &MusicListenersManager::databaseIsReady, + newFileIndexer, &FileListener::databaseReady); + connect(newFileIndexer, &FileListener::indexingFinished, + this, &MusicListenersManager::indexingFinished); + + newFileIndexer->setRootPath(oneRootPath); + + d->mFileListener.push_back({newFileIndexer}); + + newFileIndexer->performInitialScan(); + } + } + } +#endif +} + = #include "moc_musiclistenersmanager.cpp" diff --git a/src/musiclistenersmanager.h b/src/musiclistenersmanager.h index 668f770..796ba45 100644 --- a/src/musiclistenersmanager.h +++ b/src/musiclistenersmanager.h @@ -77,12 +77,20 @@ Q_SIGNALS: = void databaseIsReady(); = + void indexingFinished(); + public Q_SLOTS: = void databaseReady(); = void applicationAboutToQuit(); = + void showConfiguration(); + +private Q_SLOTS: + + void configChanged(); + private: = MusicListenersManagerPrivate *d; diff --git a/src/upnpControl.cpp b/src/upnpControl.cpp index ec0c39f..65c9e11 100644 --- a/src/upnpControl.cpp +++ b/src/upnpControl.cpp @@ -53,6 +53,7 @@ #include "elisaapplication.h" #include "audiowrapper.h" #include "alltracksmodel.h" +#include "elisa_settings.h" = #if defined Qt5DBus_FOUND && Qt5DBus_FOUND #include "mpris2/mpris2.h" @@ -214,6 +215,12 @@ int main(int argc, char *argv[]) QtAndroid::androidContext().= object()); #endif = + auto configurationFileName =3D QStandardPaths::writableLocation(QStand= ardPaths::ConfigLocation); + configurationFileName +=3D QStringLiteral("/elisarc"); + Elisa::ElisaConfiguration::instance(configurationFileName); + Elisa::ElisaConfiguration::self()->load(); + Elisa::ElisaConfiguration::self()->save(); + QQmlApplicationEngine engine; engine.addImportPath(QStringLiteral("qrc:/imports")); QQmlFileSelector selector(&engine);