summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2015-11-12 17:03:11 +0100
committerSimon Rettberg2015-11-12 17:03:11 +0100
commit1c49173c8f62d3b9e609d22a027a42376db5d3de (patch)
tree2e5559d0435aa5ff784ee58e7dbcc8524a048984
parentAdd images for win2k, winxp, win8 (diff)
downloadvmchooser2-1c49173c8f62d3b9e609d22a027a42376db5d3de.tar.gz
vmchooser2-1c49173c8f62d3b9e609d22a027a42376db5d3de.tar.xz
vmchooser2-1c49173c8f62d3b9e609d22a027a42376db5d3de.zip
Start refactoring download helpers and icon management
-rw-r--r--src/FileDownloader.cpp65
-rw-r--r--src/FileDownloader.h27
-rw-r--r--src/dialog.cpp11
-rw-r--r--src/dialog.h4
-rw-r--r--src/session.h3
-rw-r--r--src/sessionsiconholder.cpp47
-rw-r--r--src/sessionsiconholder.h12
-rw-r--r--src/sessiontreemodel.cpp56
-rw-r--r--src/sessiontreemodel.h3
-rw-r--r--src/vsession.cpp62
-rw-r--r--src/vsession.h2
-rw-r--r--src/xsession.cpp5
-rw-r--r--src/xsession.h2
13 files changed, 181 insertions, 118 deletions
diff --git a/src/FileDownloader.cpp b/src/FileDownloader.cpp
index 1a0297f..b9f79be 100644
--- a/src/FileDownloader.cpp
+++ b/src/FileDownloader.cpp
@@ -9,30 +9,65 @@
#include "FileDownloader.h"
-FileDownloader::FileDownloader(QObject *parent) :
- QObject(parent) {
- connect(&m_WebCtrl, SIGNAL(finished(QNetworkReply*)),
- SLOT(fileDownloaded(QNetworkReply*)));
+// Maximum size of download
+#define MAXSIZE (200000)
+
+static QNetworkAccessManager m_WebCtrl;
+
+FileDownloader::FileDownloader(const QUrl& fileUrl, QObject *parent) :
+ QObject(parent), started(false), url(fileUrl) {
}
FileDownloader::~FileDownloader() {
}
-void FileDownloader::connectSlot(QObject* obj, const char* slot) {
- QObject::connect(this, SIGNAL(downloaded(QString&, QByteArray)),
- obj, slot);
+bool FileDownloader::downloadFile() {
+ if (this->started)
+ return true;
+ QNetworkReply *reply = m_WebCtrl.get(QNetworkRequest(this->url));
+ if (reply == NULL)
+ return false;
+ this->started = true;
+ connect(reply, SIGNAL(finished()), SLOT(fileDownloaded()));
+ connect(reply, SIGNAL(downloadProgress(qint64, qint64)), SLOT(downloadProgress(qint64, qint64)));
+ return true;
}
-void FileDownloader::fileDownloaded(QNetworkReply* pReply) {
- QByteArray downloadedData = pReply->readAll();
+/*
+ * Slots from networkreply
+ */
+
+void FileDownloader::downloadFailed(QNetworkReply::NetworkError) {
+ QNetworkReply *reply = (QNetworkReply*)this->sender();
+ killReply(reply);
+ emit downloaded(this->url, QByteArray());
+}
+
+void FileDownloader::fileDownloaded() {
+ QNetworkReply *reply = (QNetworkReply*)this->sender();
+ if (reply == NULL)
+ return;
+ QByteArray downloadedData(reply->readAll());
+ killReply(reply);
//emit a signal
- pReply->deleteLater();
- emit downloaded(this->fileName, downloadedData);
- this->deleteLater(); // TODO: RAII - Object should not delete itself
+ emit downloaded(this->url, downloadedData);
+}
+
+void FileDownloader::downloadProgress(qint64 received, qint64 totalSize) {
+ QNetworkReply *reply = (QNetworkReply*)this->sender();
+ if (reply == NULL)
+ return;
+ if (received > MAXSIZE || totalSize > MAXSIZE) {
+ killReply(reply);
+ emit downloaded(this->url, QByteArray());
+ }
}
-void FileDownloader::downloadFile(const QUrl& fileUrl) {
- this->fileName = fileUrl.toString();
- m_WebCtrl.get(QNetworkRequest(fileUrl));
+void FileDownloader::killReply(QNetworkReply *reply) {
+ if (reply == NULL)
+ return;
+ reply->blockSignals(true);
+ reply->abort();
+ reply->deleteLater();
}
diff --git a/src/FileDownloader.h b/src/FileDownloader.h
index fccfa7a..f66f7f9 100644
--- a/src/FileDownloader.h
+++ b/src/FileDownloader.h
@@ -17,28 +17,35 @@
class FileDownloader : public QObject
{
Q_OBJECT
-public:
- explicit FileDownloader(QObject *parent = 0);
- virtual ~FileDownloader();
+public:
- void downloadFile(const QUrl& fileUrl);
+ explicit FileDownloader(const QUrl& fileUrl, QObject *parent = 0);
- void connectSlot(QObject* obj, const char* slot);
+ virtual ~FileDownloader();
- QByteArray downloadedData() const;
+ bool downloadFile();
signals:
- void downloaded(QString& fileName, QByteArray downloadedData);
+
+ /**
+ * Triggered when the download has finished.
+ * On error, downloadedData will be empty.
+ */
+ void downloaded(const QUrl& url, const QByteArray& downloadedData);
private slots:
- void fileDownloaded(QNetworkReply* pReply);
+ void fileDownloaded();
+ void downloadFailed(QNetworkReply::NetworkError code);
+ void downloadProgress(qint64 received, qint64 totalSize);
private:
- QNetworkAccessManager m_WebCtrl;
- QString fileName;
+ void killReply(QNetworkReply *reply);
+
+ bool started;
+ QUrl url;
};
diff --git a/src/dialog.cpp b/src/dialog.cpp
index 7cf8cd1..605aeb4 100644
--- a/src/dialog.cpp
+++ b/src/dialog.cpp
@@ -63,13 +63,12 @@ Dialog::Dialog(QWidget *parent)
// TODO: Implement bug report dialog :)
ui->buttonBugReport->setEnabled(false);
+ QObject::connect(SessionsIconHolder::get(), SIGNAL(iconDownloaded(const QUrl&, const QIcon&)),
+ this, SLOT(iconDownloaded(const QUrl&, const QIcon&)));
}
Dialog::~Dialog() {
delete ui;
- delete model_[0];
- delete model_[1];
- delete model_[2];
}
void Dialog::changeEvent(QEvent *e) {
@@ -600,3 +599,9 @@ void Dialog::keyPressEvent(QKeyEvent* event) {
case Qt::Key_H: this->on_helpNewsButton_clicked(); break;
}
}
+
+void Dialog::iconDownloaded(const QUrl& url, const QIcon&) {
+ qDebug() << "Icon downloaded... (" << url << ")";
+ // TODO: Check which model(s) contain an entry with this icon
+ model_[2]->updateView();
+}
diff --git a/src/dialog.h b/src/dialog.h
index 0f45466..59d2e48 100644
--- a/src/dialog.h
+++ b/src/dialog.h
@@ -10,6 +10,7 @@
#include "session.h"
#include "sessiontreemodel.h"
+#include "sessionsiconholder.h"
namespace Ui {
class Dialog;
@@ -50,6 +51,7 @@ class Dialog : public QDialog {
void onTabButtonChanged(int tab);
void configClearButton();
void setListModel(QAbstractItemModel *model);
+ void keyPressEvent(QKeyEvent * e);
private slots:
void on_pushButtonStart_clicked();
@@ -62,7 +64,7 @@ class Dialog : public QDialog {
void treeView_selectionChanged(const QModelIndex& current, const QModelIndex&);
void on_helpNewsButton_clicked();
void onCenterTimer();
- void keyPressEvent(QKeyEvent * e);
+ void iconDownloaded(const QUrl& url, const QIcon& icon);
public slots:
void addSessionsAfterDownload(QNetworkReply* reply);
diff --git a/src/session.h b/src/session.h
index e1af027..515bd2d 100644
--- a/src/session.h
+++ b/src/session.h
@@ -2,6 +2,7 @@
#define VMCHOOSER_SESSION_H_
class QString;
+class QIcon;
class Session {
public:
@@ -13,7 +14,7 @@ class Session {
virtual int priority() const = 0;
virtual QString shortDescription() const = 0;
virtual QString description() const = 0;
- virtual QString icon() const = 0;
+ virtual QIcon icon() const = 0;
virtual bool run() const = 0;
virtual int type() const = 0;
diff --git a/src/sessionsiconholder.cpp b/src/sessionsiconholder.cpp
index b52d93d..7cce455 100644
--- a/src/sessionsiconholder.cpp
+++ b/src/sessionsiconholder.cpp
@@ -12,21 +12,27 @@
#include <QIcon>
#include <QResource>
#include <QFileInfo>
+#include <QCryptographicHash>
#include "globals.h"
#include "sessionsiconholder.h"
#include "sessiontreemodel.h"
#include "FileDownloader.h"
-SessionsIconHolder::SessionsIconHolder(SessionTreeModel& sessionTreeModel):treeModel(sessionTreeModel) {
+SessionsIconHolder* SessionsIconHolder::instance = NULL;
+
+static inline QString url2filename(const QString& url) {
+ return iconsTempPath + QString(QCryptographicHash::hash(url.toUtf8(), QCryptographicHash::Md5).toHex());
+}
+
+SessionsIconHolder::SessionsIconHolder() {
QDir().mkpath(iconsTempPath);
}
-void SessionsIconHolder::afterDownload(QString& url, QByteArray downloadedData) {
+void SessionsIconHolder::afterDownload(const QUrl& url, const QByteArray& downloadedData) {
// save the data to disk
- QString file_name = url.replace("http://", "");
- file_name = file_name.replace("/", "_");
- QString file_path = iconsTempPath + file_name;
+ QString strUrl(url.toString());
+ QString file_path(url2filename(strUrl));
QFile file(file_path);
if (!file.open(QFile::WriteOnly)) {
if (debugMode) {
@@ -46,10 +52,9 @@ void SessionsIconHolder::afterDownload(QString& url, QByteArray downloadedData)
file.close();
QIcon icon(file_path);
- icons.insert(url, icon);
+ icons.insert(strUrl, icon);
- // trigger the SessionTreeModel to update the view
- treeModel.updateView();
+ emit iconDownloaded(url, icon);
}
QIcon SessionsIconHolder::getIcon(const QString& name) {
@@ -60,10 +65,11 @@ QIcon SessionsIconHolder::getIcon(const QString& name) {
// else load icon from resource
QIcon icon;
- if (QResource(":" + name.toLower() + ".svg").isValid()) {
- icon = QIcon(":" + name.toLower() + ".svg");
- } else if (QResource(":" + name.toLower()).isValid()) {
- icon = QIcon(":" + name.toLower());
+ QString resName(":" + name.toLower());
+ if (QResource(resName + ".svg").isValid()) {
+ icon = QIcon(resName + ".svg");
+ } else if (QResource(resName).isValid()) {
+ icon = QIcon(resName);
} else {
icon = QIcon();
}
@@ -80,20 +86,23 @@ QIcon SessionsIconHolder::getIcon(const QUrl& url) {
}
// search the icon in the tmp folder
- QString file_name = url.toString().replace("http://", "");
- file_name = file_name.replace("/", "_");
- QString file_path = iconsTempPath + file_name;
+ QString strUrl(url.toString());
+ QString file_path(url2filename(strUrl));
if (QFile::exists(file_path)) {
QIcon icon(file_path);
- icons.insert(url.toString(), icon);
+ icons.insert(strUrl, icon);
return icon;
}
+ // Put empty icon in map while we're downloading, so successive calls won't trigger
+ // more downloads before the running download finishes
+ icons.insert(strUrl, QIcon());
// else load icon from url
- FileDownloader* fileDownloader = new FileDownloader(this);
- fileDownloader->connectSlot(this, SLOT(afterDownload(QString&, QByteArray)));
- fileDownloader->downloadFile(url);
+ FileDownloader* fileDownloader = new FileDownloader(url, this);
+ QObject::connect(fileDownloader, SIGNAL(downloaded(const QUrl&, const QByteArray&)),
+ this, SLOT(afterDownload(const QUrl&, const QByteArray&)));
+ fileDownloader->downloadFile();
return QIcon();
}
diff --git a/src/sessionsiconholder.h b/src/sessionsiconholder.h
index d960654..a13156e 100644
--- a/src/sessionsiconholder.h
+++ b/src/sessionsiconholder.h
@@ -21,20 +21,24 @@
class SessionTreeModel;
-class SessionsIconHolder : QObject {
+class SessionsIconHolder : public QObject {
Q_OBJECT
private:
QHash<QString, QIcon> icons;
- SessionTreeModel& treeModel;
+ SessionsIconHolder();
+ static SessionsIconHolder* instance;
+
+signals:
+ void iconDownloaded(const QUrl& url, const QIcon& icon);
public:
- SessionsIconHolder(SessionTreeModel& sessionTreeModel);
QIcon getIcon(const QString& name);
QIcon getIcon(const QUrl& url);
+ static SessionsIconHolder* get() { if (instance == NULL) instance = new SessionsIconHolder(); return instance; }
public slots:
- void afterDownload(QString& iconName, QByteArray downloadedData);
+ void afterDownload(const QUrl& url, const QByteArray& downloadedData);
};
#endif /* SESSIONSICONHOLDER_H_ */
diff --git a/src/sessiontreemodel.cpp b/src/sessiontreemodel.cpp
index 7b88015..aaf47b9 100644
--- a/src/sessiontreemodel.cpp
+++ b/src/sessiontreemodel.cpp
@@ -13,7 +13,6 @@
SessionTreeModel::SessionTreeModel(QObject *parent)
: QAbstractItemModel(parent) {
root_ = new SessionTreeItem("dummy");
- iconHolder = new SessionsIconHolder(*this);
}
SessionTreeModel::~SessionTreeModel() {
@@ -55,60 +54,7 @@ QVariant SessionTreeModel::data(const QModelIndex &index, int role) const {
return s->description();
if (role == Qt::DecorationRole) {
if (index.column() == 0) { // TODO: is this line needed?
- QString icon(s->icon());
-
- if (icon.isEmpty()) {
- // Nothing...
- } else if (icon.startsWith("http://")) {
- // try to load icon from url
- QIcon url_icon = iconHolder->getIcon(QUrl(icon));
- if (!url_icon.isNull()) {
- return url_icon;
- }
- } else if (QFileInfo(icon).isAbsolute()) {
- // try to load icon from file
- return QIcon(icon);
- } else {
- // try to load icon from QResource
- QIcon res_icon = iconHolder->getIcon(icon);
- if (!res_icon.isNull()) {
- return res_icon;
- }
- }
- // fallback to os icon
- if (s->type() == Session::VSESSION) {
- const VSession* vs = (VSession*) s;
- QString os(vs->getAttribute("os", "param").toLower());
- if (!os.isEmpty()) {
- QIcon osi = iconHolder->getIcon(os);
- if (!osi.isNull())
- return osi;
- if (os == "dos")
- return iconHolder->getIcon("dos");
- if (os.startsWith("windows7"))
- return iconHolder->getIcon("win7");
- if (os.startsWith("win31"))
- return iconHolder->getIcon("win311");
- if (os.startsWith("windows8"))
- return iconHolder->getIcon("win8");
- if (os.startsWith("win2000"))
- return iconHolder->getIcon("win2000");
- if (os.startsWith("winxp"))
- return iconHolder->getIcon("winxp");
- if (os.startsWith("debian"))
- return iconHolder->getIcon("debian");
- if (os.startsWith("ubuntu"))
- return iconHolder->getIcon("ubuntu");
- if (os.startsWith("win"))
- return iconHolder->getIcon("windows");
- if (os.contains("linux"))
- return iconHolder->getIcon("linux");
- }
- if (vs->imgtype() == VMWARE)
- return iconHolder->getIcon("vmware");
- if (vs->imgtype() == VBOX)
- return iconHolder->getIcon("virtualbox");
- }
+ return s->icon();
}
}
} else if (role == Qt::DisplayRole) {
diff --git a/src/sessiontreemodel.h b/src/sessiontreemodel.h
index 9079c59..481c5f7 100644
--- a/src/sessiontreemodel.h
+++ b/src/sessiontreemodel.h
@@ -5,8 +5,6 @@
#include <QModelIndex>
#include <QVariant>
-#include "sessionsiconholder.h"
-
class SessionTreeItem;
class Session;
@@ -37,7 +35,6 @@ class SessionTreeModel : public QAbstractItemModel {
private:
SessionTreeItem* root_;
- SessionsIconHolder* iconHolder;
};
#endif // VMCHOOSER_SESSIONTREEMODEL_H
diff --git a/src/vsession.cpp b/src/vsession.cpp
index 5cd9d0b..45587f1 100644
--- a/src/vsession.cpp
+++ b/src/vsession.cpp
@@ -5,6 +5,7 @@
#include <QDate>
#include <QThread>
#include <QStringList>
+#include <QIcon>
#if 0
#include <QHostInfo> // available since Qt 4.7
#endif
@@ -14,7 +15,7 @@
#include <pwd.h> // for getpwuid
#include "globals.h"
#include "vsession.h"
-#include "httpxmldownloader.h"
+#include "sessionsiconholder.h"
bool VSession::init(const QString& xml, const QString& baseDirPath) {
this->baseDirPath_ = baseDirPath;
@@ -38,8 +39,63 @@ void VSession::addNodeWithAttribute(const QString& nodeName,
node.setAttribute(attribute, value);
}
-QString VSession::icon() const {
- return getAttribute("icon");
+QIcon VSession::icon() const {
+ QString icon(getAttribute("icon"));
+ SessionsIconHolder *iconHolder = SessionsIconHolder::get();
+ if (icon.startsWith("http://")) {
+ // try to load icon from url
+ QIcon url_icon(iconHolder->getIcon(QUrl(icon)));
+ if (!url_icon.isNull()) {
+ return url_icon;
+ }
+ } else if (QFileInfo(icon).isAbsolute()) {
+ // try to load icon from file
+ QIcon file_icon(icon);
+ if (!file_icon.isNull()) {
+ return file_icon;
+ }
+ }
+ if (!icon.isEmpty()) {
+ QIcon res_icon(iconHolder->getIcon(icon));
+ if (!res_icon.isNull()) {
+ return res_icon;
+ }
+ }
+ // Everything failed, try to guess the OS
+ QString os(getAttribute("os", "param").toLower());
+ if (!os.isEmpty()) {
+ QIcon osi = iconHolder->getIcon(os);
+ if (!osi.isNull())
+ return osi;
+ // These match vmware guestOS keywords mostly, extend for vbox...
+ if (os == "dos")
+ return iconHolder->getIcon("dos");
+ if (os.startsWith("windows7"))
+ return iconHolder->getIcon("win7");
+ if (os.startsWith("win31"))
+ return iconHolder->getIcon("win311");
+ if (os.startsWith("windows8"))
+ return iconHolder->getIcon("win8");
+ if (os.startsWith("win2000"))
+ return iconHolder->getIcon("win2000");
+ if (os.startsWith("winxp"))
+ return iconHolder->getIcon("winxp");
+ if (os.startsWith("debian"))
+ return iconHolder->getIcon("debian");
+ if (os.startsWith("ubuntu"))
+ return iconHolder->getIcon("ubuntu");
+ if (os.startsWith("win"))
+ return iconHolder->getIcon("windows");
+ if (os.contains("linux"))
+ return iconHolder->getIcon("linux");
+ }
+ // TODO: Maybe parse title of entry for an OS guess?
+ // Fallback to generic virtualizer icon
+ if (imgtype() == VMWARE)
+ return iconHolder->getIcon("vmware");
+ if (imgtype() == VBOX)
+ return iconHolder->getIcon("virtualbox");
+ return QIcon();
}
QString VSession::toXml() const {
diff --git a/src/vsession.h b/src/vsession.h
index ea04e4e..e542818 100644
--- a/src/vsession.h
+++ b/src/vsession.h
@@ -33,7 +33,7 @@ class VSession : public Session {
return getAttribute("description");
}
- QString icon() const;
+ QIcon icon() const;
QString os() const {
return getAttribute("os");
diff --git a/src/xsession.cpp b/src/xsession.cpp
index 3cd0e7e..3ae4320 100644
--- a/src/xsession.cpp
+++ b/src/xsession.cpp
@@ -5,6 +5,7 @@
#include <QProcess>
#include "xsession.h"
+#include "sessionsiconholder.h"
void XSession::init(const QString& name, const QString& exec,
const QString& comment, const QString& icon) {
@@ -86,7 +87,7 @@ int XSession::priority() const {
return 0;
}
-QString XSession::icon() const {
+QIcon XSession::icon() const {
QString icon(this->icon_);
if (icon.isEmpty()) {
@@ -105,7 +106,7 @@ QString XSession::icon() const {
}
}
- return icon;
+ return SessionsIconHolder::get()->getIcon(icon);
}
bool XSession::run() const {
diff --git a/src/xsession.h b/src/xsession.h
index 4140c38..75deffc 100644
--- a/src/xsession.h
+++ b/src/xsession.h
@@ -27,7 +27,7 @@ class XSession : public Session {
return this->comment_;
}
- QString icon() const;
+ QIcon icon() const;
bool run() const;