File indexing completed on 2025-01-05 03:54:00

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2007-03-23
0007  * Description : Core database image properties synchronizer
0008  *
0009  * SPDX-FileCopyrightText: 2007-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0010  * SPDX-FileCopyrightText: 2009-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "coredbwatch.h"
0017 
0018 // Qt includes
0019 
0020 #include <QMetaType>
0021 #include <QApplication>
0022 
0023 #ifdef HAVE_DBUS
0024 #   include <QtDBus>
0025 #   include "coredbwatchadaptor.h"
0026 #endif
0027 
0028 // Local includes
0029 
0030 #include "collectionmanager.h"
0031 
0032 namespace Digikam
0033 {
0034 
0035 #ifdef HAVE_DBUS
0036 class DBusSignalListenerThread;
0037 #endif
0038 
0039 class Q_DECL_HIDDEN CoreDbWatch::Private
0040 {
0041 public:
0042 
0043     explicit Private()
0044       :  mode       (CoreDbWatch::DatabaseSlave)
0045 
0046 #ifdef HAVE_DBUS
0047 
0048         ,adaptor    (nullptr)
0049         ,slaveThread(nullptr)
0050 
0051 #endif
0052 
0053     {
0054     }
0055 
0056 #ifdef HAVE_DBUS
0057 
0058     void connectWithDBus(const char* dbusSignal, QObject* obj, const char* slot,
0059                          QDBusConnection connection = QDBusConnection::sessionBus())
0060     {
0061         // connect to slave signals
0062 
0063         connection.connect(QString(), QLatin1String("/ChangesetRelay"),
0064                            QLatin1String("org.kde.digikam.DatabaseChangesetRelay"),
0065                            QString::fromUtf8(dbusSignal),
0066                            obj, slot);
0067 
0068         // connect to master signals
0069 
0070         connection.connect(QString(), QLatin1String("/ChangesetRelayForPeers"),
0071                            QLatin1String("org.kde.digikam.DatabaseChangesetRelay"),
0072                            QString::fromUtf8(dbusSignal),
0073                            obj, slot);
0074     }
0075 
0076 #endif
0077 
0078 public:
0079 
0080 
0081     CoreDbWatch::DatabaseMode   mode;
0082     QString                     databaseId;
0083     QString                     applicationId;
0084 
0085 #ifdef HAVE_DBUS
0086 
0087     CoreDbWatchAdaptor*         adaptor;
0088     DBusSignalListenerThread*   slaveThread;
0089 
0090 #endif
0091 
0092 };
0093 
0094 // ---------------------------------------------------------------------------------
0095 
0096 #ifdef HAVE_DBUS
0097 
0098 DBusSignalListenerThread::DBusSignalListenerThread(CoreDbWatch* const qq, CoreDbWatch::Private* const dd)
0099     : q(qq),
0100       d(dd)
0101 {
0102     start();
0103 }
0104 
0105 DBusSignalListenerThread::~DBusSignalListenerThread()
0106 {
0107     quit();
0108     wait();
0109 }
0110 
0111 void DBusSignalListenerThread::run()
0112 {
0113     // We cannot use sessionBus() here but need to connect on our own
0114 
0115     QDBusConnection threadConnection = QDBusConnection::connectToBus(QDBusConnection::SessionBus,
0116                                                                      QString::fromUtf8("DigikamDatabaseSlaveConnection-%1")
0117                                                                      .arg(qApp->applicationPid()));
0118 
0119     // DBus signals are received from within this thread and then sent with queued signals to the main thread
0120 
0121     d->connectWithDBus("signalImageTagChangeDBus", q,
0122                         SLOT(slotImageTagChangeDBus(QString,QString,Digikam::ImageTagChangeset)),
0123                         threadConnection);
0124 
0125     d->connectWithDBus("signalAlbumRootChangeDBus", q,
0126                         SLOT(slotAlbumRootChangeDBus(QString,QString,Digikam::AlbumRootChangeset)),
0127                         threadConnection);
0128 
0129     // enter thread event loop
0130 
0131     exec();
0132 }
0133 
0134 #endif
0135 
0136 // ---------------------------------------------------------------------------------
0137 
0138 CoreDbWatch::CoreDbWatch()
0139     : d(new Private)
0140 {
0141 }
0142 
0143 CoreDbWatch::~CoreDbWatch()
0144 {
0145 
0146 #ifdef HAVE_DBUS
0147 
0148     delete d->adaptor;
0149     delete d->slaveThread;
0150 
0151 #endif
0152 
0153     delete d;
0154 }
0155 
0156 void CoreDbWatch::initializeRemote(DatabaseMode mode)
0157 {
0158     d->mode = mode;
0159 
0160     qRegisterMetaType<ImageChangeset>("ImageChangeset");
0161     qRegisterMetaType<ImageTagChangeset>("ImageTagChangeset");
0162     qRegisterMetaType<CollectionImageChangeset>("CollectionImageChangeset");
0163     qRegisterMetaType<AlbumChangeset>("AlbumChangeset");
0164     qRegisterMetaType<TagChangeset>("TagChangeset");
0165     qRegisterMetaType<AlbumRootChangeset>("AlbumRootChangeset");
0166     qRegisterMetaType<SearchChangeset>("SearchChangeset");
0167 
0168 #ifdef HAVE_DBUS
0169 
0170     // NOTE: The literal for registration with DBus here will include namespace qualifier.
0171     // Therefore, the header file declaration for DBus signals and slots
0172     // must contain the full qualifier as well, so that moc picks them up.
0173 
0174     qDBusRegisterMetaType<ImageChangeset>();
0175     qDBusRegisterMetaType<ImageTagChangeset>();
0176     qDBusRegisterMetaType<CollectionImageChangeset>();
0177     qDBusRegisterMetaType<AlbumChangeset>();
0178     qDBusRegisterMetaType<TagChangeset>();
0179     qDBusRegisterMetaType<AlbumRootChangeset>();
0180     qDBusRegisterMetaType<SearchChangeset>();
0181 
0182     qDBusRegisterMetaType<DatabaseFields::Set>();
0183     qDBusRegisterMetaType< QList<qlonglong> >();
0184     qDBusRegisterMetaType< QList<int> >();
0185 
0186 #endif
0187 
0188     if (d->mode == DatabaseSlave)
0189     {
0190 
0191 #ifdef HAVE_DBUS
0192 
0193         d->adaptor     = new CoreDbWatchAdaptor(this);
0194 
0195         QDBusConnection::sessionBus().registerObject(QLatin1String("/ChangesetRelay"), this);
0196 
0197         // Slave do not have an event loop which is needed for receiving DBus signals.
0198         // See also the event loop in CoreDbAccess::setParameters.
0199 
0200         d->slaveThread = new DBusSignalListenerThread(this, d);
0201 
0202 #endif
0203 
0204     }
0205     else
0206     {
0207 
0208 #ifdef HAVE_DBUS
0209 
0210         d->adaptor = new CoreDbWatchAdaptor(this);
0211 
0212         QDBusConnection::sessionBus().registerObject(QLatin1String("/ChangesetRelayForPeers"), this);
0213 
0214         // connect DBus signals from slave or peer to our application
0215 
0216         d->connectWithDBus("signalImageChangeDBus", this,
0217                            SLOT(slotImageChangeDBus(QString,QString,Digikam::ImageChangeset)));
0218 
0219         d->connectWithDBus("signalImageTagChangeDBus", this,
0220                            SLOT(slotImageTagChangeDBus(QString,QString,Digikam::ImageTagChangeset)));
0221 
0222         d->connectWithDBus("signalCollectionImageChangeDBus", this,
0223                            SLOT(slotCollectionImageChangeDBus(QString,QString,Digikam::CollectionImageChangeset)));
0224 
0225         d->connectWithDBus("signalAlbumChangeDBus", this,
0226                            SLOT(slotAlbumChangeDBus(QString,QString,Digikam::AlbumChangeset)));
0227 
0228         d->connectWithDBus("signalTagChangeDBus", this,
0229                            SLOT(slotTagChangeDBus(QString,QString,Digikam::TagChangeset)));
0230 
0231         d->connectWithDBus("signalAlbumRootChangeDBus", this,
0232                            SLOT(slotAlbumRootChangeDBus(QString,QString,Digikam::AlbumRootChangeset)));
0233 
0234         d->connectWithDBus("signalSearchChangeDBus", this,
0235                            SLOT(slotSearchChangeDBus(QString,QString,Digikam::SearchChangeset)));
0236 #endif
0237 
0238     }
0239 
0240     // Do this as a favor for CollectionManager, we may not exist at time of its creation
0241     connect(this, SIGNAL(albumRootChange(AlbumRootChangeset)),
0242             CollectionManager::instance(), SLOT(slotAlbumRootChange(AlbumRootChangeset)));
0243 }
0244 
0245 void CoreDbWatch::doAnyProcessing()
0246 {
0247 
0248 #ifdef HAVE_DBUS
0249 
0250     // In a slave we have no event loop.
0251     // This method is called when a slave begins a new operation
0252     // (it calls CoreDbAccess::setParameters then).
0253     // Allow here queued signals to proceed that may be caused by CoreDbWatch signals
0254     // that were send from within the DBus listener thread (see above).
0255 
0256     QEventLoop loop;
0257     loop.processEvents();
0258 
0259 #endif
0260 
0261 }
0262 
0263 void CoreDbWatch::setDatabaseIdentifier(const QString& identifier)
0264 {
0265     d->databaseId = identifier;
0266 }
0267 
0268 void CoreDbWatch::setApplicationIdentifier(const QString& identifier)
0269 {
0270     d->applicationId = identifier;
0271 }
0272 
0273 void CoreDbWatch::sendDatabaseChanged()
0274 {
0275 
0276 #ifdef HAVE_DBUS
0277 
0278     // Note: This is not dispatched by DBus!
0279 
0280 #endif
0281 
0282     Q_EMIT databaseChanged();
0283 }
0284 
0285 // --- methods to dispatch changes from database to listeners (local and remote) ---
0286 
0287 void CoreDbWatch::sendImageChange(const ImageChangeset& cset)
0288 {
0289     // send local signal
0290 
0291     Q_EMIT imageChange(cset);
0292 
0293 #ifdef HAVE_DBUS
0294 
0295     // send DBUS signal
0296 
0297     Q_EMIT signalImageChangeDBus(d->databaseId, d->applicationId, cset);
0298 
0299 #endif
0300 
0301 }
0302 
0303 void CoreDbWatch::sendImageTagChange(const ImageTagChangeset& cset)
0304 {
0305     Q_EMIT imageTagChange(cset);
0306 
0307 #ifdef HAVE_DBUS
0308 
0309     Q_EMIT signalImageTagChangeDBus(d->databaseId, d->applicationId, cset);
0310 
0311 #endif
0312 
0313 }
0314 
0315 void CoreDbWatch::sendCollectionImageChange(const CollectionImageChangeset& cset)
0316 {
0317     Q_EMIT collectionImageChange(cset);
0318 
0319 #ifdef HAVE_DBUS
0320 
0321     Q_EMIT signalCollectionImageChangeDBus(d->databaseId, d->applicationId, cset);
0322 
0323 #endif
0324 
0325 }
0326 
0327 void CoreDbWatch::sendAlbumChange(const AlbumChangeset& cset)
0328 {
0329     Q_EMIT albumChange(cset);
0330 
0331 #ifdef HAVE_DBUS
0332 
0333     Q_EMIT signalAlbumChangeDBus(d->databaseId, d->applicationId, cset);
0334 
0335 #endif
0336 
0337 }
0338 
0339 void CoreDbWatch::sendTagChange(const TagChangeset& cset)
0340 {
0341     Q_EMIT tagChange(cset);
0342 
0343 #ifdef HAVE_DBUS
0344 
0345     Q_EMIT signalTagChangeDBus(d->databaseId, d->applicationId, cset);
0346 
0347 #endif
0348 
0349 }
0350 
0351 void CoreDbWatch::sendAlbumRootChange(const AlbumRootChangeset& cset)
0352 {
0353     Q_EMIT albumRootChange(cset);
0354 
0355 #ifdef HAVE_DBUS
0356 
0357     Q_EMIT signalAlbumRootChangeDBus(d->databaseId, d->applicationId, cset);
0358 
0359 #endif
0360 
0361 }
0362 
0363 void CoreDbWatch::sendSearchChange(const SearchChangeset& cset)
0364 {
0365     Q_EMIT searchChange(cset);
0366 
0367 #ifdef HAVE_DBUS
0368 
0369     Q_EMIT signalSearchChangeDBus(d->databaseId, d->applicationId, cset);
0370 
0371 #endif
0372 
0373 }
0374 
0375 #ifdef HAVE_DBUS
0376 
0377 // --- methods to dispatch from slave or peer to local listeners ---
0378 
0379 void CoreDbWatch::slotImageChangeDBus(const QString& databaseIdentifier,
0380                                       const QString& applicationIdentifier,
0381                                       const ImageChangeset& changeset)
0382 {
0383     if ((applicationIdentifier != d->applicationId) &&
0384         (databaseIdentifier    == d->databaseId))
0385     {
0386         Q_EMIT imageChange(changeset);
0387     }
0388 }
0389 
0390 void CoreDbWatch::slotImageTagChangeDBus(const QString& databaseIdentifier,
0391                                          const QString& applicationIdentifier,
0392                                          const ImageTagChangeset& changeset)
0393 {
0394     if ((applicationIdentifier != d->applicationId) &&
0395         (databaseIdentifier    == d->databaseId))
0396     {
0397         Q_EMIT imageTagChange(changeset);
0398     }
0399 }
0400 
0401 void CoreDbWatch::slotCollectionImageChangeDBus(const QString& databaseIdentifier,
0402                                                 const QString& applicationIdentifier,
0403                                                 const CollectionImageChangeset& changeset)
0404 {
0405     if ((applicationIdentifier != d->applicationId) &&
0406         (databaseIdentifier    == d->databaseId))
0407     {
0408         Q_EMIT collectionImageChange(changeset);
0409     }
0410 }
0411 
0412 void CoreDbWatch::slotAlbumChangeDBus(const QString& databaseIdentifier,
0413                                       const QString& applicationIdentifier,
0414                                       const AlbumChangeset& changeset)
0415 {
0416     if ((applicationIdentifier != d->applicationId) &&
0417         (databaseIdentifier    == d->databaseId))
0418     {
0419         Q_EMIT albumChange(changeset);
0420     }
0421 }
0422 
0423 void CoreDbWatch::slotTagChangeDBus(const QString& databaseIdentifier,
0424                                     const QString& applicationIdentifier,
0425                                     const TagChangeset& changeset)
0426 {
0427     if ((applicationIdentifier != d->applicationId) &&
0428         (databaseIdentifier    == d->databaseId))
0429     {
0430         Q_EMIT tagChange(changeset);
0431     }
0432 }
0433 
0434 void CoreDbWatch::slotAlbumRootChangeDBus(const QString& databaseIdentifier,
0435         const QString& applicationIdentifier,
0436         const AlbumRootChangeset& changeset)
0437 {
0438     if ((applicationIdentifier != d->applicationId) &&
0439         (databaseIdentifier    == d->databaseId))
0440     {
0441         Q_EMIT albumRootChange(changeset);
0442     }
0443 }
0444 
0445 void CoreDbWatch::slotSearchChangeDBus(const QString& databaseIdentifier,
0446                                        const QString& applicationIdentifier,
0447                                        const SearchChangeset& changeset)
0448 {
0449     if ((applicationIdentifier != d->applicationId) &&
0450         (databaseIdentifier    == d->databaseId))
0451     {
0452         Q_EMIT searchChange(changeset);
0453     }
0454 }
0455 
0456 #endif
0457 
0458 } // namespace Digikam
0459 
0460 #include "moc_coredbwatch.cpp"