[system/karton] src: Implement preview image deletion and storing its path

Derek Lin <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit 65c5df75705b046e4e34d1f27c3e8005ff1151f9 by Derek Lin.
Committed on 29/07/2026 at 17:58.
Pushed by kenoi into branch 'master'.

Implement preview image deletion and storing its path

M  +2    -6    src/domain.cpp
M  +0    -2    src/domain.h
M  +4    -0    src/domainconfig.cpp
M  +8    -0    src/domainconfig.h
M  +2    -0    src/domaininstaller.cpp
M  +4    -1    src/domainxmlreader.cpp
M  +2    -1    src/domainxmlreader.h
M  +15   -1    src/karton.cpp
M  +2    -2    src/qml/VMPage.qml

https://invent.kde.org/system/karton/-/commit/65c5df75705b046e4e34d1f27c3e8005ff1151f9

diff --git a/src/domain.cpp b/src/domain.cpp
index 8c97c11..626d576 100644
--- a/src/domain.cpp
+++ b/src/domain.cpp
@@ -80,13 +80,13 @@ QString Domain::uuidString(virDomainPtr domainPtr)
 
 void Domain::savePreviewFrame(QImage frame)
 {
-    qCDebug(KARTON_DEBUG) << "SavePreviewPath:" << previewPath();
+    qCDebug(KARTON_DEBUG) << "SavePreviewPath:" << this->config()->screenshotPreviewPath();
     QDir baseDir(kartonDir());
     if (!baseDir.mkpath(QStringLiteral("previews"))) {
         qCCritical(KARTON_DEBUG) << "Failed to create preview directory: " << kartonDir();
         return;
     }
-    frame.save(previewPath());
+    frame.save(this->config()->screenshotPreviewPath());
 
     Q_EMIT previewChanged();
 }
@@ -95,7 +95,3 @@ QString Domain::kartonDir() const
     QString dataDir = QStandardPaths::writableLocation(QStandardPaths::StateLocation);
     return QStringLiteral("%1").arg(dataDir);
 }
-QString Domain::previewPath() const
-{
-    return QStringLiteral("%1/previews/%2.png").arg(kartonDir()).arg(m_config->uuid());
-}
diff --git a/src/domain.h b/src/domain.h
index 87bbdd5..843a38e 100644
--- a/src/domain.h
+++ b/src/domain.h
@@ -21,7 +21,6 @@ class Domain : public QObject
     Q_PROPERTY(int ramUsage READ ramUsage NOTIFY ramUsageChanged)
     Q_PROPERTY(bool autostart READ autostart NOTIFY autostartChanged)
     Q_PROPERTY(DomainConfig *config READ config CONSTANT)
-    Q_PROPERTY(QString previewPath READ previewPath CONSTANT)
 
 Q_SIGNALS:
     void isActiveChanged(const bool active);
@@ -71,7 +70,6 @@ public:
     void setAutostart(bool autostart);
     static QString uuidString(virDomainPtr domainPtr);
     void savePreviewFrame(QImage frame);
-    QString previewPath() const;
 
 private:
     QString kartonDir() const;
diff --git a/src/domainconfig.cpp b/src/domainconfig.cpp
index 63d13f6..804cd81 100644
--- a/src/domainconfig.cpp
+++ b/src/domainconfig.cpp
@@ -21,6 +21,7 @@ DomainConfig::DomainConfig(QObject *parent)
     , m_xmlConfigPath(QString())
     , m_isoDiskPath(QString())
     , m_virtualDiskPath(QString())
+    , m_screenshotPreviewPath(QString())
     , m_autostart(false)
 {
 }
@@ -41,6 +42,7 @@ DomainConfig::DomainConfig(const DomainConfigData &data)
                    data.xmlConfigPath,
                    data.isoDiskPath,
                    data.virtualDiskPath,
+                   data.screenshotPreviewPath,
                    data.autostart,
                    data.parent)
 {
@@ -61,6 +63,7 @@ DomainConfig::DomainConfig(const QString &hypervisorType,
                            const QString &xmlConfigPath,
                            const QString &isoDiskPath,
                            const QString &virtualDiskPath,
+                           const QString &screenshotPreviewPath,
                            bool autostart,
                            QObject *parent)
     : QObject(parent)
@@ -79,6 +82,7 @@ DomainConfig::DomainConfig(const QString &hypervisorType,
     , m_xmlConfigPath(xmlConfigPath)
     , m_isoDiskPath(isoDiskPath)
     , m_virtualDiskPath(virtualDiskPath)
+    , m_screenshotPreviewPath(screenshotPreviewPath)
     , m_autostart(autostart)
 {
 }
diff --git a/src/domainconfig.h b/src/domainconfig.h
index 72210e9..876703b 100644
--- a/src/domainconfig.h
+++ b/src/domainconfig.h
@@ -25,6 +25,7 @@ class DomainConfig : public QObject
     Q_PROPERTY(QString xmlConfigPath READ xmlConfigPath CONSTANT)
     Q_PROPERTY(QString isoDiskPath READ isoDiskPath CONSTANT)
     Q_PROPERTY(QString virtualDiskPath READ virtualDiskPath CONSTANT)
+    Q_PROPERTY(QString screenshotPreviewPath READ screenshotPreviewPath CONSTANT)
     Q_PROPERTY(bool autostart READ autostart NOTIFY autostartChanged)
 
 Q_SIGNALS:
@@ -50,6 +51,7 @@ public:
         QString xmlConfigPath;
         QString isoDiskPath;
         QString virtualDiskPath;
+        QString screenshotPreviewPath;
         bool autostart;
         QObject *parent = nullptr;
     };
@@ -70,6 +72,7 @@ public:
                           const QString &xmlConfigPath,
                           const QString &isoDiskPath,
                           const QString &virtualDiskPath,
+                          const QString &screenshotPreviewPath,
                           bool autostart,
                           QObject *parent = nullptr);
 
@@ -134,6 +137,10 @@ public:
     {
         return m_virtualDiskPath;
     }
+    [[nodiscard]] QString screenshotPreviewPath() const
+    {
+        return m_screenshotPreviewPath;
+    }
     [[nodiscard]] bool autostart() const
     {
         return m_autostart;
@@ -160,5 +167,6 @@ private:
     QString m_xmlConfigPath;
     QString m_isoDiskPath;
     QString m_virtualDiskPath;
+    QString m_screenshotPreviewPath;
     bool m_autostart;
 };
\ No newline at end of file
diff --git a/src/domaininstaller.cpp b/src/domaininstaller.cpp
index ed40ba8..abe669c 100644
--- a/src/domaininstaller.cpp
+++ b/src/domaininstaller.cpp
@@ -72,6 +72,8 @@ QString DomainInstaller::generateXML(virConnectPtr conn, const DomainConfig *con
     metadata.appendChild(karton);
     QMap<QString, QString> kartonData;
     kartonData[QStringLiteral("maxDiskStorage")] = QString::number(config->maxDiskStorage() * 1024);
+    QString dataDir = QStandardPaths::writableLocation(QStandardPaths::StateLocation);
+    kartonData[QStringLiteral("screenshotPreviewPath")] = QStringLiteral("%1/previews/%2.png").arg(dataDir).arg(uuidString);
     addElementWithAttributes(document, karton, QStringLiteral("karton:data"), QString(), kartonData);
 
     // metadata->LIBOSINFO
diff --git a/src/domainxmlreader.cpp b/src/domainxmlreader.cpp
index 803808c..a8a93e1 100644
--- a/src/domainxmlreader.cpp
+++ b/src/domainxmlreader.cpp
@@ -31,7 +31,7 @@ DomainXmlReader::XmlInfo DomainXmlReader::readConfigFile(const QString &path)
     while (!xmlReader.atEnd() && !xmlReader.hasError()) {
         QXmlStreamReader::TokenType token = xmlReader.readNext();
         if (token == QXmlStreamReader::StartElement) {
-            // qCInfo(KARTON_DEBUG) << xmlReader.name(); // prints each element
+            // qCInfo(KARTON_DEBUG) << "Current element: " << xmlReader.name(); // uncomment to print each element
             if (xmlReader.name() == QStringLiteral("domain")) {
                 info.indexId = xmlReader.attributes().value("id").toInt();
                 info.hypervisorType = xmlReader.attributes().value("type").toString();
@@ -43,6 +43,9 @@ DomainXmlReader::XmlInfo DomainXmlReader::readConfigFile(const QString &path)
             if (xmlReader.name() == QStringLiteral("data") && xmlReader.attributes().hasAttribute(QStringLiteral("maxDiskStorage"))) {
                 info.maxDiskStorage = xmlReader.attributes().value("maxDiskStorage").toInt();
             }
+            if (xmlReader.name() == QStringLiteral("data") && xmlReader.attributes().hasAttribute(QStringLiteral("screenshotPreviewPath"))) {
+                info.screenshotPreviewPath = xmlReader.attributes().value("screenshotPreviewPath").toString();
+            }
             if (xmlReader.name() == QStringLiteral("disk") && xmlReader.attributes().hasAttribute(QStringLiteral("device"))) {
                 if (xmlReader.attributes().value(QStringLiteral("device")) == QStringLiteral("disk")) {
                     info.virtualDiskPath = retrieveDiskPath(xmlReader, token);
diff --git a/src/domainxmlreader.h b/src/domainxmlreader.h
index 0780f12..7f7bbbc 100644
--- a/src/domainxmlreader.h
+++ b/src/domainxmlreader.h
@@ -17,11 +17,12 @@ public:
     struct XmlInfo {
         QString hypervisorType;
         int indexId = 0;
+        int maxDiskStorage = 0;
         QString osId;
         QString shortOsId;
         QString isoDiskPath;
         QString virtualDiskPath;
-        int maxDiskStorage = 0;
+        QString screenshotPreviewPath;
     };
     XmlInfo readConfigFile(const QString &path);
     QString retrieveDiskPath(QXmlStreamReader &xmlReader, QXmlStreamReader::TokenType token);
diff --git a/src/karton.cpp b/src/karton.cpp
index 9a2f7b2..fb8b08a 100644
--- a/src/karton.cpp
+++ b/src/karton.cpp
@@ -23,7 +23,7 @@
 Karton::Karton(QObject *parent)
     : QObject(parent)
     , m_conn(nullptr)
-    , m_domains(QVector<Domain *>())
+    , m_domains()
     , m_monitor(nullptr)
     , m_domainViewer(nullptr)
     , m_currentDomain(nullptr)
@@ -191,10 +191,16 @@ void Karton::refreshDomainList()
         int cpus = domInfo.nrVirtCpu;
 
         QString dataDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
+        QString stateDir = QStandardPaths::writableLocation(QStandardPaths::StateLocation);
         QString xmlConfigPath = getXmlConfigPath(QString::fromUtf8(name));
 
         DomainXmlReader *reader = new DomainXmlReader(xmlConfigPath);
 
+        QString screenshotPreviewPath = reader->m_xmlInfo.screenshotPreviewPath;
+        if (screenshotPreviewPath == QString()) { // set default path if not found
+            screenshotPreviewPath = QStringLiteral("%1/previews/%2.png").arg(stateDir).arg(Domain::uuidString(domainPtr));
+        }
+
         int autoFlag = 0;
         virDomainGetAutostart(domains[i], &autoFlag);
         bool autostart = (autoFlag != 0);
@@ -215,6 +221,7 @@ void Karton::refreshDomainList()
                                        .xmlConfigPath = xmlConfigPath,
                                        .isoDiskPath = reader->m_xmlInfo.isoDiskPath,
                                        .virtualDiskPath = reader->m_xmlInfo.virtualDiskPath,
+                                       .screenshotPreviewPath = screenshotPreviewPath,
                                        .autostart = autostart,
                                        .parent = this};
 
@@ -307,6 +314,13 @@ bool Karton::deleteDomain(const Domain *domain, const bool deleteDisk)
         }
         qCInfo(KARTON_DEBUG) << "Successfully deleted disk image of " << domain->config()->name();
     }
+    if (!QFile::remove(domain->config()->screenshotPreviewPath())) {
+        QString errorMsg = i18nc("%1 is path of the image file", "Failed to delete image file: %1", domain->config()->virtualDiskPath());
+        qCWarning(KARTON_DEBUG) << errorMsg;
+        Q_EMIT errorOccurred(errorMsg);
+        return false;
+    }
+    qCInfo(KARTON_DEBUG) << "Successfully deleted preview image of " << domain->config()->name();
 
     qCInfo(KARTON_DEBUG) << "Successfully undefined domain:" << domain->config()->name();
     return true;
diff --git a/src/qml/VMPage.qml b/src/qml/VMPage.qml
index 106d747..a3cd91d 100644
--- a/src/qml/VMPage.qml
+++ b/src/qml/VMPage.qml
@@ -84,12 +84,12 @@ Kirigami.ScrollablePage {
                 id: previewImage
                 anchors.fill: parent
                 fillMode: Image.PreserveAspectFit
-                source: "file://" + domain.previewPath
+                source: "file://" + domain.config.screenshotPreviewPath
 
                 Connections {
                     target: domain
                     function onPreviewChanged() {
-                        previewImage.source = "file://" + domain.previewPath + "?" + Date.now();
+                        previewImage.source = "file://" + domain.config.screenshotPreviewPath + "?" + Date.now();
                     }
                 }
             }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.