diff options
| author | Petr Mrázek <peterix@gmail.com> | 2013-08-10 18:34:08 +0200 |
|---|---|---|
| committer | Petr Mrázek <peterix@gmail.com> | 2013-08-11 01:07:15 +0200 |
| commit | 1782d5ad9a646ca2a6fab90da5f04c879ddaecd4 (patch) | |
| tree | 9537ecd66dad2fbcb083da2ed07191727a8e10ef | |
| parent | bf5f5091ef6daeaf7067f4fc8973eb068ddc52fc (diff) | |
| download | PrismLauncher-1782d5ad9a646ca2a6fab90da5f04c879ddaecd4.tar.gz PrismLauncher-1782d5ad9a646ca2a6fab90da5f04c879ddaecd4.tar.bz2 PrismLauncher-1782d5ad9a646ca2a6fab90da5f04c879ddaecd4.zip | |
Implement icon picker, bring back raster icons.
75 files changed, 1097 insertions, 423 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index e858d888..d907e152 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -176,8 +176,8 @@ gui/instancemodel.h gui/instancedelegate.h gui/versionselectdialog.h gui/lwjglselectdialog.h -gui/iconcache.h gui/instancesettings.h +gui/IconPickerDialog.h java/annotations.h java/classfile.h @@ -209,8 +209,8 @@ gui/instancemodel.cpp gui/instancedelegate.cpp gui/versionselectdialog.cpp gui/lwjglselectdialog.cpp -gui/iconcache.cpp gui/instancesettings.cpp +gui/IconPickerDialog.cpp java/javautils.cpp java/annotations.cpp @@ -232,6 +232,7 @@ gui/consolewindow.ui gui/versionselectdialog.ui gui/lwjglselectdialog.ui gui/instancesettings.ui +gui/IconPickerDialog.ui ) @@ -284,15 +285,6 @@ IF(BUILD_KEYRING_TEST) TARGET_LINK_LIBRARIES(Test libUtil libSettings) ENDIF() -option(BUILD_ASSET_TEST "Build the asset sync test binary" OFF) -IF(BUILD_ASSET_TEST) - # test.cpp - ADD_EXECUTABLE(AssetTest asset_test.cpp) - QT5_USE_MODULES(AssetTest Core Network) - TARGET_LINK_LIBRARIES(AssetTest libUtil backend libSettings) -ENDIF() - - ################################ INSTALLATION AND PACKAGING ################################ # use QtCreator's QTDIR var IF(DEFINED ENV{QTDIR}) diff --git a/asset_test.cpp b/asset_test.cpp deleted file mode 100644 index 90da314f..00000000 --- a/asset_test.cpp +++ /dev/null @@ -1,170 +0,0 @@ -#include <QString> -#include <QDebug> -#include <QtXml/QtXml> - -#include "dlqueue.h" - -inline QDomElement getDomElementByTagName(QDomElement parent, QString tagname) -{ - QDomNodeList elementList = parent.elementsByTagName(tagname); - if (elementList.count()) - return elementList.at(0).toElement(); - else - return QDomElement(); -} - -class ThreadedDeleter : public QThread -{ - Q_OBJECT -public: - void run() - { - QDirIterator iter(m_base, QDirIterator::Subdirectories); - QStringList nuke_list; - int base_length = m_base.length(); - while (iter.hasNext()) - { - QString filename = iter.next(); - QFileInfo current(filename); - // we keep the dirs... whatever - if(current.isDir()) - continue; - QString trimmedf = filename; - trimmedf.remove(0, base_length + 1); - if(m_whitelist.contains(trimmedf)) - { - //qDebug() << trimmedf << " gets to live"; - } - else - { - // DO NOT TOLERATE JUNK - //qDebug() << trimmedf << " dies"; - QFile f (filename); - f.remove(); - } - } - }; - QString m_base; - QStringList m_whitelist; -}; - -class NukeAndPaveJob: public Job -{ - Q_OBJECT -public: - - explicit NukeAndPaveJob(QString base, QStringList whitelist) - :Job() - { - QDir dir(base); - deleterThread.m_base = dir.absolutePath(); - deleterThread.m_whitelist = whitelist; - }; -public slots: - virtual void start() - { - connect(&deleterThread, SIGNAL(finished()), SLOT(threadFinished())); - deleterThread.start(); - }; - void threadFinished() - { - emit finish(); - } -private: - ThreadedDeleter deleterThread; -}; - -class DlMachine : public QObject -{ - Q_OBJECT -public slots: - void filesFinished() - { - qApp->quit(); - } - - void fetchFinished() - { - QString prefix("http://s3.amazonaws.com/Minecraft.Resources/"); - QString fprefix("assets/"); - QStringList nuke_whitelist; - - JobPtr firstJob = index_job->getFirstJob(); - auto DlJob = firstJob.dynamicCast<DownloadJob>(); - QByteArray ba = DlJob->m_data; - - QString xmlErrorMsg; - QDomDocument doc; - if (!doc.setContent(ba, false, &xmlErrorMsg)) - { - qDebug() << "Failed to process s3.amazonaws.com/Minecraft.Resources. XML error:" << - xmlErrorMsg << ba; - } - //QRegExp etag_match(".*([a-f0-9]{32}).*"); - QDomNodeList contents = doc.elementsByTagName("Contents"); - - JobList *job = new JobList(); - connect(job, SIGNAL(finished()), SLOT(filesFinished())); - - for (int i = 0; i < contents.length(); i++) - { - QDomElement element = contents.at(i).toElement(); - - if (element.isNull()) - continue; - - QDomElement keyElement = getDomElementByTagName(element, "Key"); - QDomElement lastmodElement = getDomElementByTagName(element, "LastModified"); - QDomElement etagElement = getDomElementByTagName(element, "ETag"); - QDomElement sizeElement = getDomElementByTagName(element, "Size"); - - if (keyElement.isNull() || lastmodElement.isNull() || etagElement.isNull() || sizeElement.isNull()) - continue; - - QString keyStr = keyElement.text(); - QString lastModStr = lastmodElement.text(); - QString etagStr = etagElement.text(); - QString sizeStr = sizeElement.text(); - - //Filter folder keys - if (sizeStr == "0") - continue; - - QString trimmedEtag = etagStr.remove('"'); - job->add(DownloadJob::create(QUrl(prefix + keyStr),fprefix + keyStr, trimmedEtag)); - nuke_whitelist.append(keyStr); - } - job->add(JobPtr(new NukeAndPaveJob(fprefix, nuke_whitelist))); - files_job.reset(job); - dl.enqueue(files_job); - } - void fetchStarted() - { - qDebug() << "Started downloading!"; - } -public: - void start() - { - JobList *job = new JobList(); - job->add(DownloadJob::create(QUrl("http://s3.amazonaws.com/Minecraft.Resources/"))); - connect(job, SIGNAL(finished()), SLOT(fetchFinished())); - connect(job, SIGNAL(started()), SLOT(fetchStarted())); - index_job.reset(job); - dl.enqueue(index_job); - } - JobListQueue dl; - JobListPtr index_job; - JobListPtr files_job; -}; - -int main(int argc, char *argv[]) -{ - QCoreApplication app(argc, argv); - - DlMachine dl; - dl.start(); - - return app.exec(); -} - -#include "asset_test.moc" diff --git a/backend/CMakeLists.txt b/backend/CMakeLists.txt index ea19fbbf..0d0df5e5 100644 --- a/backend/CMakeLists.txt +++ b/backend/CMakeLists.txt @@ -52,6 +52,7 @@ lists/InstanceList.h lists/InstVersionList.h lists/MinecraftVersionList.h lists/LwjglVersionList.h +IconListModel.h # Tasks tasks/Task.h @@ -87,6 +88,7 @@ lists/InstanceList.cpp lists/InstVersionList.cpp lists/MinecraftVersionList.cpp lists/LwjglVersionList.cpp +IconListModel.cpp # Tasks tasks/Task.cpp diff --git a/backend/IconListModel.cpp b/backend/IconListModel.cpp new file mode 100644 index 00000000..2d2fb6cf --- /dev/null +++ b/backend/IconListModel.cpp @@ -0,0 +1,163 @@ +#include "IconListModel.h" +#include <pathutils.h> +#include <QMap> +#include <QEventLoop> +#include <QDir> + +#define MAX_SIZE 1024 +IconList* IconList::m_Instance = 0; +QMutex IconList::mutex; + +struct entry +{ + QString key; + QString name; + QIcon icon; + bool is_builtin; +}; + +class Private : public QObject +{ + Q_OBJECT +public: + QMap<QString, int> index; + QVector<entry> icons; + Private() + { + } +}; + + +IconList::IconList() : QAbstractListModel(), d(new Private()) +{ + QDir instance_icons(":/icons/instances/"); + auto file_info_list = instance_icons.entryInfoList(QDir::Files, QDir::Name); + for(auto file_info: file_info_list) + { + QString key = file_info.baseName(); + addIcon(key, key, file_info.absoluteFilePath(), true); + } + + // FIXME: get from settings + ensurePathExists("icons/"); + QDir user_icons("icons/"); + file_info_list = user_icons.entryInfoList(QDir::Files, QDir::Name); + for(auto file_info: file_info_list) + { + QString filename = file_info.absoluteFilePath(); + QString key = file_info.baseName(); + addIcon(key, key, filename); + } +} + +IconList::~IconList() +{ + delete d; + d = nullptr; +} + +QVariant IconList::data ( const QModelIndex& index, int role ) const +{ + if(!index.isValid()) + return QVariant(); + + int row = index.row(); + + if(row < 0 || row >= d->icons.size()) + return QVariant(); + + switch(role) + { + case Qt::DecorationRole: + return d->icons[row].icon; + case Qt::DisplayRole: + return d->icons[row].name; + case Qt::UserRole: + return d->icons[row].key; + default: + return QVariant(); + } +} + +int IconList::rowCount ( const QModelIndex& parent ) const +{ + return d->icons.size(); +} + +bool IconList::addIcon ( QString key, QString name, QString path, bool is_builtin ) +{ + auto iter = d->index.find(key); + if(iter != d->index.end()) + { + if(d->icons[*iter].is_builtin) return false; + + QIcon icon(path); + if(icon.isNull()) return false; + + // replace the icon + d->icons[*iter] = {key, name, icon, is_builtin}; + return true; + } + else + { + QIcon icon(path); + if(icon.isNull()) return false; + + // add a new icon + d->icons.push_back({key, name, icon, is_builtin}); + d->index[key] = d->icons.size() - 1; + return true; + } +} + + +QIcon IconList::getIcon ( QString key ) +{ + int icon_index = getIconIndex(key); + + if(icon_index != -1) + return d->icons[icon_index].icon; + + // Fallback for icons that don't exist. + icon_index = getIconIndex("infinity"); + + if(icon_index != -1) + return d->icons[icon_index].icon; + return QIcon(); +} + +int IconList::getIconIndex ( QString key ) +{ + if(key == "default") + key = "infinity"; + + auto iter = d->index.find(key); + if(iter != d->index.end()) + return *iter; + + + return -1; +} + + +void IconList::drop() +{ + mutex.lock(); + delete m_Instance; + m_Instance = 0; + mutex.unlock(); +} + +IconList* IconList::instance() +{ + if ( !m_Instance ) + { + mutex.lock(); + if ( !m_Instance ) + m_Instance = new IconList; + mutex.unlock(); + } + return m_Instance; +} + +#include "IconListModel.moc"
\ No newline at end of file diff --git a/backend/IconListModel.h b/backend/IconListModel.h new file mode 100644 index 00000000..31b05e64 --- /dev/null +++ b/backend/IconListModel.h @@ -0,0 +1,33 @@ +#pragma once + +#include <QMutex> +#include <QAbstractListModel> +#include <QtGui/QIcon> + +class Private; + +class IconList : public QAbstractListModel +{ +public: + static IconList* instance(); + static void drop(); + QIcon getIcon ( QString key ); + int getIconIndex ( QString key ); + + virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const; + virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const; + + bool addIcon(QString key, QString name, QString path, bool is_builtin = false); + + +private: + virtual ~IconList(); + IconList(); + // hide copy constructor + IconList ( const IconList & ) = delete; + // hide assign op + IconList& operator= ( const IconList & ) = delete; + static IconList* m_Instance; + static QMutex mutex; + Private* d; +}; diff --git a/gui/IconPickerDialog.cpp b/gui/IconPickerDialog.cpp new file mode 100644 index 00000000..27e7f3b6 --- /dev/null +++ b/gui/IconPickerDialog.cpp @@ -0,0 +1,88 @@ +#include "IconPickerDialog.h" +#include "instancedelegate.h" +#include "ui_IconPickerDialog.h" +#include <IconListModel.h> + +IconPickerDialog::IconPickerDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::IconPickerDialog) +{ + ui->setupUi(this); + auto contentsWidget = ui->iconView; + contentsWidget->setViewMode(QListView::IconMode); + contentsWidget->setFlow(QListView::LeftToRight); + contentsWidget->setIconSize(QSize(48, 48)); + contentsWidget->setMovement(QListView::Static); + contentsWidget->setResizeMode(QListView::Adjust); + contentsWidget->setSelectionMode(QAbstractItemView::SingleSelection); + contentsWidget->setSpacing(5); + contentsWidget->setWordWrap(false); + contentsWidget->setWrapping(true); + contentsWidget->setUniformItemSizes(true); + contentsWidget->setTextElideMode(Qt::ElideRight); + contentsWidget->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + contentsWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + contentsWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + contentsWidget->setItemDelegate(new ListViewDelegate()); + + IconList * list = IconList::instance(); + contentsWidget->setModel(list); + + connect + ( + contentsWidget, + SIGNAL(doubleClicked(QModelIndex)), + SLOT(activated(QModelIndex)) + ); + + connect + ( + contentsWidget->selectionModel(), + SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + SLOT(selectionChanged(QItemSelection,QItemSelection)) + ); +} + +void IconPickerDialog::activated ( QModelIndex index ) +{ + selectedIconKey = index.data(Qt::UserRole).toString(); + accept(); +} + + +void IconPickerDialog::selectionChanged ( QItemSelection selected, QItemSelection deselected ) +{ + if(selected.empty()) + return; + + QString key = selected.first().indexes().first().data(Qt::UserRole).toString(); + if(!key.isEmpty()) + selectedIconKey = key; +} + +int IconPickerDialog::exec ( QString selection ) +{ + IconList * list = IconList::instance(); + auto contentsWidget = ui->iconView; + selectedIconKey = selection; + + + int index_nr = list->getIconIndex(selection); + auto model_index = list->index(index_nr); + contentsWidget->selectionModel()->select(model_index, QItemSelectionModel::Current | QItemSelectionModel::Select); + + QMetaObject::invokeMethod(this, "delayed_scroll", Qt::QueuedConnection, Q_ARG(QModelIndex,model_index)); + return QDialog::exec(); +} + +void IconPickerDialog::delayed_scroll ( QModelIndex model_index ) +{ + auto contentsWidget = ui->iconView; + contentsWidget->scrollTo(model_index); +} + + +IconPickerDialog::~IconPickerDialog() +{ + delete ui; +} diff --git a/gui/IconPickerDialog.h b/gui/IconPickerDialog.h new file mode 100644 index 00000000..c55f6ff2 --- /dev/null +++ b/gui/IconPickerDialog.h @@ -0,0 +1,26 @@ +#pragma once +#include <QDialog> +#include <QItemSelection> + +namespace Ui { +class IconPickerDialog; +} + +class IconPickerDialog : public QDialog +{ + Q_OBJECT + +public: + explicit IconPickerDialog(QWidget *parent = 0); + ~IconPickerDialog(); + int exec(QString selection); + QString selectedIconKey; + +private: + Ui::IconPickerDialog *ui; + +private slots: + void selectionChanged ( QItemSelection,QItemSelection ); + void activated ( QModelIndex ); + void delayed_scroll ( QModelIndex ); +}; diff --git a/gui/IconPickerDialog.ui b/gui/IconPickerDialog.ui new file mode 100644 index 00000000..c548edfb --- /dev/null +++ b/gui/IconPickerDialog.ui @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>IconPickerDialog</class> + <widget class="QDialog" name="IconPickerDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>676</width> + <height>555</height> + </rect> + </property> + <property name="windowTitle"> + <string>Pick icon</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QListView" name="iconView"/> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>IconPickerDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>IconPickerDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/gui/iconcache.cpp b/gui/iconcache.cpp deleted file mode 100644 index 520a7839..00000000 --- a/gui/iconcache.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include "iconcache.h" -#include <QMap> -#include <QWebView> -#include <QWebFrame> -#include <QEventLoop> -#include <QWebElement> - -IconCache* IconCache::m_Instance = 0; -QMutex IconCache::mutex; -#define MAX_SIZE 1024 - -class Private : public QWebView -{ - Q_OBJECT - -public: - QString name; - QSize si |
