File indexing completed on 2024-05-12 04:37:32
0001 /* 0002 SPDX-FileCopyrightText: 2020 Friedrich W. H. Kossebau <kossebau@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "sessionfilestracker.h" 0008 0009 // library 0010 #include <kdevelopsessionsobserver.h> 0011 // KF 0012 #include <KDirWatch> 0013 #include <KConfig> 0014 #include <KConfigGroup> 0015 // Qt 0016 #include <QFileInfo> 0017 #include <QDir> 0018 #include <QStandardPaths> 0019 #include <QUuid> 0020 #include <QMutexLocker> 0021 #include <QMetaObject> 0022 #include <QCoreApplication> 0023 // Std 0024 #include <algorithm> 0025 0026 namespace { 0027 namespace Strings { 0028 QString sessionConfigFileName() { return QStringLiteral("sessionrc"); } 0029 } 0030 } 0031 0032 Q_GLOBAL_STATIC(SessionFilesTracker, s_SessionFilesTrackerInstance) 0033 0034 SessionFilesTracker *SessionFilesTracker::instance() 0035 { 0036 return s_SessionFilesTrackerInstance(); 0037 } 0038 0039 static void setSessionDataList(QObject* observer, const QVector<KDevelopSessionData>& sessionDataList) 0040 { 0041 QMetaObject::invokeMethod(observer, "setSessionDataList", Qt::AutoConnection, 0042 Q_ARG(QVector<KDevelopSessionData>, sessionDataList)); 0043 } 0044 0045 static void cleanupSessionFilesTracker() 0046 { 0047 if (s_SessionFilesTrackerInstance.exists()) { 0048 s_SessionFilesTrackerInstance->cleanup(); 0049 } 0050 } 0051 0052 0053 SessionFilesTracker::SessionFilesTracker() 0054 : QObject() 0055 , m_dirWatch(new KDirWatch(this)) 0056 { 0057 // KDirWatch might have QFileSystemWatcher, 0058 // which wants to be deleted before qApp is gone - bug 261541 0059 qAddPostRoutine(cleanupSessionFilesTracker); 0060 0061 m_sessionDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/kdevelop/sessions"); 0062 m_dirWatch->stopScan(); 0063 m_dirWatch->addDir(m_sessionDir, KDirWatch::WatchSubDirs); 0064 0065 connect(m_dirWatch, &KDirWatch::dirty, this, &SessionFilesTracker::sessionSourceChanged); 0066 0067 updateSessions(); 0068 } 0069 0070 SessionFilesTracker::~SessionFilesTracker() = default; 0071 0072 void SessionFilesTracker::cleanup() 0073 { 0074 delete m_dirWatch; 0075 m_dirWatch = nullptr; 0076 } 0077 0078 0079 void SessionFilesTracker::registerObserver(QObject* observer) 0080 { 0081 if (!qobject_cast<KDevelopSessionsObserver*>(observer)) { 0082 return; 0083 } 0084 0085 QMutexLocker lock(&m_mutex); 0086 const bool isFirstObserver = m_observers.isEmpty(); 0087 0088 m_observers.append(observer); 0089 setSessionDataList(observer, m_sessionDataList); 0090 0091 if (isFirstObserver) { 0092 m_dirWatch->startScan(true); 0093 } 0094 } 0095 0096 void SessionFilesTracker::unregisterObserver(QObject* observer) 0097 { 0098 if (!qobject_cast<KDevelopSessionsObserver*>(observer)) { 0099 return; 0100 } 0101 0102 QMutexLocker lock(&m_mutex); 0103 m_observers.removeOne(observer); 0104 0105 if (m_observers.isEmpty()) { 0106 m_dirWatch->stopScan(); 0107 } 0108 } 0109 0110 QVector<KDevelopSessionData> SessionFilesTracker::readSessionDataList() const 0111 { 0112 QVector<KDevelopSessionData> sessions; 0113 0114 QDir sessionBaseDir(m_sessionDir); 0115 const auto dirEntries = sessionBaseDir.entryList(QDir::Dirs); 0116 sessions.reserve(dirEntries.size()); 0117 for (const QString& sessionDirName : dirEntries) { 0118 if (QUuid(sessionDirName).isNull()) { 0119 continue; 0120 } 0121 0122 QDir sessionDir(sessionBaseDir.absoluteFilePath(sessionDirName)); 0123 const QString sessionConfigFilePath = sessionDir.filePath(Strings::sessionConfigFileName()); 0124 if (!QFile::exists(sessionConfigFilePath)) { 0125 continue; 0126 } 0127 0128 KConfig sessionDataStorage(sessionConfigFilePath, KConfig::SimpleConfig); 0129 const KConfigGroup mainSessionData = sessionDataStorage.group(""); 0130 0131 const KDevelopSessionData sessionData { 0132 sessionDirName, 0133 mainSessionData.readEntry("SessionName"), 0134 mainSessionData.readEntry("SessionPrettyContents"), 0135 }; 0136 0137 sessions.append(sessionData); 0138 } 0139 sessions.squeeze(); 0140 std::sort(sessions.begin(), sessions.end(), [](const KDevelopSessionData& a, const KDevelopSessionData& b) { 0141 return a.id < b.id; 0142 }); 0143 0144 return sessions; 0145 } 0146 0147 void SessionFilesTracker::sessionSourceChanged(const QString& path) 0148 { 0149 // session data is not changed too often, so we are fine to simply rescan all the data 0150 // in case any relevant files (or the main dir) have been touched 0151 0152 // session dirs removed or added? 0153 if (m_sessionDir == path) { 0154 updateSessions(); 0155 } else { 0156 // session config file? 0157 QFileInfo pathInfo(path); 0158 if (pathInfo.fileName() == Strings::sessionConfigFileName()) { 0159 updateSessions(); 0160 } 0161 } 0162 } 0163 0164 void SessionFilesTracker::updateSessions() 0165 { 0166 QMutexLocker lock(&m_mutex); 0167 0168 const auto newSessionDataList = readSessionDataList(); 0169 0170 if (m_sessionDataList == newSessionDataList) { 0171 return; 0172 } 0173 0174 m_sessionDataList = newSessionDataList; 0175 0176 for (auto* observer : qAsConst(m_observers)) { 0177 setSessionDataList(observer, m_sessionDataList); 0178 } 0179 } 0180 0181 #include "moc_sessionfilestracker.cpp"