CatalogueController.cpp
526 lines
| 17.7 KiB
| text/x-c
|
CppLexer
r1059 | #include <Catalogue/CatalogueController.h> | |||
#include <Variable/Variable.h> | ||||
#include <CatalogueDao.h> | ||||
r1125 | #include <ComparaisonPredicate.h> | |||
#include <CompoundPredicate.h> | ||||
#include <DBCatalogue.h> | ||||
#include <DBEvent.h> | ||||
r1159 | #include <DBEventProduct.h> | |||
r1125 | #include <DBTag.h> | |||
#include <IRequestPredicate.h> | ||||
r1230 | #include <QDataStream> | |||
r1059 | #include <QMutex> | |||
#include <QThread> | ||||
#include <QDir> | ||||
#include <QStandardPaths> | ||||
Q_LOGGING_CATEGORY(LOG_CatalogueController, "CatalogueController") | ||||
r1126 | namespace { | |||
r1125 | ||||
r1224 | static QString REPOSITORY_WORK_SUFFIX = QString{"_work"}; | |||
static QString REPOSITORY_TRASH_SUFFIX = QString{"_trash"}; | ||||
r1125 | } | |||
|
r1268 | /** | ||
* Possible types of an repository | ||||
*/ | ||||
r1276 | enum class DBType { SYNC, WORK, TRASH }; | |||
r1059 | class CatalogueController::CatalogueControllerPrivate { | |||
r1159 | ||||
r1059 | public: | |||
r1159 | explicit CatalogueControllerPrivate(CatalogueController *parent) : m_Q{parent} {} | |||
r1059 | CatalogueDao m_CatalogueDao; | |||
r1125 | ||||
r1159 | QStringList m_RepositoryList; | |||
CatalogueController *m_Q; | ||||
r1276 | QSet<QString> m_KeysWithChanges; | |||
r1237 | ||||
QString eventUniqueKey(const std::shared_ptr<DBEvent> &event) const; | ||||
r1276 | QString catalogueUniqueKey(const std::shared_ptr<DBCatalogue> &catalogue) const; | |||
r1237 | ||||
r1159 | void copyDBtoDB(const QString &dbFrom, const QString &dbTo); | |||
QString toWorkRepository(QString repository); | ||||
QString toSyncRepository(QString repository); | ||||
r1224 | void savAllDB(); | |||
void saveEvent(std::shared_ptr<DBEvent> event, bool persist = true); | ||||
void saveCatalogue(std::shared_ptr<DBCatalogue> catalogue, bool persist = true); | ||||
|
r1268 | |||
r1276 | std::shared_ptr<IRequestPredicate> createFinder(const QUuid &uniqId, const QString &repository, | |||
DBType type); | ||||
r1059 | }; | |||
CatalogueController::CatalogueController(QObject *parent) | ||||
r1159 | : impl{spimpl::make_unique_impl<CatalogueControllerPrivate>(this)} | |||
r1059 | { | |||
qCDebug(LOG_CatalogueController()) << tr("CatalogueController construction") | ||||
<< QThread::currentThread(); | ||||
} | ||||
CatalogueController::~CatalogueController() | ||||
{ | ||||
qCDebug(LOG_CatalogueController()) << tr("CatalogueController destruction") | ||||
<< QThread::currentThread(); | ||||
} | ||||
r1159 | QStringList CatalogueController::getRepositories() const | |||
{ | ||||
return impl->m_RepositoryList; | ||||
} | ||||
r1125 | void CatalogueController::addDB(const QString &dbPath) | |||
{ | ||||
QDir dbDir(dbPath); | ||||
if (dbDir.exists()) { | ||||
auto dirName = dbDir.dirName(); | ||||
if (std::find(impl->m_RepositoryList.cbegin(), impl->m_RepositoryList.cend(), dirName) | ||||
!= impl->m_RepositoryList.cend()) { | ||||
qCCritical(LOG_CatalogueController()) | ||||
<< tr("Impossible to addDB that is already loaded"); | ||||
} | ||||
if (!impl->m_CatalogueDao.addDB(dbPath, dirName)) { | ||||
qCCritical(LOG_CatalogueController()) | ||||
<< tr("Impossible to addDB %1 from %2 ").arg(dirName, dbPath); | ||||
} | ||||
r1126 | else { | |||
r1159 | impl->m_RepositoryList << dirName; | |||
impl->copyDBtoDB(dirName, impl->toWorkRepository(dirName)); | ||||
r1125 | } | |||
} | ||||
else { | ||||
qCCritical(LOG_CatalogueController()) << tr("Impossible to addDB that not exists: ") | ||||
<< dbPath; | ||||
} | ||||
} | ||||
void CatalogueController::saveDB(const QString &destinationPath, const QString &repository) | ||||
{ | ||||
if (!impl->m_CatalogueDao.saveDB(destinationPath, repository)) { | ||||
qCCritical(LOG_CatalogueController()) | ||||
<< tr("Impossible to saveDB %1 from %2 ").arg(repository, destinationPath); | ||||
} | ||||
} | ||||
std::list<std::shared_ptr<DBEvent> > | ||||
CatalogueController::retrieveEvents(const QString &repository) const | ||||
{ | ||||
r1159 | QString dbDireName = repository.isEmpty() ? REPOSITORY_DEFAULT : repository; | |||
r1125 | auto eventsShared = std::list<std::shared_ptr<DBEvent> >{}; | |||
r1159 | auto events = impl->m_CatalogueDao.getEvents(impl->toWorkRepository(dbDireName)); | |||
r1125 | for (auto event : events) { | |||
eventsShared.push_back(std::make_shared<DBEvent>(event)); | ||||
} | ||||
return eventsShared; | ||||
} | ||||
std::list<std::shared_ptr<DBEvent> > CatalogueController::retrieveAllEvents() const | ||||
{ | ||||
auto eventsShared = std::list<std::shared_ptr<DBEvent> >{}; | ||||
for (auto repository : impl->m_RepositoryList) { | ||||
eventsShared.splice(eventsShared.end(), retrieveEvents(repository)); | ||||
} | ||||
return eventsShared; | ||||
} | ||||
r1128 | std::list<std::shared_ptr<DBEvent> > | |||
r1143 | CatalogueController::retrieveEventsFromCatalogue(std::shared_ptr<DBCatalogue> catalogue) const | |||
r1128 | { | |||
auto eventsShared = std::list<std::shared_ptr<DBEvent> >{}; | ||||
auto events = impl->m_CatalogueDao.getCatalogueEvents(*catalogue); | ||||
for (auto event : events) { | ||||
eventsShared.push_back(std::make_shared<DBEvent>(event)); | ||||
} | ||||
return eventsShared; | ||||
} | ||||
r1159 | void CatalogueController::updateEvent(std::shared_ptr<DBEvent> event) | |||
{ | ||||
r1224 | event->setRepository(impl->toWorkRepository(event->getRepository())); | |||
r1159 | ||||
r1237 | auto uniqueId = impl->eventUniqueKey(event); | |||
r1276 | impl->m_KeysWithChanges.insert(uniqueId); | |||
r1237 | ||||
r1159 | impl->m_CatalogueDao.updateEvent(*event); | |||
} | ||||
r1227 | void CatalogueController::updateEventProduct(std::shared_ptr<DBEventProduct> eventProduct) | |||
{ | ||||
impl->m_CatalogueDao.updateEventProduct(*eventProduct); | ||||
} | ||||
r1159 | void CatalogueController::removeEvent(std::shared_ptr<DBEvent> event) | |||
{ | ||||
// Remove it from both repository and repository_work | ||||
event->setRepository(impl->toWorkRepository(event->getRepository())); | ||||
impl->m_CatalogueDao.removeEvent(*event); | ||||
event->setRepository(impl->toSyncRepository(event->getRepository())); | ||||
impl->m_CatalogueDao.removeEvent(*event); | ||||
r1241 | impl->savAllDB(); | |||
r1159 | } | |||
void CatalogueController::addEvent(std::shared_ptr<DBEvent> event) | ||||
{ | ||||
r1164 | event->setRepository(impl->toWorkRepository(event->getRepository())); | |||
r1159 | ||||
r1223 | auto eventTemp = *event; | |||
impl->m_CatalogueDao.addEvent(eventTemp); | ||||
r1159 | ||||
// Call update is necessary at the creation of add Event if it has some tags or some event | ||||
// products | ||||
if (!event->getEventProducts().empty() || !event->getTags().empty()) { | ||||
r1223 | ||||
auto eventProductsTemp = eventTemp.getEventProducts(); | ||||
auto eventProductTempUpdated = std::list<DBEventProduct>{}; | ||||
for (auto eventProductTemp : eventProductsTemp) { | ||||
eventProductTemp.setEvent(eventTemp); | ||||
eventProductTempUpdated.push_back(eventProductTemp); | ||||
} | ||||
eventTemp.setEventProducts(eventProductTempUpdated); | ||||
impl->m_CatalogueDao.updateEvent(eventTemp); | ||||
r1159 | } | |||
r1266 | ||||
r1269 | auto workPred = impl->createFinder(event->getUniqId(), event->getRepository(), DBType::WORK); | |||
r1267 | ||||
auto workEvent = impl->m_CatalogueDao.getEvent(workPred); | ||||
*event = workEvent; | ||||
r1269 | ||||
auto uniqueId = impl->eventUniqueKey(event); | ||||
r1276 | impl->m_KeysWithChanges.insert(uniqueId); | |||
r1159 | } | |||
void CatalogueController::saveEvent(std::shared_ptr<DBEvent> event) | ||||
{ | ||||
r1224 | impl->saveEvent(event, true); | |||
r1276 | impl->m_KeysWithChanges.remove(impl->eventUniqueKey(event)); | |||
r1237 | } | |||
r1267 | void CatalogueController::discardEvent(std::shared_ptr<DBEvent> event, bool &removed) | |||
r1243 | { | |||
|
r1268 | auto syncPred = impl->createFinder(event->getUniqId(), event->getRepository(), DBType::SYNC); | ||
auto workPred = impl->createFinder(event->getUniqId(), event->getRepository(), DBType::WORK); | ||||
r1244 | ||||
auto syncEvent = impl->m_CatalogueDao.getEvent(syncPred); | ||||
r1267 | if (!syncEvent.getUniqId().isNull()) { | |||
removed = false; | ||||
impl->m_CatalogueDao.copyEvent(syncEvent, impl->toWorkRepository(event->getRepository()), | ||||
true); | ||||
auto workEvent = impl->m_CatalogueDao.getEvent(workPred); | ||||
*event = workEvent; | ||||
r1276 | impl->m_KeysWithChanges.remove(impl->eventUniqueKey(event)); | |||
r1267 | } | |||
else { | ||||
removed = true; | ||||
// Since the element wasn't in sync repository. Discard it means remove it | ||||
event->setRepository(impl->toWorkRepository(event->getRepository())); | ||||
impl->m_CatalogueDao.removeEvent(*event); | ||||
} | ||||
r1243 | } | |||
r1237 | bool CatalogueController::eventHasChanges(std::shared_ptr<DBEvent> event) const | |||
{ | ||||
r1276 | return impl->m_KeysWithChanges.contains(impl->eventUniqueKey(event)); | |||
r1159 | } | |||
r1128 | std::list<std::shared_ptr<DBCatalogue> > | |||
r1159 | CatalogueController::retrieveCatalogues(const QString &repository) const | |||
r1128 | { | |||
r1159 | QString dbDireName = repository.isEmpty() ? REPOSITORY_DEFAULT : repository; | |||
r1128 | auto cataloguesShared = std::list<std::shared_ptr<DBCatalogue> >{}; | |||
r1159 | auto catalogues = impl->m_CatalogueDao.getCatalogues(impl->toWorkRepository(dbDireName)); | |||
r1128 | for (auto catalogue : catalogues) { | |||
cataloguesShared.push_back(std::make_shared<DBCatalogue>(catalogue)); | ||||
} | ||||
return cataloguesShared; | ||||
} | ||||
|
r1268 | void CatalogueController::addCatalogue(std::shared_ptr<DBCatalogue> catalogue) | ||
{ | ||||
catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository())); | ||||
auto catalogueTemp = *catalogue; | ||||
impl->m_CatalogueDao.addCatalogue(catalogueTemp); | ||||
r1276 | auto workPred | |||
= impl->createFinder(catalogue->getUniqId(), catalogue->getRepository(), DBType::WORK); | ||||
|
r1268 | |||
auto workCatalogue = impl->m_CatalogueDao.getCatalogue(workPred); | ||||
*catalogue = workCatalogue; | ||||
r1276 | auto uniqueId = impl->catalogueUniqueKey(catalogue); | |||
impl->m_KeysWithChanges.insert(uniqueId); | ||||
|
r1268 | } | ||
r1159 | void CatalogueController::updateCatalogue(std::shared_ptr<DBCatalogue> catalogue) | |||
{ | ||||
r1224 | catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository())); | |||
r1159 | ||||
r1276 | auto uniqueId = impl->catalogueUniqueKey(catalogue); | |||
impl->m_KeysWithChanges.insert(uniqueId); | ||||
|
r1268 | |||
r1159 | impl->m_CatalogueDao.updateCatalogue(*catalogue); | |||
} | ||||
void CatalogueController::removeCatalogue(std::shared_ptr<DBCatalogue> catalogue) | ||||
{ | ||||
// Remove it from both repository and repository_work | ||||
catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository())); | ||||
impl->m_CatalogueDao.removeCatalogue(*catalogue); | ||||
catalogue->setRepository(impl->toSyncRepository(catalogue->getRepository())); | ||||
impl->m_CatalogueDao.removeCatalogue(*catalogue); | ||||
|
r1268 | impl->savAllDB(); | ||
r1159 | } | |||
void CatalogueController::saveCatalogue(std::shared_ptr<DBCatalogue> catalogue) | ||||
{ | ||||
r1224 | impl->saveCatalogue(catalogue, true); | |||
r1276 | impl->m_KeysWithChanges.remove(impl->catalogueUniqueKey(catalogue)); | |||
} | ||||
void CatalogueController::discardCatalogue(std::shared_ptr<DBCatalogue> catalogue, bool &removed) | ||||
{ | ||||
auto syncPred | ||||
= impl->createFinder(catalogue->getUniqId(), catalogue->getRepository(), DBType::SYNC); | ||||
auto workPred | ||||
= impl->createFinder(catalogue->getUniqId(), catalogue->getRepository(), DBType::WORK); | ||||
auto syncCatalogue = impl->m_CatalogueDao.getCatalogue(syncPred); | ||||
if (!syncCatalogue.getUniqId().isNull()) { | ||||
removed = false; | ||||
impl->m_CatalogueDao.copyCatalogue( | ||||
syncCatalogue, impl->toWorkRepository(catalogue->getRepository()), true); | ||||
auto workCatalogue = impl->m_CatalogueDao.getCatalogue(workPred); | ||||
*catalogue = workCatalogue; | ||||
impl->m_KeysWithChanges.remove(impl->catalogueUniqueKey(catalogue)); | ||||
} | ||||
else { | ||||
removed = true; | ||||
// Since the element wasn't in sync repository. Discard it means remove it | ||||
catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository())); | ||||
impl->m_CatalogueDao.removeCatalogue(*catalogue); | ||||
} | ||||
r1159 | } | |||
void CatalogueController::saveAll() | ||||
{ | ||||
for (auto repository : impl->m_RepositoryList) { | ||||
// Save Event | ||||
auto events = this->retrieveEvents(repository); | ||||
for (auto event : events) { | ||||
r1224 | impl->saveEvent(event, false); | |||
r1159 | } | |||
// Save Catalogue | ||||
auto catalogues = this->retrieveCatalogues(repository); | ||||
for (auto catalogue : catalogues) { | ||||
r1224 | impl->saveCatalogue(catalogue, false); | |||
r1159 | } | |||
} | ||||
r1224 | ||||
impl->savAllDB(); | ||||
r1276 | impl->m_KeysWithChanges.clear(); | |||
r1159 | } | |||
r1239 | bool CatalogueController::hasChanges() const | |||
{ | ||||
r1276 | return !impl->m_KeysWithChanges.isEmpty(); | |||
r1239 | } | |||
r1230 | QByteArray | |||
CatalogueController::mimeDataForEvents(const QVector<std::shared_ptr<DBEvent> > &events) const | ||||
{ | ||||
auto encodedData = QByteArray{}; | ||||
QMap<QString, QVariantList> idsPerRepository; | ||||
for (auto event : events) { | ||||
idsPerRepository[event->getRepository()] << event->getUniqId(); | ||||
} | ||||
QDataStream stream{&encodedData, QIODevice::WriteOnly}; | ||||
stream << idsPerRepository; | ||||
return encodedData; | ||||
} | ||||
QVector<std::shared_ptr<DBEvent> > | ||||
CatalogueController::eventsForMimeData(const QByteArray &mimeData) const | ||||
{ | ||||
auto events = QVector<std::shared_ptr<DBEvent> >{}; | ||||
QDataStream stream{mimeData}; | ||||
QMap<QString, QVariantList> idsPerRepository; | ||||
stream >> idsPerRepository; | ||||
for (auto it = idsPerRepository.cbegin(); it != idsPerRepository.cend(); ++it) { | ||||
auto repository = it.key(); | ||||
auto allRepositoryEvent = retrieveEvents(repository); | ||||
for (auto uuid : it.value()) { | ||||
for (auto repositoryEvent : allRepositoryEvent) { | ||||
if (uuid.toUuid() == repositoryEvent->getUniqId()) { | ||||
events << repositoryEvent; | ||||
} | ||||
} | ||||
} | ||||
} | ||||
return events; | ||||
} | ||||
r1059 | void CatalogueController::initialize() | |||
{ | ||||
r1243 | qCDebug(LOG_CatalogueController()) << tr("CatalogueController init") | |||
<< QThread::currentThread(); | ||||
r1242 | ||||
r1059 | impl->m_CatalogueDao.initialize(); | |||
r1126 | auto defaultRepositoryLocation | |||
= QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); | ||||
QDir defaultRepositoryLocationDir; | ||||
if (defaultRepositoryLocationDir.mkpath(defaultRepositoryLocation)) { | ||||
defaultRepositoryLocationDir.cd(defaultRepositoryLocation); | ||||
auto defaultRepository = defaultRepositoryLocationDir.absoluteFilePath(REPOSITORY_DEFAULT); | ||||
r1263 | ||||
r1159 | qCInfo(LOG_CatalogueController()) << tr("Persistant data loading from: ") | |||
<< defaultRepository; | ||||
r1263 | ||||
QDir dbDir(defaultRepository); | ||||
impl->m_RepositoryList << REPOSITORY_DEFAULT; | ||||
if (dbDir.exists()) { | ||||
auto dirName = dbDir.dirName(); | ||||
if (impl->m_CatalogueDao.addDB(defaultRepository, dirName)) { | ||||
impl->copyDBtoDB(dirName, impl->toWorkRepository(dirName)); | ||||
} | ||||
} | ||||
else { | ||||
qCInfo(LOG_CatalogueController()) << tr("Initialisation of Default repository detected") | ||||
<< defaultRepository; | ||||
} | ||||
r1125 | } | |||
r1126 | else { | |||
qCWarning(LOG_CatalogueController()) | ||||
<< tr("Cannot load the persistent default repository from ") | ||||
<< defaultRepositoryLocation; | ||||
} | ||||
qCDebug(LOG_CatalogueController()) << tr("CatalogueController init END"); | ||||
r1059 | } | |||
r1237 | QString CatalogueController::CatalogueControllerPrivate::eventUniqueKey( | |||
const std::shared_ptr<DBEvent> &event) const | ||||
{ | ||||
return event->getUniqId().toString().append(event->getRepository()); | ||||
} | ||||
r1276 | QString CatalogueController::CatalogueControllerPrivate::catalogueUniqueKey( | |||
const std::shared_ptr<DBCatalogue> &catalogue) const | ||||
{ | ||||
return catalogue->getUniqId().toString().append(catalogue->getRepository()); | ||||
} | ||||
r1159 | void CatalogueController::CatalogueControllerPrivate::copyDBtoDB(const QString &dbFrom, | |||
const QString &dbTo) | ||||
{ | ||||
r1225 | // auto cataloguesShared = std::list<std::shared_ptr<DBCatalogue> >{}; | |||
r1164 | auto catalogues = m_CatalogueDao.getCatalogues(dbFrom); | |||
r1225 | auto events = m_CatalogueDao.getEvents(dbFrom); | |||
r1159 | for (auto catalogue : catalogues) { | |||
r1225 | m_CatalogueDao.copyCatalogue(catalogue, dbTo, true); | |||
r1159 | } | |||
for (auto event : events) { | ||||
r1225 | m_CatalogueDao.copyEvent(event, dbTo, true); | |||
r1159 | } | |||
} | ||||
QString CatalogueController::CatalogueControllerPrivate::toWorkRepository(QString repository) | ||||
{ | ||||
auto syncRepository = toSyncRepository(repository); | ||||
r1224 | return QString("%1%2").arg(syncRepository, REPOSITORY_WORK_SUFFIX); | |||
r1159 | } | |||
QString CatalogueController::CatalogueControllerPrivate::toSyncRepository(QString repository) | ||||
{ | ||||
auto syncRepository = repository; | ||||
if (repository.endsWith(REPOSITORY_WORK_SUFFIX)) { | ||||
syncRepository.remove(REPOSITORY_WORK_SUFFIX); | ||||
} | ||||
else if (repository.endsWith(REPOSITORY_TRASH_SUFFIX)) { | ||||
syncRepository.remove(REPOSITORY_TRASH_SUFFIX); | ||||
} | ||||
return syncRepository; | ||||
} | ||||
r1224 | ||||
void CatalogueController::CatalogueControllerPrivate::savAllDB() | ||||
{ | ||||
for (auto repository : m_RepositoryList) { | ||||
auto defaultRepositoryLocation | ||||
= QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); | ||||
m_CatalogueDao.saveDB(defaultRepositoryLocation, repository); | ||||
} | ||||
} | ||||
void CatalogueController::CatalogueControllerPrivate::saveEvent(std::shared_ptr<DBEvent> event, | ||||
bool persist) | ||||
{ | ||||
r1225 | m_CatalogueDao.copyEvent(*event, toSyncRepository(event->getRepository()), true); | |||
r1224 | if (persist) { | |||
savAllDB(); | ||||
} | ||||
} | ||||
void CatalogueController::CatalogueControllerPrivate::saveCatalogue( | ||||
std::shared_ptr<DBCatalogue> catalogue, bool persist) | ||||
{ | ||||
r1225 | m_CatalogueDao.copyCatalogue(*catalogue, toSyncRepository(catalogue->getRepository()), true); | |||
r1224 | if (persist) { | |||
savAllDB(); | ||||
} | ||||
} | ||||
|
r1268 | |||
r1276 | std::shared_ptr<IRequestPredicate> CatalogueController::CatalogueControllerPrivate::createFinder( | |||
const QUuid &uniqId, const QString &repository, DBType type) | ||||
|
r1268 | { | ||
// update catalogue parameter | ||||
r1276 | auto uniqIdPredicate = std::make_shared<ComparaisonPredicate>(QString{"uniqId"}, uniqId, | |||
ComparaisonOperation::EQUALEQUAL); | ||||
|
r1268 | |||
auto repositoryType = repository; | ||||
switch (type) { | ||||
r1276 | case DBType::SYNC: | |||
repositoryType = toSyncRepository(repositoryType); | ||||
break; | ||||
case DBType::WORK: | ||||
repositoryType = toWorkRepository(repositoryType); | ||||
break; | ||||
case DBType::TRASH: | ||||
default: | ||||
break; | ||||
|
r1268 | } | ||
auto repositoryPredicate = std::make_shared<ComparaisonPredicate>( | ||||
r1276 | QString{"repository"}, repositoryType, ComparaisonOperation::EQUALEQUAL); | |||
|
r1268 | |||
auto finderPred = std::make_shared<CompoundPredicate>(CompoundOperation::AND); | ||||
finderPred->AddRequestPredicate(uniqIdPredicate); | ||||
finderPred->AddRequestPredicate(repositoryPredicate); | ||||
return finderPred; | ||||
} | ||||