NOISSUE tabs -> spaces
This commit is contained in:
@ -27,113 +27,113 @@
|
||||
// This is a hack, but I can't think of a better way to do this easily without screwing with QTextDocument...
|
||||
static QString getCreditsHtml(QStringList patrons)
|
||||
{
|
||||
QString creditsHtml = QObject::tr(
|
||||
"<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.0//EN' 'http://www.w3.org/TR/REC-html40/strict.dtd'>"
|
||||
"<html>"
|
||||
""
|
||||
"<head>"
|
||||
"<meta name='qrichtext' content='1' />"
|
||||
"<style type='text/css'>"
|
||||
"p { white-space: pre-wrap; margin-top:2px; margin-bottom:2px; }"
|
||||
"</style>"
|
||||
"</head>"
|
||||
""
|
||||
"<body style=' font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;'>"
|
||||
""
|
||||
"<h3>MultiMC Developers</h3>"
|
||||
"<p>Andrew Okin <<a href='mailto:forkk@forkk.net'>forkk@forkk.net</a>></p>"
|
||||
"<p>Petr Mrázek <<a href='mailto:peterix@gmail.com'>peterix@gmail.com</a>></p>"
|
||||
"<p>Sky Welch <<a href='mailto:multimc@bunnies.io'>multimc@bunnies.io</a>></p>"
|
||||
"<p>Jan (02JanDal) <<a href='mailto:02jandal@gmail.com'>02jandal@gmail.com</a>></p>"
|
||||
"<p>RoboSky <<a href='https://twitter.com/RoboSky_'>@RoboSky_</a>></p>"
|
||||
""
|
||||
"<h3>With thanks to</h3>"
|
||||
"<p>Orochimarufan <<a href='mailto:orochimarufan.x3@gmail.com'>orochimarufan.x3@gmail.com</a>></p>"
|
||||
"<p>TakSuyu <<a href='mailto:taksuyu@gmail.com'>taksuyu@gmail.com</a>></p>"
|
||||
"<p>Kilobyte <<a href='mailto:stiepen22@gmx.de'>stiepen22@gmx.de</a>></p>"
|
||||
"<p>Rootbear75 <<a href='https://twitter.com/rootbear75'>@rootbear75</a>></p>"
|
||||
""
|
||||
"<h3>Patrons</h3>"
|
||||
"%1"
|
||||
""
|
||||
"</body>"
|
||||
"</html>");
|
||||
if (patrons.isEmpty())
|
||||
return creditsHtml.arg(QObject::tr("<p>Loading...</p>"));
|
||||
else
|
||||
{
|
||||
QString patronsStr;
|
||||
for (QString patron : patrons)
|
||||
{
|
||||
patronsStr.append(QString("<p>%1</p>").arg(patron));
|
||||
}
|
||||
QString creditsHtml = QObject::tr(
|
||||
"<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.0//EN' 'http://www.w3.org/TR/REC-html40/strict.dtd'>"
|
||||
"<html>"
|
||||
""
|
||||
"<head>"
|
||||
"<meta name='qrichtext' content='1' />"
|
||||
"<style type='text/css'>"
|
||||
"p { white-space: pre-wrap; margin-top:2px; margin-bottom:2px; }"
|
||||
"</style>"
|
||||
"</head>"
|
||||
""
|
||||
"<body style=' font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;'>"
|
||||
""
|
||||
"<h3>MultiMC Developers</h3>"
|
||||
"<p>Andrew Okin <<a href='mailto:forkk@forkk.net'>forkk@forkk.net</a>></p>"
|
||||
"<p>Petr Mrázek <<a href='mailto:peterix@gmail.com'>peterix@gmail.com</a>></p>"
|
||||
"<p>Sky Welch <<a href='mailto:multimc@bunnies.io'>multimc@bunnies.io</a>></p>"
|
||||
"<p>Jan (02JanDal) <<a href='mailto:02jandal@gmail.com'>02jandal@gmail.com</a>></p>"
|
||||
"<p>RoboSky <<a href='https://twitter.com/RoboSky_'>@RoboSky_</a>></p>"
|
||||
""
|
||||
"<h3>With thanks to</h3>"
|
||||
"<p>Orochimarufan <<a href='mailto:orochimarufan.x3@gmail.com'>orochimarufan.x3@gmail.com</a>></p>"
|
||||
"<p>TakSuyu <<a href='mailto:taksuyu@gmail.com'>taksuyu@gmail.com</a>></p>"
|
||||
"<p>Kilobyte <<a href='mailto:stiepen22@gmx.de'>stiepen22@gmx.de</a>></p>"
|
||||
"<p>Rootbear75 <<a href='https://twitter.com/rootbear75'>@rootbear75</a>></p>"
|
||||
""
|
||||
"<h3>Patrons</h3>"
|
||||
"%1"
|
||||
""
|
||||
"</body>"
|
||||
"</html>");
|
||||
if (patrons.isEmpty())
|
||||
return creditsHtml.arg(QObject::tr("<p>Loading...</p>"));
|
||||
else
|
||||
{
|
||||
QString patronsStr;
|
||||
for (QString patron : patrons)
|
||||
{
|
||||
patronsStr.append(QString("<p>%1</p>").arg(patron));
|
||||
}
|
||||
|
||||
return creditsHtml.arg(patronsStr);
|
||||
}
|
||||
return creditsHtml.arg(patronsStr);
|
||||
}
|
||||
}
|
||||
|
||||
static QString getLicenseHtml()
|
||||
{
|
||||
HoeDown hoedown;
|
||||
QFile dataFile(":/documents/COPYING.md");
|
||||
dataFile.open(QIODevice::ReadOnly);
|
||||
QString output = hoedown.process(dataFile.readAll());
|
||||
return output;
|
||||
HoeDown hoedown;
|
||||
QFile dataFile(":/documents/COPYING.md");
|
||||
dataFile.open(QIODevice::ReadOnly);
|
||||
QString output = hoedown.process(dataFile.readAll());
|
||||
return output;
|
||||
}
|
||||
|
||||
AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent), ui(new Ui::AboutDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->setupUi(this);
|
||||
|
||||
QString chtml = getCreditsHtml(QStringList());
|
||||
ui->creditsText->setHtml(chtml);
|
||||
QString chtml = getCreditsHtml(QStringList());
|
||||
ui->creditsText->setHtml(chtml);
|
||||
|
||||
QString lhtml = getLicenseHtml();
|
||||
ui->licenseText->setHtml(lhtml);
|
||||
QString lhtml = getLicenseHtml();
|
||||
ui->licenseText->setHtml(lhtml);
|
||||
|
||||
ui->urlLabel->setOpenExternalLinks(true);
|
||||
ui->urlLabel->setOpenExternalLinks(true);
|
||||
|
||||
ui->icon->setPixmap(MMC->getThemedIcon("logo").pixmap(64));
|
||||
ui->title->setText("MultiMC 5");
|
||||
ui->icon->setPixmap(MMC->getThemedIcon("logo").pixmap(64));
|
||||
ui->title->setText("MultiMC 5");
|
||||
|
||||
ui->versionLabel->setText(tr("Version") +": " + BuildConfig.printableVersionString());
|
||||
ui->platformLabel->setText(tr("Platform") +": " + BuildConfig.BUILD_PLATFORM);
|
||||
ui->versionLabel->setText(tr("Version") +": " + BuildConfig.printableVersionString());
|
||||
ui->platformLabel->setText(tr("Platform") +": " + BuildConfig.BUILD_PLATFORM);
|
||||
|
||||
if (BuildConfig.VERSION_BUILD >= 0)
|
||||
ui->buildNumLabel->setText(tr("Build Number") +": " + QString::number(BuildConfig.VERSION_BUILD));
|
||||
else
|
||||
ui->buildNumLabel->setVisible(false);
|
||||
if (BuildConfig.VERSION_BUILD >= 0)
|
||||
ui->buildNumLabel->setText(tr("Build Number") +": " + QString::number(BuildConfig.VERSION_BUILD));
|
||||
else
|
||||
ui->buildNumLabel->setVisible(false);
|
||||
|
||||
if (!BuildConfig.VERSION_CHANNEL.isEmpty())
|
||||
ui->channelLabel->setText(tr("Channel") +": " + BuildConfig.VERSION_CHANNEL);
|
||||
else
|
||||
ui->channelLabel->setVisible(false);
|
||||
if (!BuildConfig.VERSION_CHANNEL.isEmpty())
|
||||
ui->channelLabel->setText(tr("Channel") +": " + BuildConfig.VERSION_CHANNEL);
|
||||
else
|
||||
ui->channelLabel->setVisible(false);
|
||||
|
||||
connect(ui->closeButton, SIGNAL(clicked()), SLOT(close()));
|
||||
connect(ui->closeButton, SIGNAL(clicked()), SLOT(close()));
|
||||
|
||||
connect(ui->aboutQt, &QPushButton::clicked, &QApplication::aboutQt);
|
||||
connect(ui->aboutQt, &QPushButton::clicked, &QApplication::aboutQt);
|
||||
|
||||
loadPatronList();
|
||||
loadPatronList();
|
||||
}
|
||||
|
||||
AboutDialog::~AboutDialog()
|
||||
{
|
||||
delete ui;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void AboutDialog::loadPatronList()
|
||||
{
|
||||
netJob.reset(new NetJob("Patreon Patron List"));
|
||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl("http://files.multimc.org/patrons.txt"), &dataSink));
|
||||
connect(netJob.get(), &NetJob::succeeded, this, &AboutDialog::patronListLoaded);
|
||||
netJob->start();
|
||||
netJob.reset(new NetJob("Patreon Patron List"));
|
||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl("http://files.multimc.org/patrons.txt"), &dataSink));
|
||||
connect(netJob.get(), &NetJob::succeeded, this, &AboutDialog::patronListLoaded);
|
||||
netJob->start();
|
||||
}
|
||||
|
||||
void AboutDialog::patronListLoaded()
|
||||
{
|
||||
QString patronListStr(dataSink);
|
||||
dataSink.clear();
|
||||
QString html = getCreditsHtml(patronListStr.split("\n", QString::SkipEmptyParts));
|
||||
ui->creditsText->setHtml(html);
|
||||
QString patronListStr(dataSink);
|
||||
dataSink.clear();
|
||||
QString html = getCreditsHtml(patronListStr.split("\n", QString::SkipEmptyParts));
|
||||
ui->creditsText->setHtml(html);
|
||||
}
|
||||
|
||||
|
@ -25,23 +25,23 @@ class AboutDialog;
|
||||
|
||||
class AboutDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AboutDialog(QWidget *parent = 0);
|
||||
~AboutDialog();
|
||||
explicit AboutDialog(QWidget *parent = 0);
|
||||
~AboutDialog();
|
||||
|
||||
public
|
||||
slots:
|
||||
/// Starts loading a list of Patreon patrons.
|
||||
void loadPatronList();
|
||||
|
||||
/// Slot for when the patron list loads successfully.
|
||||
void patronListLoaded();
|
||||
/// Starts loading a list of Patreon patrons.
|
||||
void loadPatronList();
|
||||
|
||||
/// Slot for when the patron list loads successfully.
|
||||
void patronListLoaded();
|
||||
|
||||
private:
|
||||
Ui::AboutDialog *ui;
|
||||
Ui::AboutDialog *ui;
|
||||
|
||||
NetJobPtr netJob;
|
||||
QByteArray dataSink;
|
||||
NetJobPtr netJob;
|
||||
QByteArray dataSink;
|
||||
};
|
||||
|
@ -29,87 +29,87 @@
|
||||
#include "InstanceList.h"
|
||||
|
||||
CopyInstanceDialog::CopyInstanceDialog(InstancePtr original, QWidget *parent)
|
||||
:QDialog(parent), ui(new Ui::CopyInstanceDialog), m_original(original)
|
||||
:QDialog(parent), ui(new Ui::CopyInstanceDialog), m_original(original)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
resize(minimumSizeHint());
|
||||
layout()->setSizeConstraint(QLayout::SetFixedSize);
|
||||
ui->setupUi(this);
|
||||
resize(minimumSizeHint());
|
||||
layout()->setSizeConstraint(QLayout::SetFixedSize);
|
||||
|
||||
InstIconKey = original->iconKey();
|
||||
ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
|
||||
ui->instNameTextBox->setText(original->name());
|
||||
ui->instNameTextBox->setFocus();
|
||||
auto groups = MMC->instances()->getGroups().toSet();
|
||||
auto groupList = QStringList(groups.toList());
|
||||
groupList.sort(Qt::CaseInsensitive);
|
||||
groupList.removeOne("");
|
||||
groupList.push_front("");
|
||||
ui->groupBox->addItems(groupList);
|
||||
int index = groupList.indexOf(m_original->group());
|
||||
if(index == -1)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
ui->groupBox->setCurrentIndex(index);
|
||||
ui->groupBox->lineEdit()->setPlaceholderText(tr("No group"));
|
||||
ui->copySavesCheckbox->setChecked(m_copySaves);
|
||||
InstIconKey = original->iconKey();
|
||||
ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
|
||||
ui->instNameTextBox->setText(original->name());
|
||||
ui->instNameTextBox->setFocus();
|
||||
auto groups = MMC->instances()->getGroups().toSet();
|
||||
auto groupList = QStringList(groups.toList());
|
||||
groupList.sort(Qt::CaseInsensitive);
|
||||
groupList.removeOne("");
|
||||
groupList.push_front("");
|
||||
ui->groupBox->addItems(groupList);
|
||||
int index = groupList.indexOf(m_original->group());
|
||||
if(index == -1)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
ui->groupBox->setCurrentIndex(index);
|
||||
ui->groupBox->lineEdit()->setPlaceholderText(tr("No group"));
|
||||
ui->copySavesCheckbox->setChecked(m_copySaves);
|
||||
}
|
||||
|
||||
CopyInstanceDialog::~CopyInstanceDialog()
|
||||
{
|
||||
delete ui;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void CopyInstanceDialog::updateDialogState()
|
||||
{
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!instName().isEmpty());
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!instName().isEmpty());
|
||||
}
|
||||
|
||||
QString CopyInstanceDialog::instName() const
|
||||
{
|
||||
return ui->instNameTextBox->text();
|
||||
return ui->instNameTextBox->text();
|
||||
}
|
||||
|
||||
QString CopyInstanceDialog::iconKey() const
|
||||
{
|
||||
return InstIconKey;
|
||||
return InstIconKey;
|
||||
}
|
||||
|
||||
QString CopyInstanceDialog::instGroup() const
|
||||
{
|
||||
return ui->groupBox->currentText();
|
||||
return ui->groupBox->currentText();
|
||||
}
|
||||
|
||||
void CopyInstanceDialog::on_iconButton_clicked()
|
||||
{
|
||||
IconPickerDialog dlg(this);
|
||||
dlg.execWithSelection(InstIconKey);
|
||||
IconPickerDialog dlg(this);
|
||||
dlg.execWithSelection(InstIconKey);
|
||||
|
||||
if (dlg.result() == QDialog::Accepted)
|
||||
{
|
||||
InstIconKey = dlg.selectedIconKey;
|
||||
ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
|
||||
}
|
||||
if (dlg.result() == QDialog::Accepted)
|
||||
{
|
||||
InstIconKey = dlg.selectedIconKey;
|
||||
ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
|
||||
}
|
||||
}
|
||||
|
||||
void CopyInstanceDialog::on_instNameTextBox_textChanged(const QString &arg1)
|
||||
{
|
||||
updateDialogState();
|
||||
updateDialogState();
|
||||
}
|
||||
|
||||
bool CopyInstanceDialog::shouldCopySaves() const
|
||||
{
|
||||
return m_copySaves;
|
||||
return m_copySaves;
|
||||
}
|
||||
|
||||
void CopyInstanceDialog::on_copySavesCheckbox_stateChanged(int state)
|
||||
{
|
||||
if(state == Qt::Unchecked)
|
||||
{
|
||||
m_copySaves = false;
|
||||
}
|
||||
else if(state == Qt::Checked)
|
||||
{
|
||||
m_copySaves = true;
|
||||
}
|
||||
if(state == Qt::Unchecked)
|
||||
{
|
||||
m_copySaves = false;
|
||||
}
|
||||
else if(state == Qt::Checked)
|
||||
{
|
||||
m_copySaves = true;
|
||||
}
|
||||
}
|
||||
|
@ -28,28 +28,28 @@ class CopyInstanceDialog;
|
||||
|
||||
class CopyInstanceDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CopyInstanceDialog(InstancePtr original, QWidget *parent = 0);
|
||||
~CopyInstanceDialog();
|
||||
explicit CopyInstanceDialog(InstancePtr original, QWidget *parent = 0);
|
||||
~CopyInstanceDialog();
|
||||
|
||||
void updateDialogState();
|
||||
void updateDialogState();
|
||||
|
||||
QString instName() const;
|
||||
QString instGroup() const;
|
||||
QString iconKey() const;
|
||||
bool shouldCopySaves() const;
|
||||
QString instName() const;
|
||||
QString instGroup() const;
|
||||
QString iconKey() const;
|
||||
bool shouldCopySaves() const;
|
||||
|
||||
private
|
||||
slots:
|
||||
void on_iconButton_clicked();
|
||||
void on_instNameTextBox_textChanged(const QString &arg1);
|
||||
void on_copySavesCheckbox_stateChanged(int state);
|
||||
void on_iconButton_clicked();
|
||||
void on_instNameTextBox_textChanged(const QString &arg1);
|
||||
void on_copySavesCheckbox_stateChanged(int state);
|
||||
|
||||
private:
|
||||
Ui::CopyInstanceDialog *ui;
|
||||
QString InstIconKey;
|
||||
InstancePtr m_original;
|
||||
bool m_copySaves = true;
|
||||
Ui::CopyInstanceDialog *ui;
|
||||
QString InstIconKey;
|
||||
InstancePtr m_original;
|
||||
bool m_copySaves = true;
|
||||
};
|
||||
|
@ -18,18 +18,18 @@
|
||||
namespace CustomMessageBox
|
||||
{
|
||||
QMessageBox *selectable(QWidget *parent, const QString &title, const QString &text,
|
||||
QMessageBox::Icon icon, QMessageBox::StandardButtons buttons,
|
||||
QMessageBox::StandardButton defaultButton)
|
||||
QMessageBox::Icon icon, QMessageBox::StandardButtons buttons,
|
||||
QMessageBox::StandardButton defaultButton)
|
||||
{
|
||||
QMessageBox *messageBox = new QMessageBox(parent);
|
||||
messageBox->setWindowTitle(title);
|
||||
messageBox->setText(text);
|
||||
messageBox->setStandardButtons(buttons);
|
||||
messageBox->setDefaultButton(defaultButton);
|
||||
messageBox->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||
messageBox->setIcon(icon);
|
||||
messageBox->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
QMessageBox *messageBox = new QMessageBox(parent);
|
||||
messageBox->setWindowTitle(title);
|
||||
messageBox->setText(text);
|
||||
messageBox->setStandardButtons(buttons);
|
||||
messageBox->setDefaultButton(defaultButton);
|
||||
messageBox->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||
messageBox->setIcon(icon);
|
||||
messageBox->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
|
||||
return messageBox;
|
||||
return messageBox;
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
namespace CustomMessageBox
|
||||
{
|
||||
QMessageBox *selectable(QWidget *parent, const QString &title, const QString &text,
|
||||
QMessageBox::Icon icon = QMessageBox::NoIcon,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
||||
QMessageBox::Icon icon = QMessageBox::NoIcon,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
||||
}
|
||||
|
@ -19,43 +19,43 @@
|
||||
#include <QUrl>
|
||||
|
||||
EditAccountDialog::EditAccountDialog(const QString &text, QWidget *parent, int flags)
|
||||
: QDialog(parent), ui(new Ui::EditAccountDialog)
|
||||
: QDialog(parent), ui(new Ui::EditAccountDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->label->setText(text);
|
||||
ui->label->setVisible(!text.isEmpty());
|
||||
ui->label->setText(text);
|
||||
ui->label->setVisible(!text.isEmpty());
|
||||
|
||||
ui->userTextBox->setEnabled(flags & UsernameField);
|
||||
ui->passTextBox->setEnabled(flags & PasswordField);
|
||||
ui->userTextBox->setEnabled(flags & UsernameField);
|
||||
ui->passTextBox->setEnabled(flags & PasswordField);
|
||||
}
|
||||
|
||||
EditAccountDialog::~EditAccountDialog()
|
||||
{
|
||||
delete ui;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void EditAccountDialog::on_label_linkActivated(const QString &link)
|
||||
{
|
||||
DesktopServices::openUrl(QUrl(link));
|
||||
DesktopServices::openUrl(QUrl(link));
|
||||
}
|
||||
|
||||
void EditAccountDialog::setUsername(const QString & user) const
|
||||
{
|
||||
ui->userTextBox->setText(user);
|
||||
ui->userTextBox->setText(user);
|
||||
}
|
||||
|
||||
QString EditAccountDialog::username() const
|
||||
{
|
||||
return ui->userTextBox->text();
|
||||
return ui->userTextBox->text();
|
||||
}
|
||||
|
||||
void EditAccountDialog::setPassword(const QString & pass) const
|
||||
{
|
||||
ui->passTextBox->setText(pass);
|
||||
ui->passTextBox->setText(pass);
|
||||
}
|
||||
|
||||
QString EditAccountDialog::password() const
|
||||
{
|
||||
return ui->passTextBox->text();
|
||||
return ui->passTextBox->text();
|
||||
}
|
||||
|
@ -24,33 +24,33 @@ class EditAccountDialog;
|
||||
|
||||
class EditAccountDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit EditAccountDialog(const QString &text = "", QWidget *parent = 0,
|
||||
int flags = UsernameField | PasswordField);
|
||||
~EditAccountDialog();
|
||||
explicit EditAccountDialog(const QString &text = "", QWidget *parent = 0,
|
||||
int flags = UsernameField | PasswordField);
|
||||
~EditAccountDialog();
|
||||
|
||||
void setUsername(const QString & user) const;
|
||||
void setPassword(const QString & pass) const;
|
||||
void setUsername(const QString & user) const;
|
||||
void setPassword(const QString & pass) const;
|
||||
|
||||
QString username() const;
|
||||
QString password() const;
|
||||
QString username() const;
|
||||
QString password() const;
|
||||
|
||||
enum Flags
|
||||
{
|
||||
NoFlags = 0,
|
||||
enum Flags
|
||||
{
|
||||
NoFlags = 0,
|
||||
|
||||
//! Specifies that the dialog should have a username field.
|
||||
UsernameField,
|
||||
//! Specifies that the dialog should have a username field.
|
||||
UsernameField,
|
||||
|
||||
//! Specifies that the dialog should have a password field.
|
||||
PasswordField,
|
||||
};
|
||||
//! Specifies that the dialog should have a password field.
|
||||
PasswordField,
|
||||
};
|
||||
|
||||
private slots:
|
||||
void on_label_linkActivated(const QString &link);
|
||||
|
||||
private:
|
||||
Ui::EditAccountDialog *ui;
|
||||
Ui::EditAccountDialog *ui;
|
||||
};
|
||||
|
@ -33,456 +33,456 @@
|
||||
|
||||
class PackIgnoreProxy : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PackIgnoreProxy(InstancePtr instance, QObject *parent) : QSortFilterProxyModel(parent)
|
||||
{
|
||||
m_instance = instance;
|
||||
}
|
||||
// NOTE: Sadly, we have to do sorting ourselves.
|
||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const
|
||||
{
|
||||
QFileSystemModel *fsm = qobject_cast<QFileSystemModel *>(sourceModel());
|
||||
if (!fsm)
|
||||
{
|
||||
return QSortFilterProxyModel::lessThan(left, right);
|
||||
}
|
||||
bool asc = sortOrder() == Qt::AscendingOrder ? true : false;
|
||||
PackIgnoreProxy(InstancePtr instance, QObject *parent) : QSortFilterProxyModel(parent)
|
||||
{
|
||||
m_instance = instance;
|
||||
}
|
||||
// NOTE: Sadly, we have to do sorting ourselves.
|
||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const
|
||||
{
|
||||
QFileSystemModel *fsm = qobject_cast<QFileSystemModel *>(sourceModel());
|
||||
if (!fsm)
|
||||
{
|
||||
return QSortFilterProxyModel::lessThan(left, right);
|
||||
}
|
||||
bool asc = sortOrder() == Qt::AscendingOrder ? true : false;
|
||||
|
||||
QFileInfo leftFileInfo = fsm->fileInfo(left);
|
||||
QFileInfo rightFileInfo = fsm->fileInfo(right);
|
||||
QFileInfo leftFileInfo = fsm->fileInfo(left);
|
||||
QFileInfo rightFileInfo = fsm->fileInfo(right);
|
||||
|
||||
if (!leftFileInfo.isDir() && rightFileInfo.isDir())
|
||||
{
|
||||
return !asc;
|
||||
}
|
||||
if (leftFileInfo.isDir() && !rightFileInfo.isDir())
|
||||
{
|
||||
return asc;
|
||||
}
|
||||
if (!leftFileInfo.isDir() && rightFileInfo.isDir())
|
||||
{
|
||||
return !asc;
|
||||
}
|
||||
if (leftFileInfo.isDir() && !rightFileInfo.isDir())
|
||||
{
|
||||
return asc;
|
||||
}
|
||||
|
||||
// sort and proxy model breaks the original model...
|
||||
if (sortColumn() == 0)
|
||||
{
|
||||
return Strings::naturalCompare(leftFileInfo.fileName(), rightFileInfo.fileName(),
|
||||
Qt::CaseInsensitive) < 0;
|
||||
}
|
||||
if (sortColumn() == 1)
|
||||
{
|
||||
auto leftSize = leftFileInfo.size();
|
||||
auto rightSize = rightFileInfo.size();
|
||||
if ((leftSize == rightSize) || (leftFileInfo.isDir() && rightFileInfo.isDir()))
|
||||
{
|
||||
return Strings::naturalCompare(leftFileInfo.fileName(),
|
||||
rightFileInfo.fileName(),
|
||||
Qt::CaseInsensitive) < 0
|
||||
? asc
|
||||
: !asc;
|
||||
}
|
||||
return leftSize < rightSize;
|
||||
}
|
||||
return QSortFilterProxyModel::lessThan(left, right);
|
||||
}
|
||||
// sort and proxy model breaks the original model...
|
||||
if (sortColumn() == 0)
|
||||
{
|
||||
return Strings::naturalCompare(leftFileInfo.fileName(), rightFileInfo.fileName(),
|
||||
Qt::CaseInsensitive) < 0;
|
||||
}
|
||||
if (sortColumn() == 1)
|
||||
{
|
||||
auto leftSize = leftFileInfo.size();
|
||||
auto rightSize = rightFileInfo.size();
|
||||
if ((leftSize == rightSize) || (leftFileInfo.isDir() && rightFileInfo.isDir()))
|
||||
{
|
||||
return Strings::naturalCompare(leftFileInfo.fileName(),
|
||||
rightFileInfo.fileName(),
|
||||
Qt::CaseInsensitive) < 0
|
||||
? asc
|
||||
: !asc;
|
||||
}
|
||||
return leftSize < rightSize;
|
||||
}
|
||||
return QSortFilterProxyModel::lessThan(left, right);
|
||||
}
|
||||
|
||||
virtual Qt::ItemFlags flags(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return Qt::NoItemFlags;
|
||||
virtual Qt::ItemFlags flags(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return Qt::NoItemFlags;
|
||||
|
||||
auto sourceIndex = mapToSource(index);
|
||||
Qt::ItemFlags flags = sourceIndex.flags();
|
||||
if (index.column() == 0)
|
||||
{
|
||||
flags |= Qt::ItemIsUserCheckable;
|
||||
if (sourceIndex.model()->hasChildren(sourceIndex))
|
||||
{
|
||||
flags |= Qt::ItemIsTristate;
|
||||
}
|
||||
}
|
||||
auto sourceIndex = mapToSource(index);
|
||||
Qt::ItemFlags flags = sourceIndex.flags();
|
||||
if (index.column() == 0)
|
||||
{
|
||||
flags |= Qt::ItemIsUserCheckable;
|
||||
if (sourceIndex.model()->hasChildren(sourceIndex))
|
||||
{
|
||||
flags |= Qt::ItemIsTristate;
|
||||
}
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
|
||||
{
|
||||
QModelIndex sourceIndex = mapToSource(index);
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
|
||||
{
|
||||
QModelIndex sourceIndex = mapToSource(index);
|
||||
|
||||
if (index.column() == 0 && role == Qt::CheckStateRole)
|
||||
{
|
||||
QFileSystemModel *fsm = qobject_cast<QFileSystemModel *>(sourceModel());
|
||||
auto blockedPath = relPath(fsm->filePath(sourceIndex));
|
||||
auto cover = blocked.cover(blockedPath);
|
||||
if (!cover.isNull())
|
||||
{
|
||||
return QVariant(Qt::Unchecked);
|
||||
}
|
||||
else if (blocked.exists(blockedPath))
|
||||
{
|
||||
return QVariant(Qt::PartiallyChecked);
|
||||
}
|
||||
else
|
||||
{
|
||||
return QVariant(Qt::Checked);
|
||||
}
|
||||
}
|
||||
if (index.column() == 0 && role == Qt::CheckStateRole)
|
||||
{
|
||||
QFileSystemModel *fsm = qobject_cast<QFileSystemModel *>(sourceModel());
|
||||
auto blockedPath = relPath(fsm->filePath(sourceIndex));
|
||||
auto cover = blocked.cover(blockedPath);
|
||||
if (!cover.isNull())
|
||||
{
|
||||
return QVariant(Qt::Unchecked);
|
||||
}
|
||||
else if (blocked.exists(blockedPath))
|
||||
{
|
||||
return QVariant(Qt::PartiallyChecked);
|
||||
}
|
||||
else
|
||||
{
|
||||
return QVariant(Qt::Checked);
|
||||
}
|
||||
}
|
||||
|
||||
return sourceIndex.data(role);
|
||||
}
|
||||
return sourceIndex.data(role);
|
||||
}
|
||||
|
||||
virtual bool setData(const QModelIndex &index, const QVariant &value,
|
||||
int role = Qt::EditRole)
|
||||
{
|
||||
if (index.column() == 0 && role == Qt::CheckStateRole)
|
||||
{
|
||||
Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
|
||||
return setFilterState(index, state);
|
||||
}
|
||||
virtual bool setData(const QModelIndex &index, const QVariant &value,
|
||||
int role = Qt::EditRole)
|
||||
{
|
||||
if (index.column() == 0 && role == Qt::CheckStateRole)
|
||||
{
|
||||
Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
|
||||
return setFilterState(index, state);
|
||||
}
|
||||
|
||||
QModelIndex sourceIndex = mapToSource(index);
|
||||
return QSortFilterProxyModel::sourceModel()->setData(sourceIndex, value, role);
|
||||
}
|
||||
QModelIndex sourceIndex = mapToSource(index);
|
||||
return QSortFilterProxyModel::sourceModel()->setData(sourceIndex, value, role);
|
||||
}
|
||||
|
||||
QString relPath(const QString &path) const
|
||||
{
|
||||
QString prefix = QDir().absoluteFilePath(m_instance->instanceRoot());
|
||||
prefix += '/';
|
||||
if (!path.startsWith(prefix))
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
return path.mid(prefix.size());
|
||||
}
|
||||
QString relPath(const QString &path) const
|
||||
{
|
||||
QString prefix = QDir().absoluteFilePath(m_instance->instanceRoot());
|
||||
prefix += '/';
|
||||
if (!path.startsWith(prefix))
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
return path.mid(prefix.size());
|
||||
}
|
||||
|
||||
bool setFilterState(QModelIndex index, Qt::CheckState state)
|
||||
{
|
||||
QFileSystemModel *fsm = qobject_cast<QFileSystemModel *>(sourceModel());
|
||||
bool setFilterState(QModelIndex index, Qt::CheckState state)
|
||||
{
|
||||
QFileSystemModel *fsm = qobject_cast<QFileSystemModel *>(sourceModel());
|
||||
|
||||
if (!fsm)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!fsm)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QModelIndex sourceIndex = mapToSource(index);
|
||||
auto blockedPath = relPath(fsm->filePath(sourceIndex));
|
||||
bool changed = false;
|
||||
if (state == Qt::Unchecked)
|
||||
{
|
||||
// blocking a path
|
||||
auto &node = blocked.insert(blockedPath);
|
||||
// get rid of all blocked nodes below
|
||||
node.clear();
|
||||
changed = true;
|
||||
}
|
||||
else if (state == Qt::Checked || state == Qt::PartiallyChecked)
|
||||
{
|
||||
if (!blocked.remove(blockedPath))
|
||||
{
|
||||
auto cover = blocked.cover(blockedPath);
|
||||
qDebug() << "Blocked by cover" << cover;
|
||||
// uncover
|
||||
blocked.remove(cover);
|
||||
// block all contents, except for any cover
|
||||
QModelIndex rootIndex =
|
||||
fsm->index(FS::PathCombine(m_instance->instanceRoot(), cover));
|
||||
QModelIndex doing = rootIndex;
|
||||
int row = 0;
|
||||
QStack<QModelIndex> todo;
|
||||
while (1)
|
||||
{
|
||||
auto node = doing.child(row, 0);
|
||||
if (!node.isValid())
|
||||
{
|
||||
if (!todo.size())
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
doing = todo.pop();
|
||||
row = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
auto relpath = relPath(fsm->filePath(node));
|
||||
if (blockedPath.startsWith(relpath)) // cover found?
|
||||
{
|
||||
// continue processing cover later
|
||||
todo.push(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
// or just block this one.
|
||||
blocked.insert(relpath);
|
||||
}
|
||||
row++;
|
||||
}
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
if (changed)
|
||||
{
|
||||
// update the thing
|
||||
emit dataChanged(index, index, {Qt::CheckStateRole});
|
||||
// update everything above index
|
||||
QModelIndex up = index.parent();
|
||||
while (1)
|
||||
{
|
||||
if (!up.isValid())
|
||||
break;
|
||||
emit dataChanged(up, up, {Qt::CheckStateRole});
|
||||
up = up.parent();
|
||||
}
|
||||
// and everything below the index
|
||||
QModelIndex doing = index;
|
||||
int row = 0;
|
||||
QStack<QModelIndex> todo;
|
||||
while (1)
|
||||
{
|
||||
auto node = doing.child(row, 0);
|
||||
if (!node.isValid())
|
||||
{
|
||||
if (!todo.size())
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
doing = todo.pop();
|
||||
row = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
emit dataChanged(node, node, {Qt::CheckStateRole});
|
||||
todo.push(node);
|
||||
row++;
|
||||
}
|
||||
// siblings and unrelated nodes are ignored
|
||||
}
|
||||
return true;
|
||||
}
|
||||
QModelIndex sourceIndex = mapToSource(index);
|
||||
auto blockedPath = relPath(fsm->filePath(sourceIndex));
|
||||
bool changed = false;
|
||||
if (state == Qt::Unchecked)
|
||||
{
|
||||
// blocking a path
|
||||
auto &node = blocked.insert(blockedPath);
|
||||
// get rid of all blocked nodes below
|
||||
node.clear();
|
||||
changed = true;
|
||||
}
|
||||
else if (state == Qt::Checked || state == Qt::PartiallyChecked)
|
||||
{
|
||||
if (!blocked.remove(blockedPath))
|
||||
{
|
||||
auto cover = blocked.cover(blockedPath);
|
||||
qDebug() << "Blocked by cover" << cover;
|
||||
// uncover
|
||||
blocked.remove(cover);
|
||||
// block all contents, except for any cover
|
||||
QModelIndex rootIndex =
|
||||
fsm->index(FS::PathCombine(m_instance->instanceRoot(), cover));
|
||||
QModelIndex doing = rootIndex;
|
||||
int row = 0;
|
||||
QStack<QModelIndex> todo;
|
||||
while (1)
|
||||
{
|
||||
auto node = doing.child(row, 0);
|
||||
if (!node.isValid())
|
||||
{
|
||||
if (!todo.size())
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
doing = todo.pop();
|
||||
row = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
auto relpath = relPath(fsm->filePath(node));
|
||||
if (blockedPath.startsWith(relpath)) // cover found?
|
||||
{
|
||||
// continue processing cover later
|
||||
todo.push(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
// or just block this one.
|
||||
blocked.insert(relpath);
|
||||
}
|
||||
row++;
|
||||
}
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
if (changed)
|
||||
{
|
||||
// update the thing
|
||||
emit dataChanged(index, index, {Qt::CheckStateRole});
|
||||
// update everything above index
|
||||
QModelIndex up = index.parent();
|
||||
while (1)
|
||||
{
|
||||
if (!up.isValid())
|
||||
break;
|
||||
emit dataChanged(up, up, {Qt::CheckStateRole});
|
||||
up = up.parent();
|
||||
}
|
||||
// and everything below the index
|
||||
QModelIndex doing = index;
|
||||
int row = 0;
|
||||
QStack<QModelIndex> todo;
|
||||
while (1)
|
||||
{
|
||||
auto node = doing.child(row, 0);
|
||||
if (!node.isValid())
|
||||
{
|
||||
if (!todo.size())
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
doing = todo.pop();
|
||||
row = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
emit dataChanged(node, node, {Qt::CheckStateRole});
|
||||
todo.push(node);
|
||||
row++;
|
||||
}
|
||||
// siblings and unrelated nodes are ignored
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool shouldExpand(QModelIndex index)
|
||||
{
|
||||
QModelIndex sourceIndex = mapToSource(index);
|
||||
QFileSystemModel *fsm = qobject_cast<QFileSystemModel *>(sourceModel());
|
||||
if (!fsm)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
auto blockedPath = relPath(fsm->filePath(sourceIndex));
|
||||
auto found = blocked.find(blockedPath);
|
||||
if(found)
|
||||
{
|
||||
return !found->leaf();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool shouldExpand(QModelIndex index)
|
||||
{
|
||||
QModelIndex sourceIndex = mapToSource(index);
|
||||
QFileSystemModel *fsm = qobject_cast<QFileSystemModel *>(sourceModel());
|
||||
if (!fsm)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
auto blockedPath = relPath(fsm->filePath(sourceIndex));
|
||||
auto found = blocked.find(blockedPath);
|
||||
if(found)
|
||||
{
|
||||
return !found->leaf();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void setBlockedPaths(QStringList paths)
|
||||
{
|
||||
beginResetModel();
|
||||
blocked.clear();
|
||||
blocked.insert(paths);
|
||||
endResetModel();
|
||||
}
|
||||
void setBlockedPaths(QStringList paths)
|
||||
{
|
||||
beginResetModel();
|
||||
blocked.clear();
|
||||
blocked.insert(paths);
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
const SeparatorPrefixTree<'/'> & blockedPaths() const
|
||||
{
|
||||
return blocked;
|
||||
}
|
||||
const SeparatorPrefixTree<'/'> & blockedPaths() const
|
||||
{
|
||||
return blocked;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const
|
||||
{
|
||||
Q_UNUSED(source_parent)
|
||||
bool filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const
|
||||
{
|
||||
Q_UNUSED(source_parent)
|
||||
|
||||
// adjust the columns you want to filter out here
|
||||
// return false for those that will be hidden
|
||||
if (source_column == 2 || source_column == 3)
|
||||
return false;
|
||||
// adjust the columns you want to filter out here
|
||||
// return false for those that will be hidden
|
||||
if (source_column == 2 || source_column == 3)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
InstancePtr m_instance;
|
||||
SeparatorPrefixTree<'/'> blocked;
|
||||
InstancePtr m_instance;
|
||||
SeparatorPrefixTree<'/'> blocked;
|
||||
};
|
||||
|
||||
ExportInstanceDialog::ExportInstanceDialog(InstancePtr instance, QWidget *parent)
|
||||
: QDialog(parent), ui(new Ui::ExportInstanceDialog), m_instance(instance)
|
||||
: QDialog(parent), ui(new Ui::ExportInstanceDialog), m_instance(instance)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
auto model = new QFileSystemModel(this);
|
||||
proxyModel = new PackIgnoreProxy(m_instance, this);
|
||||
loadPackIgnore();
|
||||
proxyModel->setSourceModel(model);
|
||||
auto root = instance->instanceRoot();
|
||||
ui->treeView->setModel(proxyModel);
|
||||
ui->treeView->setRootIndex(proxyModel->mapFromSource(model->index(root)));
|
||||
ui->treeView->sortByColumn(0, Qt::AscendingOrder);
|
||||
ui->setupUi(this);
|
||||
auto model = new QFileSystemModel(this);
|
||||
proxyModel = new PackIgnoreProxy(m_instance, this);
|
||||
loadPackIgnore();
|
||||
proxyModel->setSourceModel(model);
|
||||
auto root = instance->instanceRoot();
|
||||
ui->treeView->setModel(proxyModel);
|
||||
ui->treeView->setRootIndex(proxyModel->mapFromSource(model->index(root)));
|
||||
ui->treeView->sortByColumn(0, Qt::AscendingOrder);
|
||||
|
||||
connect(proxyModel, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(rowsInserted(QModelIndex,int,int)));
|
||||
connect(proxyModel, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(rowsInserted(QModelIndex,int,int)));
|
||||
|
||||
model->setFilter(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::AllDirs | QDir::Hidden);
|
||||
model->setRootPath(root);
|
||||
auto headerView = ui->treeView->header();
|
||||
headerView->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
headerView->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||
model->setFilter(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::AllDirs | QDir::Hidden);
|
||||
model->setRootPath(root);
|
||||
auto headerView = ui->treeView->header();
|
||||
headerView->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
headerView->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||
}
|
||||
|
||||
ExportInstanceDialog::~ExportInstanceDialog()
|
||||
{
|
||||
delete ui;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
/// Save icon to instance's folder is needed
|
||||
void SaveIcon(InstancePtr m_instance)
|
||||
{
|
||||
auto iconKey = m_instance->iconKey();
|
||||
auto iconList = MMC->icons();
|
||||
auto mmcIcon = iconList->icon(iconKey);
|
||||
if(mmcIcon)
|
||||
{
|
||||
bool saveIcon = false;
|
||||
switch(mmcIcon->type())
|
||||
{
|
||||
case IconType::FileBased:
|
||||
case IconType::Transient:
|
||||
saveIcon = true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(saveIcon)
|
||||
{
|
||||
auto & image = mmcIcon->m_images[mmcIcon->type()];
|
||||
auto & icon = image.icon;
|
||||
auto sizes = icon.availableSizes();
|
||||
if(sizes.size() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto areaOf = [](QSize size)
|
||||
{
|
||||
return size.width() * size.height();
|
||||
};
|
||||
QSize largest = sizes[0];
|
||||
// find variant with largest area
|
||||
for(auto size: sizes)
|
||||
{
|
||||
if(areaOf(largest) < areaOf(size))
|
||||
{
|
||||
largest = size;
|
||||
}
|
||||
}
|
||||
auto pixmap = icon.pixmap(largest);
|
||||
pixmap.save(FS::PathCombine(m_instance->instanceRoot(), iconKey + ".png"));
|
||||
}
|
||||
}
|
||||
auto iconKey = m_instance->iconKey();
|
||||
auto iconList = MMC->icons();
|
||||
auto mmcIcon = iconList->icon(iconKey);
|
||||
if(mmcIcon)
|
||||
{
|
||||
bool saveIcon = false;
|
||||
switch(mmcIcon->type())
|
||||
{
|
||||
case IconType::FileBased:
|
||||
case IconType::Transient:
|
||||
saveIcon = true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(saveIcon)
|
||||
{
|
||||
auto & image = mmcIcon->m_images[mmcIcon->type()];
|
||||
auto & icon = image.icon;
|
||||
auto sizes = icon.availableSizes();
|
||||
if(sizes.size() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto areaOf = [](QSize size)
|
||||
{
|
||||
return size.width() * size.height();
|
||||
};
|
||||
QSize largest = sizes[0];
|
||||
// find variant with largest area
|
||||
for(auto size: sizes)
|
||||
{
|
||||
if(areaOf(largest) < areaOf(size))
|
||||
{
|
||||
largest = size;
|
||||
}
|
||||
}
|
||||
auto pixmap = icon.pixmap(largest);
|
||||
pixmap.save(FS::PathCombine(m_instance->instanceRoot(), iconKey + ".png"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ExportInstanceDialog::doExport()
|
||||
{
|
||||
auto name = FS::RemoveInvalidFilenameChars(m_instance->name());
|
||||
auto name = FS::RemoveInvalidFilenameChars(m_instance->name());
|
||||
|
||||
const QString output = QFileDialog::getSaveFileName(
|
||||
this, tr("Export %1").arg(m_instance->name()),
|
||||
FS::PathCombine(QDir::homePath(), name + ".zip"), "Zip (*.zip)", nullptr, QFileDialog::DontConfirmOverwrite);
|
||||
if (output.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (QFile::exists(output))
|
||||
{
|
||||
int ret =
|
||||
QMessageBox::question(this, tr("Overwrite?"),
|
||||
tr("This file already exists. Do you want to overwrite it?"),
|
||||
QMessageBox::No, QMessageBox::Yes);
|
||||
if (ret == QMessageBox::No)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const QString output = QFileDialog::getSaveFileName(
|
||||
this, tr("Export %1").arg(m_instance->name()),
|
||||
FS::PathCombine(QDir::homePath(), name + ".zip"), "Zip (*.zip)", nullptr, QFileDialog::DontConfirmOverwrite);
|
||||
if (output.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (QFile::exists(output))
|
||||
{
|
||||
int ret =
|
||||
QMessageBox::question(this, tr("Overwrite?"),
|
||||
tr("This file already exists. Do you want to overwrite it?"),
|
||||
QMessageBox::No, QMessageBox::Yes);
|
||||
if (ret == QMessageBox::No)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SaveIcon(m_instance);
|
||||
SaveIcon(m_instance);
|
||||
|
||||
auto & blocked = proxyModel->blockedPaths();
|
||||
using std::placeholders::_1;
|
||||
if (!JlCompress::compressDir(output, m_instance->instanceRoot(), name, std::bind(&SeparatorPrefixTree<'/'>::covers, blocked, _1)))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Error"), tr("Unable to export instance"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
auto & blocked = proxyModel->blockedPaths();
|
||||
using std::placeholders::_1;
|
||||
if (!JlCompress::compressDir(output, m_instance->instanceRoot(), name, std::bind(&SeparatorPrefixTree<'/'>::covers, blocked, _1)))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Error"), tr("Unable to export instance"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExportInstanceDialog::done(int result)
|
||||
{
|
||||
savePackIgnore();
|
||||
if (result == QDialog::Accepted)
|
||||
{
|
||||
if (doExport())
|
||||
{
|
||||
QDialog::done(QDialog::Accepted);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
QDialog::done(result);
|
||||
savePackIgnore();
|
||||
if (result == QDialog::Accepted)
|
||||
{
|
||||
if (doExport())
|
||||
{
|
||||
QDialog::done(QDialog::Accepted);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
QDialog::done(result);
|
||||
}
|
||||
|
||||
void ExportInstanceDialog::rowsInserted(QModelIndex parent, int top, int bottom)
|
||||
{
|
||||
//WARNING: possible off-by-one?
|
||||
for(int i = top; i < bottom; i++)
|
||||
{
|
||||
auto node = parent.child(i, 0);
|
||||
if(proxyModel->shouldExpand(node))
|
||||
{
|
||||
auto expNode = node.parent();
|
||||
if(!expNode.isValid())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ui->treeView->expand(node);
|
||||
}
|
||||
}
|
||||
//WARNING: possible off-by-one?
|
||||
for(int i = top; i < bottom; i++)
|
||||
{
|
||||
auto node = parent.child(i, 0);
|
||||
if(proxyModel->shouldExpand(node))
|
||||
{
|
||||
auto expNode = node.parent();
|
||||
if(!expNode.isValid())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ui->treeView->expand(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString ExportInstanceDialog::ignoreFileName()
|
||||
{
|
||||
return FS::PathCombine(m_instance->instanceRoot(), ".packignore");
|
||||
return FS::PathCombine(m_instance->instanceRoot(), ".packignore");
|
||||
}
|
||||
|
||||
void ExportInstanceDialog::loadPackIgnore()
|
||||
{
|
||||
auto filename = ignoreFileName();
|
||||
QFile ignoreFile(filename);
|
||||
if(!ignoreFile.open(QIODevice::ReadOnly))
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto data = ignoreFile.readAll();
|
||||
auto string = QString::fromUtf8(data);
|
||||
proxyModel->setBlockedPaths(string.split('\n', QString::SkipEmptyParts));
|
||||
auto filename = ignoreFileName();
|
||||
QFile ignoreFile(filename);
|
||||
if(!ignoreFile.open(QIODevice::ReadOnly))
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto data = ignoreFile.readAll();
|
||||
auto string = QString::fromUtf8(data);
|
||||
proxyModel->setBlockedPaths(string.split('\n', QString::SkipEmptyParts));
|
||||
}
|
||||
|
||||
void ExportInstanceDialog::savePackIgnore()
|
||||
{
|
||||
auto data = proxyModel->blockedPaths().toStringList().join('\n').toUtf8();
|
||||
auto filename = ignoreFileName();
|
||||
try
|
||||
{
|
||||
FS::write(filename, data);
|
||||
}
|
||||
catch (const Exception &e)
|
||||
{
|
||||
qWarning() << e.cause();
|
||||
}
|
||||
auto data = proxyModel->blockedPaths().toStringList().join('\n').toUtf8();
|
||||
auto filename = ignoreFileName();
|
||||
try
|
||||
{
|
||||
FS::write(filename, data);
|
||||
}
|
||||
catch (const Exception &e)
|
||||
{
|
||||
qWarning() << e.cause();
|
||||
}
|
||||
}
|
||||
|
||||
#include "ExportInstanceDialog.moc"
|
||||
|
@ -30,25 +30,25 @@ class ExportInstanceDialog;
|
||||
|
||||
class ExportInstanceDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ExportInstanceDialog(InstancePtr instance, QWidget *parent = 0);
|
||||
~ExportInstanceDialog();
|
||||
explicit ExportInstanceDialog(InstancePtr instance, QWidget *parent = 0);
|
||||
~ExportInstanceDialog();
|
||||
|
||||
virtual void done(int result);
|
||||
virtual void done(int result);
|
||||
|
||||
private:
|
||||
bool doExport();
|
||||
void loadPackIgnore();
|
||||
void savePackIgnore();
|
||||
QString ignoreFileName();
|
||||
bool doExport();
|
||||
void loadPackIgnore();
|
||||
void savePackIgnore();
|
||||
QString ignoreFileName();
|
||||
|
||||
private:
|
||||
Ui::ExportInstanceDialog *ui;
|
||||
InstancePtr m_instance;
|
||||
PackIgnoreProxy * proxyModel;
|
||||
Ui::ExportInstanceDialog *ui;
|
||||
InstancePtr m_instance;
|
||||
PackIgnoreProxy * proxyModel;
|
||||
|
||||
private slots:
|
||||
void rowsInserted(QModelIndex parent, int top, int bottom);
|
||||
void rowsInserted(QModelIndex parent, int top, int bottom);
|
||||
};
|
||||
|
@ -28,135 +28,135 @@
|
||||
#include <DesktopServices.h>
|
||||
|
||||
IconPickerDialog::IconPickerDialog(QWidget *parent)
|
||||
: QDialog(parent), ui(new Ui::IconPickerDialog)
|
||||
: QDialog(parent), ui(new Ui::IconPickerDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowModality(Qt::WindowModal);
|
||||
ui->setupUi(this);
|
||||
setWindowModality(Qt::WindowModal);
|
||||
|
||||
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());
|
||||
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());
|
||||
|
||||
// contentsWidget->setAcceptDrops(true);
|
||||
contentsWidget->setDropIndicatorShown(true);
|
||||
contentsWidget->viewport()->setAcceptDrops(true);
|
||||
contentsWidget->setDragDropMode(QAbstractItemView::DropOnly);
|
||||
contentsWidget->setDefaultDropAction(Qt::CopyAction);
|
||||
// contentsWidget->setAcceptDrops(true);
|
||||
contentsWidget->setDropIndicatorShown(true);
|
||||
contentsWidget->viewport()->setAcceptDrops(true);
|
||||
contentsWidget->setDragDropMode(QAbstractItemView::DropOnly);
|
||||
contentsWidget->setDefaultDropAction(Qt::CopyAction);
|
||||
|
||||
contentsWidget->installEventFilter(this);
|
||||
contentsWidget->installEventFilter(this);
|
||||
|
||||
contentsWidget->setModel(MMC->icons().get());
|
||||
contentsWidget->setModel(MMC->icons().get());
|
||||
|
||||
// NOTE: ResetRole forces the button to be on the left, while the OK/Cancel ones are on the right. We win.
|
||||
auto buttonAdd = ui->buttonBox->addButton(tr("Add Icon"), QDialogButtonBox::ResetRole);
|
||||
auto buttonRemove = ui->buttonBox->addButton(tr("Remove Icon"), QDialogButtonBox::ResetRole);
|
||||
// NOTE: ResetRole forces the button to be on the left, while the OK/Cancel ones are on the right. We win.
|
||||
auto buttonAdd = ui->buttonBox->addButton(tr("Add Icon"), QDialogButtonBox::ResetRole);
|
||||
auto buttonRemove = ui->buttonBox->addButton(tr("Remove Icon"), QDialogButtonBox::ResetRole);
|
||||
|
||||
connect(buttonAdd, SIGNAL(clicked(bool)), SLOT(addNewIcon()));
|
||||
connect(buttonRemove, SIGNAL(clicked(bool)), SLOT(removeSelectedIcon()));
|
||||
connect(buttonAdd, SIGNAL(clicked(bool)), SLOT(addNewIcon()));
|
||||
connect(buttonRemove, SIGNAL(clicked(bool)), SLOT(removeSelectedIcon()));
|
||||
|
||||
connect(contentsWidget, SIGNAL(doubleClicked(QModelIndex)), SLOT(activated(QModelIndex)));
|
||||
connect(contentsWidget, SIGNAL(doubleClicked(QModelIndex)), SLOT(activated(QModelIndex)));
|
||||
|
||||
connect(contentsWidget->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), SLOT(selectionChanged(QItemSelection, QItemSelection)));
|
||||
connect(contentsWidget->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), SLOT(selectionChanged(QItemSelection, QItemSelection)));
|
||||
|
||||
auto buttonFolder = ui->buttonBox->addButton(tr("Open Folder"), QDialogButtonBox::ResetRole);
|
||||
connect(buttonFolder, &QPushButton::clicked, this, &IconPickerDialog::openFolder);
|
||||
auto buttonFolder = ui->buttonBox->addButton(tr("Open Folder"), QDialogButtonBox::ResetRole);
|
||||
connect(buttonFolder, &QPushButton::clicked, this, &IconPickerDialog::openFolder);
|
||||
}
|
||||
|
||||
bool IconPickerDialog::eventFilter(QObject *obj, QEvent *evt)
|
||||
{
|
||||
if (obj != ui->iconView)
|
||||
return QDialog::eventFilter(obj, evt);
|
||||
if (evt->type() != QEvent::KeyPress)
|
||||
{
|
||||
return QDialog::eventFilter(obj, evt);
|
||||
}
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(evt);
|
||||
switch (keyEvent->key())
|
||||
{
|
||||
case Qt::Key_Delete:
|
||||
removeSelectedIcon();
|
||||
return true;
|
||||
case Qt::Key_Plus:
|
||||
addNewIcon();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QDialog::eventFilter(obj, evt);
|
||||
if (obj != ui->iconView)
|
||||
return QDialog::eventFilter(obj, evt);
|
||||
if (evt->type() != QEvent::KeyPress)
|
||||
{
|
||||
return QDialog::eventFilter(obj, evt);
|
||||
}
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(evt);
|
||||
switch (keyEvent->key())
|
||||
{
|
||||
case Qt::Key_Delete:
|
||||
removeSelectedIcon();
|
||||
return true;
|
||||
case Qt::Key_Plus:
|
||||
addNewIcon();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QDialog::eventFilter(obj, evt);
|
||||
}
|
||||
|
||||
void IconPickerDialog::addNewIcon()
|
||||
{
|
||||
//: The title of the select icons open file dialog
|
||||
QString selectIcons = tr("Select Icons");
|
||||
//: The type of icon files
|
||||
QStringList fileNames = QFileDialog::getOpenFileNames(this, selectIcons, QString(),
|
||||
tr("Icons") + "(*.png *.jpg *.jpeg *.ico *.svg)");
|
||||
MMC->icons()->installIcons(fileNames);
|
||||
//: The title of the select icons open file dialog
|
||||
QString selectIcons = tr("Select Icons");
|
||||
//: The type of icon files
|
||||
QStringList fileNames = QFileDialog::getOpenFileNames(this, selectIcons, QString(),
|
||||
tr("Icons") + "(*.png *.jpg *.jpeg *.ico *.svg)");
|
||||
MMC->icons()->installIcons(fileNames);
|
||||
}
|
||||
|
||||
void IconPickerDialog::removeSelectedIcon()
|
||||
{
|
||||
MMC->icons()->deleteIcon(selectedIconKey);
|
||||
MMC->icons()->deleteIcon(selectedIconKey);
|
||||
}
|
||||
|
||||
void IconPickerDialog::activated(QModelIndex index)
|
||||
{
|
||||
selectedIconKey = index.data(Qt::UserRole).toString();
|
||||
accept();
|
||||
selectedIconKey = index.data(Qt::UserRole).toString();
|
||||
accept();
|
||||
}
|
||||
|
||||
void IconPickerDialog::selectionChanged(QItemSelection selected, QItemSelection deselected)
|
||||
{
|
||||
if (selected.empty())
|
||||
return;
|
||||
if (selected.empty())
|
||||
return;
|
||||
|
||||
QString key = selected.first().indexes().first().data(Qt::UserRole).toString();
|
||||
if (!key.isEmpty())
|
||||
selectedIconKey = key;
|
||||
QString key = selected.first().indexes().first().data(Qt::UserRole).toString();
|
||||
if (!key.isEmpty())
|
||||
selectedIconKey = key;
|
||||
}
|
||||
|
||||
int IconPickerDialog::execWithSelection(QString selection)
|
||||
{
|
||||
auto list = MMC->icons();
|
||||
auto contentsWidget = ui->iconView;
|
||||
selectedIconKey = selection;
|
||||
auto list = MMC->icons();
|
||||
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);
|
||||
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();
|
||||
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);
|
||||
auto contentsWidget = ui->iconView;
|
||||
contentsWidget->scrollTo(model_index);
|
||||
}
|
||||
|
||||
IconPickerDialog::~IconPickerDialog()
|
||||
{
|
||||
delete ui;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void IconPickerDialog::openFolder()
|
||||
{
|
||||
DesktopServices::openDirectory(MMC->icons()->getDirectory(), true);
|
||||
DesktopServices::openDirectory(MMC->icons()->getDirectory(), true);
|
||||
}
|
||||
|
@ -24,26 +24,26 @@ class IconPickerDialog;
|
||||
|
||||
class IconPickerDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit IconPickerDialog(QWidget *parent = 0);
|
||||
~IconPickerDialog();
|
||||
int execWithSelection(QString selection);
|
||||
QString selectedIconKey;
|
||||
explicit IconPickerDialog(QWidget *parent = 0);
|
||||
~IconPickerDialog();
|
||||
int execWithSelection(QString selection);
|
||||
QString selectedIconKey;
|
||||
|
||||
protected:
|
||||
virtual bool eventFilter(QObject *, QEvent *);
|
||||
virtual bool eventFilter(QObject *, QEvent *);
|
||||
|
||||
private:
|
||||
Ui::IconPickerDialog *ui;
|
||||
Ui::IconPickerDialog *ui;
|
||||
|
||||
private
|
||||
slots:
|
||||
void selectionChanged(QItemSelection, QItemSelection);
|
||||
void activated(QModelIndex);
|
||||
void delayed_scroll(QModelIndex);
|
||||
void addNewIcon();
|
||||
void removeSelectedIcon();
|
||||
void openFolder();
|
||||
void selectionChanged(QItemSelection, QItemSelection);
|
||||
void activated(QModelIndex);
|
||||
void delayed_scroll(QModelIndex);
|
||||
void addNewIcon();
|
||||
void removeSelectedIcon();
|
||||
void openFolder();
|
||||
};
|
||||
|
@ -22,89 +22,89 @@
|
||||
|
||||
LoginDialog::LoginDialog(QWidget *parent) : QDialog(parent), ui(new Ui::LoginDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->progressBar->setVisible(false);
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
|
||||
ui->setupUi(this);
|
||||
ui->progressBar->setVisible(false);
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
|
||||
|
||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
}
|
||||
|
||||
LoginDialog::~LoginDialog()
|
||||
{
|
||||
delete ui;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
// Stage 1: User interaction
|
||||
void LoginDialog::accept()
|
||||
{
|
||||
setUserInputsEnabled(false);
|
||||
ui->progressBar->setVisible(true);
|
||||
setUserInputsEnabled(false);
|
||||
ui->progressBar->setVisible(true);
|
||||
|
||||
// Setup the login task and start it
|
||||
m_account = MojangAccount::createFromUsername(ui->userTextBox->text());
|
||||
m_loginTask = m_account->login(nullptr, ui->passTextBox->text());
|
||||
connect(m_loginTask.get(), &Task::failed, this, &LoginDialog::onTaskFailed);
|
||||
connect(m_loginTask.get(), &Task::succeeded, this,
|
||||
&LoginDialog::onTaskSucceeded);
|
||||
connect(m_loginTask.get(), &Task::status, this, &LoginDialog::onTaskStatus);
|
||||
connect(m_loginTask.get(), &Task::progress, this, &LoginDialog::onTaskProgress);
|
||||
m_loginTask->start();
|
||||
// Setup the login task and start it
|
||||
m_account = MojangAccount::createFromUsername(ui->userTextBox->text());
|
||||
m_loginTask = m_account->login(nullptr, ui->passTextBox->text());
|
||||
connect(m_loginTask.get(), &Task::failed, this, &LoginDialog::onTaskFailed);
|
||||
connect(m_loginTask.get(), &Task::succeeded, this,
|
||||
&LoginDialog::onTaskSucceeded);
|
||||
connect(m_loginTask.get(), &Task::status, this, &LoginDialog::onTaskStatus);
|
||||
connect(m_loginTask.get(), &Task::progress, this, &LoginDialog::onTaskProgress);
|
||||
m_loginTask->start();
|
||||
}
|
||||
|
||||
void LoginDialog::setUserInputsEnabled(bool enable)
|
||||
{
|
||||
ui->userTextBox->setEnabled(enable);
|
||||
ui->passTextBox->setEnabled(enable);
|
||||
ui->buttonBox->setEnabled(enable);
|
||||
ui->userTextBox->setEnabled(enable);
|
||||
ui->passTextBox->setEnabled(enable);
|
||||
ui->buttonBox->setEnabled(enable);
|
||||
}
|
||||
|
||||
// Enable the OK button only when both textboxes contain something.
|
||||
void LoginDialog::on_userTextBox_textEdited(const QString &newText)
|
||||
{
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)
|
||||
->setEnabled(!newText.isEmpty() && !ui->passTextBox->text().isEmpty());
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)
|
||||
->setEnabled(!newText.isEmpty() && !ui->passTextBox->text().isEmpty());
|
||||
}
|
||||
void LoginDialog::on_passTextBox_textEdited(const QString &newText)
|
||||
{
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)
|
||||
->setEnabled(!newText.isEmpty() && !ui->userTextBox->text().isEmpty());
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)
|
||||
->setEnabled(!newText.isEmpty() && !ui->userTextBox->text().isEmpty());
|
||||
}
|
||||
|
||||
void LoginDialog::onTaskFailed(const QString &reason)
|
||||
{
|
||||
// Set message
|
||||
ui->label->setText("<span style='color:red'>" + reason + "</span>");
|
||||
// Set message
|
||||
ui->label->setText("<span style='color:red'>" + reason + "</span>");
|
||||
|
||||
// Re-enable user-interaction
|
||||
setUserInputsEnabled(true);
|
||||
ui->progressBar->setVisible(false);
|
||||
// Re-enable user-interaction
|
||||
setUserInputsEnabled(true);
|
||||
ui->progressBar->setVisible(false);
|
||||
}
|
||||
|
||||
void LoginDialog::onTaskSucceeded()
|
||||
{
|
||||
QDialog::accept();
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void LoginDialog::onTaskStatus(const QString &status)
|
||||
{
|
||||
ui->label->setText(status);
|
||||
ui->label->setText(status);
|
||||
}
|
||||
|
||||
void LoginDialog::onTaskProgress(qint64 current, qint64 total)
|
||||
{
|
||||
ui->progressBar->setMaximum(total);
|
||||
ui->progressBar->setValue(current);
|
||||
ui->progressBar->setMaximum(total);
|
||||
ui->progressBar->setValue(current);
|
||||
}
|
||||
|
||||
// Public interface
|
||||
MojangAccountPtr LoginDialog::newAccount(QWidget *parent, QString msg)
|
||||
{
|
||||
LoginDialog dlg(parent);
|
||||
dlg.ui->label->setText(msg);
|
||||
if (dlg.exec() == QDialog::Accepted)
|
||||
{
|
||||
return dlg.m_account;
|
||||
}
|
||||
return 0;
|
||||
LoginDialog dlg(parent);
|
||||
dlg.ui->label->setText(msg);
|
||||
if (dlg.exec() == QDialog::Accepted)
|
||||
{
|
||||
return dlg.m_account;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -27,32 +27,32 @@ class LoginDialog;
|
||||
|
||||
class LoginDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
~LoginDialog();
|
||||
~LoginDialog();
|
||||
|
||||
static MojangAccountPtr newAccount(QWidget *parent, QString message);
|
||||
static MojangAccountPtr newAccount(QWidget *parent, QString message);
|
||||
|
||||
private:
|
||||
explicit LoginDialog(QWidget *parent = 0);
|
||||
explicit LoginDialog(QWidget *parent = 0);
|
||||
|
||||
void setUserInputsEnabled(bool enable);
|
||||
void setUserInputsEnabled(bool enable);
|
||||
|
||||
protected
|
||||
slots:
|
||||
void accept();
|
||||
void accept();
|
||||
|
||||
void onTaskFailed(const QString &reason);
|
||||
void onTaskSucceeded();
|
||||
void onTaskStatus(const QString &status);
|
||||
void onTaskProgress(qint64 current, qint64 total);
|
||||
void onTaskFailed(const QString &reason);
|
||||
void onTaskSucceeded();
|
||||
void onTaskStatus(const QString &status);
|
||||
void onTaskProgress(qint64 current, qint64 total);
|
||||
|
||||
void on_userTextBox_textEdited(const QString &newText);
|
||||
void on_passTextBox_textEdited(const QString &newText);
|
||||
void on_userTextBox_textEdited(const QString &newText);
|
||||
void on_passTextBox_textEdited(const QString &newText);
|
||||
|
||||
private:
|
||||
Ui::LoginDialog *ui;
|
||||
MojangAccountPtr m_account;
|
||||
std::shared_ptr<Task> m_loginTask;
|
||||
Ui::LoginDialog *ui;
|
||||
MojangAccountPtr m_account;
|
||||
std::shared_ptr<Task> m_loginTask;
|
||||
};
|
||||
|
@ -4,37 +4,37 @@
|
||||
|
||||
bool lastfirst(QModelIndexList &list, int &first, int &last)
|
||||
{
|
||||
if (list.isEmpty())
|
||||
return false;
|
||||
first = last = list[0].row();
|
||||
for (auto item : list)
|
||||
{
|
||||
int row = item.row();
|
||||
if (row < first)
|
||||
first = row;
|
||||
if (row > last)
|
||||
last = row;
|
||||
}
|
||||
return true;
|
||||
if (list.isEmpty())
|
||||
return false;
|
||||
first = last = list[0].row();
|
||||
for (auto item : list)
|
||||
{
|
||||
int row = item.row();
|
||||
if (row < first)
|
||||
first = row;
|
||||
if (row > last)
|
||||
last = row;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void showWebsiteForMod(QWidget *parentDlg, Mod &m)
|
||||
{
|
||||
QString url = m.homeurl();
|
||||
if (url.size())
|
||||
{
|
||||
// catch the cases where the protocol is missing
|
||||
if (!url.startsWith("http"))
|
||||
{
|
||||
url = "http://" + url;
|
||||
}
|
||||
DesktopServices::openUrl(url);
|
||||
}
|
||||
else
|
||||
{
|
||||
CustomMessageBox::selectable(
|
||||
parentDlg, QObject::tr("How sad!"),
|
||||
QObject::tr("The mod author didn't provide a website link for this mod."),
|
||||
QMessageBox::Warning);
|
||||
}
|
||||
QString url = m.homeurl();
|
||||
if (url.size())
|
||||
{
|
||||
// catch the cases where the protocol is missing
|
||||
if (!url.startsWith("http"))
|
||||
{
|
||||
url = "http://" + url;
|
||||
}
|
||||
DesktopServices::openUrl(url);
|
||||
}
|
||||
else
|
||||
{
|
||||
CustomMessageBox::selectable(
|
||||
parentDlg, QObject::tr("How sad!"),
|
||||
QObject::tr("The mod author didn't provide a website link for this mod."),
|
||||
QMessageBox::Warning);
|
||||
}
|
||||
}
|
||||
|
@ -35,72 +35,72 @@
|
||||
#include <meta/VersionList.h>
|
||||
|
||||
NewComponentDialog::NewComponentDialog(const QString & initialName, const QString & initialUid, QWidget *parent)
|
||||
: QDialog(parent), ui(new Ui::NewComponentDialog)
|
||||
: QDialog(parent), ui(new Ui::NewComponentDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
resize(minimumSizeHint());
|
||||
ui->setupUi(this);
|
||||
resize(minimumSizeHint());
|
||||
|
||||
ui->nameTextBox->setText(initialName);
|
||||
ui->uidTextBox->setText(initialUid);
|
||||
ui->nameTextBox->setText(initialName);
|
||||
ui->uidTextBox->setText(initialUid);
|
||||
|
||||
connect(ui->nameTextBox, &QLineEdit::textChanged, this, &NewComponentDialog::updateDialogState);
|
||||
connect(ui->uidTextBox, &QLineEdit::textChanged, this, &NewComponentDialog::updateDialogState);
|
||||
connect(ui->nameTextBox, &QLineEdit::textChanged, this, &NewComponentDialog::updateDialogState);
|
||||
connect(ui->uidTextBox, &QLineEdit::textChanged, this, &NewComponentDialog::updateDialogState);
|
||||
|
||||
auto groups = MMC->instances()->getGroups().toSet();
|
||||
ui->nameTextBox->setFocus();
|
||||
auto groups = MMC->instances()->getGroups().toSet();
|
||||
ui->nameTextBox->setFocus();
|
||||
|
||||
originalPlaceholderText = ui->uidTextBox->placeholderText();
|
||||
updateDialogState();
|
||||
originalPlaceholderText = ui->uidTextBox->placeholderText();
|
||||
updateDialogState();
|
||||
}
|
||||
|
||||
NewComponentDialog::~NewComponentDialog()
|
||||
{
|
||||
delete ui;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void NewComponentDialog::updateDialogState()
|
||||
{
|
||||
auto protoUid = ui->nameTextBox->text().toLower();
|
||||
protoUid.remove(QRegularExpression("[^a-z]"));
|
||||
if(protoUid.isEmpty())
|
||||
{
|
||||
ui->uidTextBox->setPlaceholderText(originalPlaceholderText);
|
||||
}
|
||||
else
|
||||
{
|
||||
QString suggestedUid = "org.multimc.custom." + protoUid;
|
||||
ui->uidTextBox->setPlaceholderText(suggestedUid);
|
||||
}
|
||||
bool allowOK = !name().isEmpty() && !uid().isEmpty() && !uidBlacklist.contains(uid());
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(allowOK);
|
||||
auto protoUid = ui->nameTextBox->text().toLower();
|
||||
protoUid.remove(QRegularExpression("[^a-z]"));
|
||||
if(protoUid.isEmpty())
|
||||
{
|
||||
ui->uidTextBox->setPlaceholderText(originalPlaceholderText);
|
||||
}
|
||||
else
|
||||
{
|
||||
QString suggestedUid = "org.multimc.custom." + protoUid;
|
||||
ui->uidTextBox->setPlaceholderText(suggestedUid);
|
||||
}
|
||||
bool allowOK = !name().isEmpty() && !uid().isEmpty() && !uidBlacklist.contains(uid());
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(allowOK);
|
||||
}
|
||||
|
||||
QString NewComponentDialog::name() const
|
||||
{
|
||||
auto result = ui->nameTextBox->text();
|
||||
if(result.size())
|
||||
{
|
||||
return result.trimmed();
|
||||
}
|
||||
return QString();
|
||||
auto result = ui->nameTextBox->text();
|
||||
if(result.size())
|
||||
{
|
||||
return result.trimmed();
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString NewComponentDialog::uid() const
|
||||
{
|
||||
auto result = ui->uidTextBox->text();
|
||||
if(result.size())
|
||||
{
|
||||
return result.trimmed();
|
||||
}
|
||||
result = ui->uidTextBox->placeholderText();
|
||||
if(result.size() && result != originalPlaceholderText)
|
||||
{
|
||||
return result.trimmed();
|
||||
}
|
||||
return QString();
|
||||
auto result = ui->uidTextBox->text();
|
||||
if(result.size())
|
||||
{
|
||||
return result.trimmed();
|
||||
}
|
||||
result = ui->uidTextBox->placeholderText();
|
||||
if(result.size() && result != originalPlaceholderText)
|
||||
{
|
||||
return result.trimmed();
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
void NewComponentDialog::setBlacklist(QStringList badUids)
|
||||
{
|
||||
uidBlacklist = badUids;
|
||||
uidBlacklist = badUids;
|
||||
}
|
||||
|
@ -27,22 +27,22 @@ class NewComponentDialog;
|
||||
|
||||
class NewComponentDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit NewComponentDialog(const QString & initialName = QString(), const QString & initialUid = QString(), QWidget *parent = 0);
|
||||
virtual ~NewComponentDialog();
|
||||
void setBlacklist(QStringList badUids);
|
||||
explicit NewComponentDialog(const QString & initialName = QString(), const QString & initialUid = QString(), QWidget *parent = 0);
|
||||
virtual ~NewComponentDialog();
|
||||
void setBlacklist(QStringList badUids);
|
||||
|
||||
QString name() const;
|
||||
QString uid() const;
|
||||
QString name() const;
|
||||
QString uid() const;
|
||||
|
||||
private slots:
|
||||
void updateDialogState();
|
||||
void updateDialogState();
|
||||
|
||||
private:
|
||||
Ui::NewComponentDialog *ui;
|
||||
Ui::NewComponentDialog *ui;
|
||||
|
||||
QString originalPlaceholderText;
|
||||
QStringList uidBlacklist;
|
||||
QString originalPlaceholderText;
|
||||
QStringList uidBlacklist;
|
||||
};
|
||||
|
@ -40,178 +40,178 @@
|
||||
#include <pages/modplatform/TechnicPage.h>
|
||||
|
||||
NewInstanceDialog::NewInstanceDialog(const QString & initialGroup, const QString & url, QWidget *parent)
|
||||
: QDialog(parent), ui(new Ui::NewInstanceDialog)
|
||||
: QDialog(parent), ui(new Ui::NewInstanceDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->setupUi(this);
|
||||
|
||||
setWindowIcon(MMC->getThemedIcon("new"));
|
||||
setWindowIcon(MMC->getThemedIcon("new"));
|
||||
|
||||
InstIconKey = "default";
|
||||
ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
|
||||
InstIconKey = "default";
|
||||
ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
|
||||
|
||||
auto groups = MMC->instances()->getGroups().toSet();
|
||||
auto groupList = QStringList(groups.toList());
|
||||
groupList.sort(Qt::CaseInsensitive);
|
||||
groupList.removeOne("");
|
||||
groupList.push_front(initialGroup);
|
||||
groupList.push_front("");
|
||||
ui->groupBox->addItems(groupList);
|
||||
int index = groupList.indexOf(initialGroup);
|
||||
if(index == -1)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
ui->groupBox->setCurrentIndex(index);
|
||||
ui->groupBox->lineEdit()->setPlaceholderText(tr("No group"));
|
||||
auto groups = MMC->instances()->getGroups().toSet();
|
||||
auto groupList = QStringList(groups.toList());
|
||||
groupList.sort(Qt::CaseInsensitive);
|
||||
groupList.removeOne("");
|
||||
groupList.push_front(initialGroup);
|
||||
groupList.push_front("");
|
||||
ui->groupBox->addItems(groupList);
|
||||
int index = groupList.indexOf(initialGroup);
|
||||
if(index == -1)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
ui->groupBox->setCurrentIndex(index);
|
||||
ui->groupBox->lineEdit()->setPlaceholderText(tr("No group"));
|
||||
|
||||
m_buttons = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
m_buttons->button(QDialogButtonBox::Ok)->setDefault(true);
|
||||
m_buttons = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
m_buttons->button(QDialogButtonBox::Ok)->setDefault(true);
|
||||
|
||||
|
||||
m_container = new PageContainer(this);
|
||||
m_container->setSizePolicy(QSizePolicy::Policy::Preferred, QSizePolicy::Policy::Expanding);
|
||||
m_container->layout()->setContentsMargins(0, 0, 0, 0);
|
||||
ui->verticalLayout->insertWidget(2, m_container);
|
||||
m_container = new PageContainer(this);
|
||||
m_container->setSizePolicy(QSizePolicy::Policy::Preferred, QSizePolicy::Policy::Expanding);
|
||||
m_container->layout()->setContentsMargins(0, 0, 0, 0);
|
||||
ui->verticalLayout->insertWidget(2, m_container);
|
||||
|
||||
m_container->addButtons(m_buttons);
|
||||
m_buttons->setFocus();
|
||||
m_container->addButtons(m_buttons);
|
||||
m_buttons->setFocus();
|
||||
|
||||
if(!url.isEmpty())
|
||||
{
|
||||
m_container->selectPage("import");
|
||||
importPage->setUrl(url);
|
||||
}
|
||||
if(!url.isEmpty())
|
||||
{
|
||||
m_container->selectPage("import");
|
||||
importPage->setUrl(url);
|
||||
}
|
||||
|
||||
connect(m_buttons->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &NewInstanceDialog::accept);
|
||||
connect(m_buttons->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &NewInstanceDialog::reject);
|
||||
connect(m_buttons->button(QDialogButtonBox::Help), &QPushButton::clicked, m_container, &PageContainer::help);
|
||||
connect(m_buttons->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &NewInstanceDialog::accept);
|
||||
connect(m_buttons->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &NewInstanceDialog::reject);
|
||||
connect(m_buttons->button(QDialogButtonBox::Help), &QPushButton::clicked, m_container, &PageContainer::help);
|
||||
|
||||
updateDialogState();
|
||||
updateDialogState();
|
||||
|
||||
restoreGeometry(QByteArray::fromBase64(MMC->settings()->get("NewInstanceGeometry").toByteArray()));
|
||||
restoreGeometry(QByteArray::fromBase64(MMC->settings()->get("NewInstanceGeometry").toByteArray()));
|
||||
|
||||
}
|
||||
|
||||
void NewInstanceDialog::reject()
|
||||
{
|
||||
MMC->settings()->set("NewInstanceGeometry", saveGeometry().toBase64());
|
||||
QDialog::reject();
|
||||
MMC->settings()->set("NewInstanceGeometry", saveGeometry().toBase64());
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
void NewInstanceDialog::accept()
|
||||
{
|
||||
MMC->settings()->set("NewInstanceGeometry", saveGeometry().toBase64());
|
||||
importIconNow();
|
||||
QDialog::accept();
|
||||
MMC->settings()->set("NewInstanceGeometry", saveGeometry().toBase64());
|
||||
importIconNow();
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
QList<BasePage *> NewInstanceDialog::getPages()
|
||||
{
|
||||
importPage = new ImportPage(this);
|
||||
return
|
||||
{
|
||||
new VanillaPage(this),
|
||||
new FTBPage(this),
|
||||
importPage,
|
||||
new TwitchPage(this),
|
||||
new TechnicPage(this)
|
||||
};
|
||||
importPage = new ImportPage(this);
|
||||
return
|
||||
{
|
||||
new VanillaPage(this),
|
||||
new FTBPage(this),
|
||||
importPage,
|
||||
new TwitchPage(this),
|
||||
new TechnicPage(this)
|
||||
};
|
||||
}
|
||||
|
||||
QString NewInstanceDialog::dialogTitle()
|
||||
{
|
||||
return tr("New Instance");
|
||||
return tr("New Instance");
|
||||
}
|
||||
|
||||
NewInstanceDialog::~NewInstanceDialog()
|
||||
{
|
||||
delete ui;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void NewInstanceDialog::setSuggestedPack(const QString& name, InstanceTask* task)
|
||||
{
|
||||
creationTask.reset(task);
|
||||
ui->instNameTextBox->setPlaceholderText(name);
|
||||
creationTask.reset(task);
|
||||
ui->instNameTextBox->setPlaceholderText(name);
|
||||
|
||||
auto allowOK = task && !instName().isEmpty();
|
||||
m_buttons->button(QDialogButtonBox::Ok)->setEnabled(allowOK);
|
||||
auto allowOK = task && !instName().isEmpty();
|
||||
m_buttons->button(QDialogButtonBox::Ok)->setEnabled(allowOK);
|
||||
}
|
||||
|
||||
void NewInstanceDialog::setSuggestedIconFromFile(const QString &path, const QString &name)
|
||||
{
|
||||
importIcon = true;
|
||||
importIconPath = path;
|
||||
importIconName = name;
|
||||
importIcon = true;
|
||||
importIconPath = path;
|
||||
importIconName = name;
|
||||
|
||||
//Hmm, for some reason they can be to small
|
||||
ui->iconButton->setIcon(QIcon(path));
|
||||
//Hmm, for some reason they can be to small
|
||||
ui->iconButton->setIcon(QIcon(path));
|
||||
}
|
||||
|
||||
InstanceTask * NewInstanceDialog::extractTask()
|
||||
{
|
||||
InstanceTask * extracted = creationTask.get();
|
||||
creationTask.release();
|
||||
extracted->setName(instName());
|
||||
extracted->setGroup(instGroup());
|
||||
extracted->setIcon(iconKey());
|
||||
return extracted;
|
||||
InstanceTask * extracted = creationTask.get();
|
||||
creationTask.release();
|
||||
extracted->setName(instName());
|
||||
extracted->setGroup(instGroup());
|
||||
extracted->setIcon(iconKey());
|
||||
return extracted;
|
||||
}
|
||||
|
||||
void NewInstanceDialog::updateDialogState()
|
||||
{
|
||||
auto allowOK = creationTask && !instName().isEmpty();
|
||||
m_buttons->button(QDialogButtonBox::Ok)->setEnabled(allowOK);
|
||||
auto allowOK = creationTask && !instName().isEmpty();
|
||||
m_buttons->button(QDialogButtonBox::Ok)->setEnabled(allowOK);
|
||||
}
|
||||
|
||||
QString NewInstanceDialog::instName() const
|
||||
{
|
||||
auto result = ui->instNameTextBox->text();
|
||||
if(result.size())
|
||||
{
|
||||
return result.trimmed();
|
||||
}
|
||||
result = ui->instNameTextBox->placeholderText();
|
||||
if(result.size())
|
||||
{
|
||||
return result.trimmed();
|
||||
}
|
||||
return QString();
|
||||
auto result = ui->instNameTextBox->text();
|
||||
if(result.size())
|
||||
{
|
||||
return result.trimmed();
|
||||
}
|
||||
result = ui->instNameTextBox->placeholderText();
|
||||
if(result.size())
|
||||
{
|
||||
return result.trimmed();
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString NewInstanceDialog::instGroup() const
|
||||
{
|
||||
return ui->groupBox->currentText();
|
||||
return ui->groupBox->currentText();
|
||||
}
|
||||
QString NewInstanceDialog::iconKey() const
|
||||
{
|
||||
return InstIconKey;
|
||||
return InstIconKey;
|
||||
}
|
||||
|
||||
void NewInstanceDialog::on_iconButton_clicked()
|
||||
{
|
||||
importIconNow(); //so the user can switch back
|
||||
IconPickerDialog dlg(this);
|
||||
dlg.execWithSelection(InstIconKey);
|
||||
importIconNow(); //so the user can switch back
|
||||
IconPickerDialog dlg(this);
|
||||
dlg.execWithSelection(InstIconKey);
|
||||
|
||||
if (dlg.result() == QDialog::Accepted)
|
||||
{
|
||||
InstIconKey = dlg.selectedIconKey;
|
||||
ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
|
||||
importIcon = false;
|
||||
}
|
||||
if (dlg.result() == QDialog::Accepted)
|
||||
{
|
||||
InstIconKey = dlg.selectedIconKey;
|
||||
ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
|
||||
importIcon = false;
|
||||
}
|
||||
}
|
||||
|
||||
void NewInstanceDialog::on_instNameTextBox_textChanged(const QString &arg1)
|
||||
{
|
||||
updateDialogState();
|
||||
updateDialogState();
|
||||
}
|
||||
|
||||
void NewInstanceDialog::importIconNow()
|
||||
{
|
||||
if(importIcon) {
|
||||
MMC->icons()->installIcon(importIconPath, importIconName);
|
||||
InstIconKey = importIconName;
|
||||
importIcon = false;
|
||||
}
|
||||
MMC->settings()->set("NewInstanceGeometry", saveGeometry().toBase64());
|
||||
if(importIcon) {
|
||||
MMC->icons()->installIcon(importIconPath, importIconName);
|
||||
InstIconKey = importIconName;
|
||||
importIcon = false;
|
||||
}
|
||||
MMC->settings()->set("NewInstanceGeometry", saveGeometry().toBase64());
|
||||
}
|
||||
|
@ -32,46 +32,46 @@ class ImportPage;
|
||||
|
||||
class NewInstanceDialog : public QDialog, public BasePageProvider
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit NewInstanceDialog(const QString & initialGroup, const QString & url = QString(), QWidget *parent = 0);
|
||||
~NewInstanceDialog();
|
||||
explicit NewInstanceDialog(const QString & initialGroup, const QString & url = QString(), QWidget *parent = 0);
|
||||
~NewInstanceDialog();
|
||||
|
||||
void updateDialogState();
|
||||
void updateDialogState();
|
||||
|
||||
void setSuggestedPack(const QString & name = QString(), InstanceTask * task = nullptr);
|
||||
void setSuggestedIconFromFile(const QString &path, const QString &name);
|
||||
void setSuggestedPack(const QString & name = QString(), InstanceTask * task = nullptr);
|
||||
void setSuggestedIconFromFile(const QString &path, const QString &name);
|
||||
|
||||
InstanceTask * extractTask();
|
||||
InstanceTask * extractTask();
|
||||
|
||||
QString dialogTitle() override;
|
||||
QList<BasePage *> getPages() override;
|
||||
QString dialogTitle() override;
|
||||
QList<BasePage *> getPages() override;
|
||||
|
||||
QString instName() const;
|
||||
QString instGroup() const;
|
||||
QString iconKey() const;
|
||||
QString instName() const;
|
||||
QString instGroup() const;
|
||||
QString iconKey() const;
|
||||
|
||||
public slots:
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
|
||||
private slots:
|
||||
void on_iconButton_clicked();
|
||||
void on_instNameTextBox_textChanged(const QString &arg1);
|
||||
void on_iconButton_clicked();
|
||||
void on_instNameTextBox_textChanged(const QString &arg1);
|
||||
|
||||
private:
|
||||
Ui::NewInstanceDialog *ui = nullptr;
|
||||
PageContainer * m_container = nullptr;
|
||||
QDialogButtonBox * m_buttons = nullptr;
|
||||
Ui::NewInstanceDialog *ui = nullptr;
|
||||
PageContainer * m_container = nullptr;
|
||||
QDialogButtonBox * m_buttons = nullptr;
|
||||
|
||||
QString InstIconKey;
|
||||
ImportPage *importPage = nullptr;
|
||||
std::unique_ptr<InstanceTask> creationTask;
|
||||
QString InstIconKey;
|
||||
ImportPage *importPage = nullptr;
|
||||
std::unique_ptr<InstanceTask> creationTask;
|
||||
|
||||
bool importIcon = false;
|
||||
QString importIconPath;
|
||||
QString importIconName;
|
||||
bool importIcon = false;
|
||||
QString importIconPath;
|
||||
QString importIconName;
|
||||
|
||||
void importIconNow();
|
||||
void importIconNow();
|
||||
};
|
||||
|
@ -5,82 +5,82 @@
|
||||
#include <QStyle>
|
||||
|
||||
NotificationDialog::NotificationDialog(const NotificationChecker::NotificationEntry &entry, QWidget *parent) :
|
||||
QDialog(parent, Qt::MSWindowsFixedSizeDialogHint | Qt::WindowTitleHint | Qt::CustomizeWindowHint),
|
||||
ui(new Ui::NotificationDialog)
|
||||
QDialog(parent, Qt::MSWindowsFixedSizeDialogHint | Qt::WindowTitleHint | Qt::CustomizeWindowHint),
|
||||
ui(new Ui::NotificationDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->setupUi(this);
|
||||
|
||||
QStyle::StandardPixmap icon;
|
||||
switch (entry.type)
|
||||
{
|
||||
case NotificationChecker::NotificationEntry::Critical:
|
||||
icon = QStyle::SP_MessageBoxCritical;
|
||||
break;
|
||||
case NotificationChecker::NotificationEntry::Warning:
|
||||
icon = QStyle::SP_MessageBoxWarning;
|
||||
break;
|
||||
default:
|
||||
case NotificationChecker::NotificationEntry::Information:
|
||||
icon = QStyle::SP_MessageBoxInformation;
|
||||
break;
|
||||
}
|
||||
ui->iconLabel->setPixmap(style()->standardPixmap(icon, 0, this));
|
||||
ui->messageLabel->setText(entry.message);
|
||||
QStyle::StandardPixmap icon;
|
||||
switch (entry.type)
|
||||
{
|
||||
case NotificationChecker::NotificationEntry::Critical:
|
||||
icon = QStyle::SP_MessageBoxCritical;
|
||||
break;
|
||||
case NotificationChecker::NotificationEntry::Warning:
|
||||
icon = QStyle::SP_MessageBoxWarning;
|
||||
break;
|
||||
default:
|
||||
case NotificationChecker::NotificationEntry::Information:
|
||||
icon = QStyle::SP_MessageBoxInformation;
|
||||
break;
|
||||
}
|
||||
ui->iconLabel->setPixmap(style()->standardPixmap(icon, 0, this));
|
||||
ui->messageLabel->setText(entry.message);
|
||||
|
||||
m_dontShowAgainText = tr("Don't show again");
|
||||
m_closeText = tr("Close");
|
||||
m_dontShowAgainText = tr("Don't show again");
|
||||
m_closeText = tr("Close");
|
||||
|
||||
ui->dontShowAgainBtn->setText(m_dontShowAgainText + QString(" (%1)").arg(m_dontShowAgainTime));
|
||||
ui->closeBtn->setText(m_closeText + QString(" (%1)").arg(m_closeTime));
|
||||
ui->dontShowAgainBtn->setText(m_dontShowAgainText + QString(" (%1)").arg(m_dontShowAgainTime));
|
||||
ui->closeBtn->setText(m_closeText + QString(" (%1)").arg(m_closeTime));
|
||||
|
||||
startTimer(1000);
|
||||
startTimer(1000);
|
||||
}
|
||||
|
||||
NotificationDialog::~NotificationDialog()
|
||||
{
|
||||
delete ui;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void NotificationDialog::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
if (m_dontShowAgainTime > 0)
|
||||
{
|
||||
m_dontShowAgainTime--;
|
||||
if (m_dontShowAgainTime == 0)
|
||||
{
|
||||
ui->dontShowAgainBtn->setText(m_dontShowAgainText);
|
||||
ui->dontShowAgainBtn->setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->dontShowAgainBtn->setText(m_dontShowAgainText + QString(" (%1)").arg(m_dontShowAgainTime));
|
||||
}
|
||||
}
|
||||
if (m_closeTime > 0)
|
||||
{
|
||||
m_closeTime--;
|
||||
if (m_closeTime == 0)
|
||||
{
|
||||
ui->closeBtn->setText(m_closeText);
|
||||
ui->closeBtn->setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->closeBtn->setText(m_closeText + QString(" (%1)").arg(m_closeTime));
|
||||
}
|
||||
}
|
||||
if (m_dontShowAgainTime > 0)
|
||||
{
|
||||
m_dontShowAgainTime--;
|
||||
if (m_dontShowAgainTime == 0)
|
||||
{
|
||||
ui->dontShowAgainBtn->setText(m_dontShowAgainText);
|
||||
ui->dontShowAgainBtn->setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->dontShowAgainBtn->setText(m_dontShowAgainText + QString(" (%1)").arg(m_dontShowAgainTime));
|
||||
}
|
||||
}
|
||||
if (m_closeTime > 0)
|
||||
{
|
||||
m_closeTime--;
|
||||
if (m_closeTime == 0)
|
||||
{
|
||||
ui->closeBtn->setText(m_closeText);
|
||||
ui->closeBtn->setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->closeBtn->setText(m_closeText + QString(" (%1)").arg(m_closeTime));
|
||||
}
|
||||
}
|
||||
|
||||
if (m_closeTime == 0 && m_dontShowAgainTime == 0)
|
||||
{
|
||||
killTimer(event->timerId());
|
||||
}
|
||||
if (m_closeTime == 0 && m_dontShowAgainTime == 0)
|
||||
{
|
||||
killTimer(event->timerId());
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationDialog::on_dontShowAgainBtn_clicked()
|
||||
{
|
||||
done(DontShowAgain);
|
||||
done(DontShowAgain);
|
||||
}
|
||||
void NotificationDialog::on_closeBtn_clicked()
|
||||
{
|
||||
done(Normal);
|
||||
done(Normal);
|
||||
}
|
||||
|
@ -11,34 +11,34 @@ class NotificationDialog;
|
||||
|
||||
class NotificationDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit NotificationDialog(const NotificationChecker::NotificationEntry &entry, QWidget *parent = 0);
|
||||
~NotificationDialog();
|
||||
explicit NotificationDialog(const NotificationChecker::NotificationEntry &entry, QWidget *parent = 0);
|
||||
~NotificationDialog();
|
||||
|
||||
enum ExitCode
|
||||
{
|
||||
Normal,
|
||||
DontShowAgain
|
||||
};
|
||||
enum ExitCode
|
||||
{
|
||||
Normal,
|
||||
DontShowAgain
|
||||
};
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *event);
|
||||
void timerEvent(QTimerEvent *event);
|
||||
|
||||
private:
|
||||
Ui::NotificationDialog *ui;
|
||||
Ui::NotificationDialog *ui;
|
||||
|
||||
int m_dontShowAgainTime = 10;
|
||||
int m_closeTime = 5;
|
||||
int m_dontShowAgainTime = 10;
|
||||
int m_closeTime = 5;
|
||||
|
||||
QString m_dontShowAgainText;
|
||||
QString m_closeText;
|
||||
QString m_dontShowAgainText;
|
||||
QString m_closeText;
|
||||
|
||||
private
|
||||
slots:
|
||||
void on_dontShowAgainBtn_clicked();
|
||||
void on_closeBtn_clicked();
|
||||
void on_dontShowAgainBtn_clicked();
|
||||
void on_closeBtn_clicked();
|
||||
};
|
||||
|
||||
#endif // NOTIFICATIONDIALOG_H
|
||||
|
@ -26,91 +26,91 @@
|
||||
#include <MultiMC.h>
|
||||
|
||||
ProfileSelectDialog::ProfileSelectDialog(const QString &message, int flags, QWidget *parent)
|
||||
: QDialog(parent), ui(new Ui::ProfileSelectDialog)
|
||||
: QDialog(parent), ui(new Ui::ProfileSelectDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->setupUi(this);
|
||||
|
||||
m_accounts = MMC->accounts();
|
||||
auto view = ui->listView;
|
||||
//view->setModel(m_accounts.get());
|
||||
//view->hideColumn(MojangAccountList::ActiveColumn);
|
||||
view->setColumnCount(1);
|
||||
view->setRootIsDecorated(false);
|
||||
if(QTreeWidgetItem* header = view->headerItem())
|
||||
{
|
||||
header->setText(0, tr("Name"));
|
||||
}
|
||||
else
|
||||
{
|
||||
view->setHeaderLabel(tr("Name"));
|
||||
}
|
||||
QList <QTreeWidgetItem *> items;
|
||||
for (int i = 0; i < m_accounts->count(); i++)
|
||||
{
|
||||
MojangAccountPtr account = m_accounts->at(i);
|
||||
for (auto profile : account->profiles())
|
||||
{
|
||||
auto profileLabel = profile.name;
|
||||
if(account->isInUse())
|
||||
{
|
||||
profileLabel += tr(" (in use)");
|
||||
}
|
||||
auto item = new QTreeWidgetItem(view);
|
||||
item->setText(0, profileLabel);
|
||||
item->setIcon(0, SkinUtils::getFaceFromCache(profile.id));
|
||||
item->setData(0, MojangAccountList::PointerRole, QVariant::fromValue(account));
|
||||
items.append(item);
|
||||
}
|
||||
}
|
||||
view->addTopLevelItems(items);
|
||||
m_accounts = MMC->accounts();
|
||||
auto view = ui->listView;
|
||||
//view->setModel(m_accounts.get());
|
||||
//view->hideColumn(MojangAccountList::ActiveColumn);
|
||||
view->setColumnCount(1);
|
||||
view->setRootIsDecorated(false);
|
||||
if(QTreeWidgetItem* header = view->headerItem())
|
||||
{
|
||||
header->setText(0, tr("Name"));
|
||||
}
|
||||
else
|
||||
{
|
||||
view->setHeaderLabel(tr("Name"));
|
||||
}
|
||||
QList <QTreeWidgetItem *> items;
|
||||
for (int i = 0; i < m_accounts->count(); i++)
|
||||
{
|
||||
MojangAccountPtr account = m_accounts->at(i);
|
||||
for (auto profile : account->profiles())
|
||||
{
|
||||
auto profileLabel = profile.name;
|
||||
if(account->isInUse())
|
||||
{
|
||||
profileLabel += tr(" (in use)");
|
||||
}
|
||||
auto item = new QTreeWidgetItem(view);
|
||||
item->setText(0, profileLabel);
|
||||
item->setIcon(0, SkinUtils::getFaceFromCache(profile.id));
|
||||
item->setData(0, MojangAccountList::PointerRole, QVariant::fromValue(account));
|
||||
items.append(item);
|
||||
}
|
||||
}
|
||||
view->addTopLevelItems(items);
|
||||
|
||||
// Set the message label.
|
||||
ui->msgLabel->setVisible(!message.isEmpty());
|
||||
ui->msgLabel->setText(message);
|
||||
// Set the message label.
|
||||
ui->msgLabel->setVisible(!message.isEmpty());
|
||||
ui->msgLabel->setText(message);
|
||||
|
||||
// Flags...
|
||||
ui->globalDefaultCheck->setVisible(flags & GlobalDefaultCheckbox);
|
||||
ui->instDefaultCheck->setVisible(flags & InstanceDefaultCheckbox);
|
||||
qDebug() << flags;
|
||||
// Flags...
|
||||
ui->globalDefaultCheck->setVisible(flags & GlobalDefaultCheckbox);
|
||||
ui->instDefaultCheck->setVisible(flags & InstanceDefaultCheckbox);
|
||||
qDebug() << flags;
|
||||
|
||||
// Select the first entry in the list.
|
||||
ui->listView->setCurrentIndex(ui->listView->model()->index(0, 0));
|
||||
// Select the first entry in the list.
|
||||
ui->listView->setCurrentIndex(ui->listView->model()->index(0, 0));
|
||||
|
||||
connect(ui->listView, SIGNAL(doubleClicked(QModelIndex)), SLOT(on_buttonBox_accepted()));
|
||||
connect(ui->listView, SIGNAL(doubleClicked(QModelIndex)), SLOT(on_buttonBox_accepted()));
|
||||
}
|
||||
|
||||
ProfileSelectDialog::~ProfileSelectDialog()
|
||||
{
|
||||
delete ui;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
MojangAccountPtr ProfileSelectDialog::selectedAccount() const
|
||||
{
|
||||
return m_selected;
|
||||
return m_selected;
|
||||
}
|
||||
|
||||
bool ProfileSelectDialog::useAsGlobalDefault() const
|
||||
{
|
||||
return ui->globalDefaultCheck->isChecked();
|
||||
return ui->globalDefaultCheck->isChecked();
|
||||
}
|
||||
|
||||
bool ProfileSelectDialog::useAsInstDefaullt() const
|
||||
{
|
||||
return ui->instDefaultCheck->isChecked();
|
||||
return ui->instDefaultCheck->isChecked();
|
||||
}
|
||||
|
||||
void ProfileSelectDialog::on_buttonBox_accepted()
|
||||
{
|
||||
QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
|
||||
if (selection.size() > 0)
|
||||
{
|
||||
QModelIndex selected = selection.first();
|
||||
m_selected = selected.data(MojangAccountList::PointerRole).value<MojangAccountPtr>();
|
||||
}
|
||||
close();
|
||||
QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
|
||||
if (selection.size() > 0)
|
||||
{
|
||||
QModelIndex selected = selection.first();
|
||||
m_selected = selected.data(MojangAccountList::PointerRole).value<MojangAccountPtr>();
|
||||
}
|
||||
close();
|
||||
}
|
||||
|
||||
void ProfileSelectDialog::on_buttonBox_rejected()
|
||||
{
|
||||
close();
|
||||
close();
|
||||
}
|
||||
|
@ -28,63 +28,63 @@ class ProfileSelectDialog;
|
||||
|
||||
class ProfileSelectDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Flags
|
||||
{
|
||||
NoFlags = 0,
|
||||
enum Flags
|
||||
{
|
||||
NoFlags = 0,
|
||||
|
||||
/*!
|
||||
* Shows a check box on the dialog that allows the user to specify that the account
|
||||
* they've selected should be used as the global default for all instances.
|
||||
*/
|
||||
GlobalDefaultCheckbox,
|
||||
/*!
|
||||
* Shows a check box on the dialog that allows the user to specify that the account
|
||||
* they've selected should be used as the global default for all instances.
|
||||
*/
|
||||
GlobalDefaultCheckbox,
|
||||
|
||||
/*!
|
||||
* Shows a check box on the dialog that allows the user to specify that the account
|
||||
* they've selected should be used as the default for the instance they are currently launching.
|
||||
* This is not currently implemented.
|
||||
*/
|
||||
InstanceDefaultCheckbox,
|
||||
};
|
||||
/*!
|
||||
* Shows a check box on the dialog that allows the user to specify that the account
|
||||
* they've selected should be used as the default for the instance they are currently launching.
|
||||
* This is not currently implemented.
|
||||
*/
|
||||
InstanceDefaultCheckbox,
|
||||
};
|
||||
|
||||
/*!
|
||||
* Constructs a new account select dialog with the given parent and message.
|
||||
* The message will be shown at the top of the dialog. It is an empty string by default.
|
||||
*/
|
||||
explicit ProfileSelectDialog(const QString& message="", int flags=0, QWidget *parent = 0);
|
||||
~ProfileSelectDialog();
|
||||
/*!
|
||||
* Constructs a new account select dialog with the given parent and message.
|
||||
* The message will be shown at the top of the dialog. It is an empty string by default.
|
||||
*/
|
||||
explicit ProfileSelectDialog(const QString& message="", int flags=0, QWidget *parent = 0);
|
||||
~ProfileSelectDialog();
|
||||
|
||||
/*!
|
||||
* Gets a pointer to the account that the user selected.
|
||||
* This is null if the user clicked cancel or hasn't clicked OK yet.
|
||||
*/
|
||||
MojangAccountPtr selectedAccount() const;
|
||||
/*!
|
||||
* Gets a pointer to the account that the user selected.
|
||||
* This is null if the user clicked cancel or hasn't clicked OK yet.
|
||||
*/
|
||||
MojangAccountPtr selectedAccount() const;
|
||||
|
||||
/*!
|
||||
* Returns true if the user checked the "use as global default" checkbox.
|
||||
* If the checkbox wasn't shown, this function returns false.
|
||||
*/
|
||||
bool useAsGlobalDefault() const;
|
||||
/*!
|
||||
* Returns true if the user checked the "use as global default" checkbox.
|
||||
* If the checkbox wasn't shown, this function returns false.
|
||||
*/
|
||||
bool useAsGlobalDefault() const;
|
||||
|
||||
/*!
|
||||
* Returns true if the user checked the "use as instance default" checkbox.
|
||||
* If the checkbox wasn't shown, this function returns false.
|
||||
*/
|
||||
bool useAsInstDefaullt() const;
|
||||
/*!
|
||||
* Returns true if the user checked the "use as instance default" checkbox.
|
||||
* If the checkbox wasn't shown, this function returns false.
|
||||
*/
|
||||
bool useAsInstDefaullt() const;
|
||||
|
||||
public
|
||||
slots:
|
||||
void on_buttonBox_accepted();
|
||||
void on_buttonBox_accepted();
|
||||
|
||||
void on_buttonBox_rejected();
|
||||
void on_buttonBox_rejected();
|
||||
|
||||
protected:
|
||||
std::shared_ptr<MojangAccountList> m_accounts;
|
||||
std::shared_ptr<MojangAccountList> m_accounts;
|
||||
|
||||
//! The account that was selected when the user clicked OK.
|
||||
MojangAccountPtr m_selected;
|
||||
//! The account that was selected when the user clicked OK.
|
||||
MojangAccountPtr m_selected;
|
||||
|
||||
private:
|
||||
Ui::ProfileSelectDialog *ui;
|
||||
Ui::ProfileSelectDialog *ui;
|
||||
};
|
||||
|
@ -23,117 +23,117 @@
|
||||
|
||||
ProgressDialog::ProgressDialog(QWidget *parent) : QDialog(parent), ui(new Ui::ProgressDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
this->setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
setSkipButton(false);
|
||||
changeProgress(0, 100);
|
||||
ui->setupUi(this);
|
||||
this->setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
setSkipButton(false);
|
||||
changeProgress(0, 100);
|
||||
}
|
||||
|
||||
void ProgressDialog::setSkipButton(bool present, QString label)
|
||||
{
|
||||
ui->skipButton->setAutoDefault(false);
|
||||
ui->skipButton->setDefault(false);
|
||||
ui->skipButton->setFocusPolicy(Qt::ClickFocus);
|
||||
ui->skipButton->setEnabled(present);
|
||||
ui->skipButton->setVisible(present);
|
||||
ui->skipButton->setText(label);
|
||||
updateSize();
|
||||
ui->skipButton->setAutoDefault(false);
|
||||
ui->skipButton->setDefault(false);
|
||||
ui->skipButton->setFocusPolicy(Qt::ClickFocus);
|
||||
ui->skipButton->setEnabled(present);
|
||||
ui->skipButton->setVisible(present);
|
||||
ui->skipButton->setText(label);
|
||||
updateSize();
|
||||
}
|
||||
|
||||
void ProgressDialog::on_skipButton_clicked(bool checked)
|
||||
{
|
||||
Q_UNUSED(checked);
|
||||
task->abort();
|
||||
Q_UNUSED(checked);
|
||||
task->abort();
|
||||
}
|
||||
|
||||
ProgressDialog::~ProgressDialog()
|
||||
{
|
||||
delete ui;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ProgressDialog::updateSize()
|
||||
{
|
||||
QSize qSize = QSize(480, minimumSizeHint().height());
|
||||
resize(qSize);
|
||||
resize(qSize);
|
||||
setFixedSize(qSize);
|
||||
}
|
||||
|
||||
int ProgressDialog::execWithTask(Task *task)
|
||||
{
|
||||
this->task = task;
|
||||
QDialog::DialogCode result;
|
||||
this->task = task;
|
||||
QDialog::DialogCode result;
|
||||
|
||||
if(!task)
|
||||
{
|
||||
qDebug() << "Programmer error: progress dialog created with null task.";
|
||||
return Accepted;
|
||||
}
|
||||
if(!task)
|
||||
{
|
||||
qDebug() << "Programmer error: progress dialog created with null task.";
|
||||
return Accepted;
|
||||
}
|
||||
|
||||
if(handleImmediateResult(result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
if(handleImmediateResult(result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
// Connect signals.
|
||||
connect(task, SIGNAL(started()), SLOT(onTaskStarted()));
|
||||
connect(task, SIGNAL(failed(QString)), SLOT(onTaskFailed(QString)));
|
||||
connect(task, SIGNAL(succeeded()), SLOT(onTaskSucceeded()));
|
||||
connect(task, SIGNAL(status(QString)), SLOT(changeStatus(const QString &)));
|
||||
connect(task, SIGNAL(progress(qint64, qint64)), SLOT(changeProgress(qint64, qint64)));
|
||||
// Connect signals.
|
||||
connect(task, SIGNAL(started()), SLOT(onTaskStarted()));
|
||||
connect(task, SIGNAL(failed(QString)), SLOT(onTaskFailed(QString)));
|
||||
connect(task, SIGNAL(succeeded()), SLOT(onTaskSucceeded()));
|
||||
connect(task, SIGNAL(status(QString)), SLOT(changeStatus(const QString &)));
|
||||
connect(task, SIGNAL(progress(qint64, qint64)), SLOT(changeProgress(qint64, qint64)));
|
||||
|
||||
// if this didn't connect to an already running task, invoke start
|
||||
if(!task->isRunning())
|
||||
{
|
||||
task->start();
|
||||
}
|
||||
if(task->isRunning())
|
||||
{
|
||||
changeProgress(task->getProgress(), task->getTotalProgress());
|
||||
changeStatus(task->getStatus());
|
||||
return QDialog::exec();
|
||||
}
|
||||
else if(handleImmediateResult(result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return QDialog::Rejected;
|
||||
}
|
||||
// if this didn't connect to an already running task, invoke start
|
||||
if(!task->isRunning())
|
||||
{
|
||||
task->start();
|
||||
}
|
||||
if(task->isRunning())
|
||||
{
|
||||
changeProgress(task->getProgress(), task->getTotalProgress());
|
||||
changeStatus(task->getStatus());
|
||||
return QDialog::exec();
|
||||
}
|
||||
else if(handleImmediateResult(result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return QDialog::Rejected;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: only provide the unique_ptr overloads
|
||||
int ProgressDialog::execWithTask(std::unique_ptr<Task> &&task)
|
||||
{
|
||||
connect(this, &ProgressDialog::destroyed, task.get(), &Task::deleteLater);
|
||||
return execWithTask(task.release());
|
||||
connect(this, &ProgressDialog::destroyed, task.get(), &Task::deleteLater);
|
||||
return execWithTask(task.release());
|
||||
}
|
||||
int ProgressDialog::execWithTask(std::unique_ptr<Task> &task)
|
||||
{
|
||||
connect(this, &ProgressDialog::destroyed, task.get(), &Task::deleteLater);
|
||||
return execWithTask(task.release());
|
||||
connect(this, &ProgressDialog::destroyed, task.get(), &Task::deleteLater);
|
||||
return execWithTask(task.release());
|
||||
}
|
||||
|
||||
bool ProgressDialog::handleImmediateResult(QDialog::DialogCode &result)
|
||||
{
|
||||
if(task->isFinished())
|
||||
{
|
||||
if(task->wasSuccessful())
|
||||
{
|
||||
result = QDialog::Accepted;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = QDialog::Rejected;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if(task->isFinished())
|
||||
{
|
||||
if(task->wasSuccessful())
|
||||
{
|
||||
result = QDialog::Accepted;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = QDialog::Rejected;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Task *ProgressDialog::getTask()
|
||||
{
|
||||
return task;
|
||||
return task;
|
||||
}
|
||||
|
||||
void ProgressDialog::onTaskStarted()
|
||||
@ -142,55 +142,55 @@ void ProgressDialog::onTaskStarted()
|
||||
|
||||
void ProgressDialog::onTaskFailed(QString failure)
|
||||
{
|
||||
reject();
|
||||
reject();
|
||||
}
|
||||
|
||||
void ProgressDialog::onTaskSucceeded()
|
||||
{
|
||||
accept();
|
||||
accept();
|
||||
}
|
||||
|
||||
void ProgressDialog::changeStatus(const QString &status)
|
||||
{
|
||||
ui->statusLabel->setText(status);
|
||||
updateSize();
|
||||
ui->statusLabel->setText(status);
|
||||
updateSize();
|
||||
}
|
||||
|
||||
void ProgressDialog::changeProgress(qint64 current, qint64 total)
|
||||
{
|
||||
ui->taskProgressBar->setMaximum(total);
|
||||
ui->taskProgressBar->setValue(current);
|
||||
ui->taskProgressBar->setMaximum(total);
|
||||
ui->taskProgressBar->setValue(current);
|
||||
}
|
||||
|
||||
void ProgressDialog::keyPressEvent(QKeyEvent *e)
|
||||
{
|
||||
if(ui->skipButton->isVisible())
|
||||
{
|
||||
if (e->key() == Qt::Key_Escape)
|
||||
{
|
||||
on_skipButton_clicked(true);
|
||||
return;
|
||||
}
|
||||
else if(e->key() == Qt::Key_Tab)
|
||||
{
|
||||
ui->skipButton->setFocusPolicy(Qt::StrongFocus);
|
||||
ui->skipButton->setFocus();
|
||||
ui->skipButton->setAutoDefault(true);
|
||||
ui->skipButton->setDefault(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
QDialog::keyPressEvent(e);
|
||||
if(ui->skipButton->isVisible())
|
||||
{
|
||||
if (e->key() == Qt::Key_Escape)
|
||||
{
|
||||
on_skipButton_clicked(true);
|
||||
return;
|
||||
}
|
||||
else if(e->key() == Qt::Key_Tab)
|
||||
{
|
||||
ui->skipButton->setFocusPolicy(Qt::StrongFocus);
|
||||
ui->skipButton->setFocus();
|
||||
ui->skipButton->setAutoDefault(true);
|
||||
ui->skipButton->setDefault(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
QDialog::keyPressEvent(e);
|
||||
}
|
||||
|
||||
void ProgressDialog::closeEvent(QCloseEvent *e)
|
||||
{
|
||||
if (task && task->isRunning())
|
||||
{
|
||||
e->ignore();
|
||||
}
|
||||
else
|
||||
{
|
||||
QDialog::closeEvent(e);
|
||||
}
|
||||
if (task && task->isRunning())
|
||||
{
|
||||
e->ignore();
|
||||
}
|
||||
else
|
||||
{
|
||||
QDialog::closeEvent(e);
|
||||
}
|
||||
}
|
||||
|
@ -27,45 +27,45 @@ class ProgressDialog;
|
||||
|
||||
class ProgressDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ProgressDialog(QWidget *parent = 0);
|
||||
~ProgressDialog();
|
||||
explicit ProgressDialog(QWidget *parent = 0);
|
||||
~ProgressDialog();
|
||||
|
||||
void updateSize();
|
||||
void updateSize();
|
||||
|
||||
int execWithTask(Task *task);
|
||||
int execWithTask(std::unique_ptr<Task> &&task);
|
||||
int execWithTask(std::unique_ptr<Task> &task);
|
||||
int execWithTask(Task *task);
|
||||
int execWithTask(std::unique_ptr<Task> &&task);
|
||||
int execWithTask(std::unique_ptr<Task> &task);
|
||||
|
||||
void setSkipButton(bool present, QString label = QString());
|
||||
void setSkipButton(bool present, QString label = QString());
|
||||
|
||||
Task *getTask();
|
||||
Task *getTask();
|
||||
|
||||
public
|
||||
slots:
|
||||
void onTaskStarted();
|
||||
void onTaskFailed(QString failure);
|
||||
void onTaskSucceeded();
|
||||
void onTaskStarted();
|
||||
void onTaskFailed(QString failure);
|
||||
void onTaskSucceeded();
|
||||
|
||||
void changeStatus(const QString &status);
|
||||
void changeProgress(qint64 current, qint64 total);
|
||||
void changeStatus(const QString &status);
|
||||
void changeProgress(qint64 current, qint64 total);
|
||||
|
||||
|
||||
private
|
||||
slots:
|
||||
void on_skipButton_clicked(bool checked);
|
||||
void on_skipButton_clicked(bool checked);
|
||||
|
||||
protected:
|
||||
virtual void keyPressEvent(QKeyEvent *e);
|
||||
virtual void closeEvent(QCloseEvent *e);
|
||||
virtual void keyPressEvent(QKeyEvent *e);
|
||||
virtual void closeEvent(QCloseEvent *e);
|
||||
|
||||
private:
|
||||
bool handleImmediateResult(QDialog::DialogCode &result);
|
||||
bool handleImmediateResult(QDialog::DialogCode &result);
|
||||
|
||||
private:
|
||||
Ui::ProgressDialog *ui;
|
||||
Ui::ProgressDialog *ui;
|
||||
|
||||
Task *task;
|
||||
Task *task;
|
||||
};
|
||||
|
@ -9,106 +9,106 @@
|
||||
|
||||
void SkinUploadDialog::on_buttonBox_rejected()
|
||||
{
|
||||
close();
|
||||
close();
|
||||
}
|
||||
|
||||
void SkinUploadDialog::on_buttonBox_accepted()
|
||||
{
|
||||
AuthSessionPtr session = std::make_shared<AuthSession>();
|
||||
auto login = m_acct->login(session);
|
||||
ProgressDialog prog(this);
|
||||
if (prog.execWithTask((Task*)login.get()) != QDialog::Accepted)
|
||||
{
|
||||
//FIXME: recover with password prompt
|
||||
CustomMessageBox::selectable(this, tr("Skin Upload"), tr("Failed to login!"), QMessageBox::Warning)->exec();
|
||||
close();
|
||||
return;
|
||||
}
|
||||
QString fileName;
|
||||
QString input = ui->skinPathTextBox->text();
|
||||
QRegExp urlPrefixMatcher("^([a-z]+)://.+$");
|
||||
bool isLocalFile = false;
|
||||
// it has an URL prefix -> it is an URL
|
||||
if(urlPrefixMatcher.exactMatch(input))
|
||||
{
|
||||
QUrl fileURL = input;
|
||||
if(fileURL.isValid())
|
||||
{
|
||||
// local?
|
||||
if(fileURL.isLocalFile())
|
||||
{
|
||||
isLocalFile = true;
|
||||
fileName = fileURL.toLocalFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
CustomMessageBox::selectable(
|
||||
this,
|
||||
tr("Skin Upload"),
|
||||
tr("Using remote URLs for setting skins is not implemented yet."),
|
||||
QMessageBox::Warning
|
||||
)->exec();
|
||||
close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CustomMessageBox::selectable(
|
||||
this,
|
||||
tr("Skin Upload"),
|
||||
tr("You cannot use an invalid URL for uploading skins."),
|
||||
QMessageBox::Warning
|
||||
)->exec();
|
||||
close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// just assume it's a path then
|
||||
isLocalFile = true;
|
||||
fileName = ui->skinPathTextBox->text();
|
||||
}
|
||||
if (isLocalFile && !QFile::exists(fileName))
|
||||
{
|
||||
CustomMessageBox::selectable(this, tr("Skin Upload"), tr("Skin file does not exist!"), QMessageBox::Warning)->exec();
|
||||
close();
|
||||
return;
|
||||
}
|
||||
SkinUpload::Model model = SkinUpload::STEVE;
|
||||
if (ui->steveBtn->isChecked())
|
||||
{
|
||||
model = SkinUpload::STEVE;
|
||||
}
|
||||
else if (ui->alexBtn->isChecked())
|
||||
{
|
||||
model = SkinUpload::ALEX;
|
||||
}
|
||||
SkinUploadPtr upload = std::make_shared<SkinUpload>(this, session, FS::read(fileName), model);
|
||||
if (prog.execWithTask((Task*)upload.get()) != QDialog::Accepted)
|
||||
{
|
||||
CustomMessageBox::selectable(this, tr("Skin Upload"), tr("Failed to upload skin!"), QMessageBox::Warning)->exec();
|
||||
close();
|
||||
return;
|
||||
}
|
||||
CustomMessageBox::selectable(this, tr("Skin Upload"), tr("Success"), QMessageBox::Information)->exec();
|
||||
close();
|
||||
AuthSessionPtr session = std::make_shared<AuthSession>();
|
||||
auto login = m_acct->login(session);
|
||||
ProgressDialog prog(this);
|
||||
if (prog.execWithTask((Task*)login.get()) != QDialog::Accepted)
|
||||
{
|
||||
//FIXME: recover with password prompt
|
||||
CustomMessageBox::selectable(this, tr("Skin Upload"), tr("Failed to login!"), QMessageBox::Warning)->exec();
|
||||
close();
|
||||
return;
|
||||
}
|
||||
QString fileName;
|
||||
QString input = ui->skinPathTextBox->text();
|
||||
QRegExp urlPrefixMatcher("^([a-z]+)://.+$");
|
||||
bool isLocalFile = false;
|
||||
// it has an URL prefix -> it is an URL
|
||||
if(urlPrefixMatcher.exactMatch(input))
|
||||
{
|
||||
QUrl fileURL = input;
|
||||
if(fileURL.isValid())
|
||||
{
|
||||
// local?
|
||||
if(fileURL.isLocalFile())
|
||||
{
|
||||
isLocalFile = true;
|
||||
fileName = fileURL.toLocalFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
CustomMessageBox::selectable(
|
||||
this,
|
||||
tr("Skin Upload"),
|
||||
tr("Using remote URLs for setting skins is not implemented yet."),
|
||||
QMessageBox::Warning
|
||||
)->exec();
|
||||
close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CustomMessageBox::selectable(
|
||||
this,
|
||||
tr("Skin Upload"),
|
||||
tr("You cannot use an invalid URL for uploading skins."),
|
||||
QMessageBox::Warning
|
||||
)->exec();
|
||||
close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// just assume it's a path then
|
||||
isLocalFile = true;
|
||||
fileName = ui->skinPathTextBox->text();
|
||||
}
|
||||
if (isLocalFile && !QFile::exists(fileName))
|
||||
{
|
||||
CustomMessageBox::selectable(this, tr("Skin Upload"), tr("Skin file does not exist!"), QMessageBox::Warning)->exec();
|
||||
close();
|
||||
return;
|
||||
}
|
||||
SkinUpload::Model model = SkinUpload::STEVE;
|
||||
if (ui->steveBtn->isChecked())
|
||||
{
|
||||
model = SkinUpload::STEVE;
|
||||
}
|
||||
else if (ui->alexBtn->isChecked())
|
||||
{
|
||||
model = SkinUpload::ALEX;
|
||||
}
|
||||
SkinUploadPtr upload = std::make_shared<SkinUpload>(this, session, FS::read(fileName), model);
|
||||
if (prog.execWithTask((Task*)upload.get()) != QDialog::Accepted)
|
||||
{
|
||||
CustomMessageBox::selectable(this, tr("Skin Upload"), tr("Failed to upload skin!"), QMessageBox::Warning)->exec();
|
||||
close();
|
||||
return;
|
||||
}
|
||||
CustomMessageBox::selectable(this, tr("Skin Upload"), tr("Success"), QMessageBox::Information)->exec();
|
||||
close();
|
||||
}
|
||||
|
||||
void SkinUploadDialog::on_skinBrowseBtn_clicked()
|
||||
{
|
||||
QString raw_path = QFileDialog::getOpenFileName(this, tr("Select Skin Texture"), QString(), "*.png");
|
||||
if (raw_path.isEmpty() || !QFileInfo::exists(raw_path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
QString cooked_path = FS::NormalizePath(raw_path);
|
||||
ui->skinPathTextBox->setText(cooked_path);
|
||||
QString raw_path = QFileDialog::getOpenFileName(this, tr("Select Skin Texture"), QString(), "*.png");
|
||||
if (raw_path.isEmpty() || !QFileInfo::exists(raw_path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
QString cooked_path = FS::NormalizePath(raw_path);
|
||||
ui->skinPathTextBox->setText(cooked_path);
|
||||
}
|
||||
|
||||
SkinUploadDialog::SkinUploadDialog(MojangAccountPtr acct, QWidget *parent)
|
||||
:QDialog(parent), m_acct(acct), ui(new Ui::SkinUploadDialog)
|
||||
:QDialog(parent), m_acct(acct), ui(new Ui::SkinUploadDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
@ -5,25 +5,25 @@
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class SkinUploadDialog;
|
||||
class SkinUploadDialog;
|
||||
}
|
||||
|
||||
class SkinUploadDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SkinUploadDialog(MojangAccountPtr acct, QWidget *parent = 0);
|
||||
virtual ~SkinUploadDialog() {};
|
||||
explicit SkinUploadDialog(MojangAccountPtr acct, QWidget *parent = 0);
|
||||
virtual ~SkinUploadDialog() {};
|
||||
|
||||
public slots:
|
||||
void on_buttonBox_accepted();
|
||||
void on_buttonBox_accepted();
|
||||
|
||||
void on_buttonBox_rejected();
|
||||
void on_buttonBox_rejected();
|
||||
|
||||
void on_skinBrowseBtn_clicked();
|
||||
void on_skinBrowseBtn_clicked();
|
||||
|
||||
protected:
|
||||
MojangAccountPtr m_acct;
|
||||
MojangAccountPtr m_acct;
|
||||
|
||||
private:
|
||||
Ui::SkinUploadDialog *ui;
|
||||
Ui::SkinUploadDialog *ui;
|
||||
};
|
||||
|
@ -10,20 +10,20 @@
|
||||
|
||||
UpdateDialog::UpdateDialog(bool hasUpdate, QWidget *parent) : QDialog(parent), ui(new Ui::UpdateDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
auto channel = MMC->settings()->get("UpdateChannel").toString();
|
||||
if(hasUpdate)
|
||||
{
|
||||
ui->label->setText(tr("A new %1 update is available!").arg(channel));
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->label->setText(tr("No %1 updates found. You are running the latest version.").arg(channel));
|
||||
ui->btnUpdateNow->setHidden(true);
|
||||
ui->btnUpdateLater->setText(tr("Close"));
|
||||
}
|
||||
loadChangelog();
|
||||
restoreGeometry(QByteArray::fromBase64(MMC->settings()->get("UpdateDialogGeometry").toByteArray()));
|
||||
ui->setupUi(this);
|
||||
auto channel = MMC->settings()->get("UpdateChannel").toString();
|
||||
if(hasUpdate)
|
||||
{
|
||||
ui->label->setText(tr("A new %1 update is available!").arg(channel));
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->label->setText(tr("No %1 updates found. You are running the latest version.").arg(channel));
|
||||
ui->btnUpdateNow->setHidden(true);
|
||||
ui->btnUpdateLater->setText(tr("Close"));
|
||||
}
|
||||
loadChangelog();
|
||||
restoreGeometry(QByteArray::fromBase64(MMC->settings()->get("UpdateDialogGeometry").toByteArray()));
|
||||
}
|
||||
|
||||
UpdateDialog::~UpdateDialog()
|
||||
@ -32,150 +32,150 @@ UpdateDialog::~UpdateDialog()
|
||||
|
||||
void UpdateDialog::loadChangelog()
|
||||
{
|
||||
auto channel = MMC->settings()->get("UpdateChannel").toString();
|
||||
dljob.reset(new NetJob("Changelog"));
|
||||
QString url;
|
||||
if(channel == "stable")
|
||||
{
|
||||
url = QString("https://raw.githubusercontent.com/MultiMC/MultiMC5/%1/changelog.md").arg(channel);
|
||||
m_changelogType = CHANGELOG_MARKDOWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
url = QString("https://api.github.com/repos/MultiMC/MultiMC5/compare/%1...%2").arg(BuildConfig.GIT_COMMIT, channel);
|
||||
m_changelogType = CHANGELOG_COMMITS;
|
||||
}
|
||||
dljob->addNetAction(Net::Download::makeByteArray(QUrl(url), &changelogData));
|
||||
connect(dljob.get(), &NetJob::succeeded, this, &UpdateDialog::changelogLoaded);
|
||||
connect(dljob.get(), &NetJob::failed, this, &UpdateDialog::changelogFailed);
|
||||
dljob->start();
|
||||
auto channel = MMC->settings()->get("UpdateChannel").toString();
|
||||
dljob.reset(new NetJob("Changelog"));
|
||||
QString url;
|
||||
if(channel == "stable")
|
||||
{
|
||||
url = QString("https://raw.githubusercontent.com/MultiMC/MultiMC5/%1/changelog.md").arg(channel);
|
||||
m_changelogType = CHANGELOG_MARKDOWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
url = QString("https://api.github.com/repos/MultiMC/MultiMC5/compare/%1...%2").arg(BuildConfig.GIT_COMMIT, channel);
|
||||
m_changelogType = CHANGELOG_COMMITS;
|
||||
}
|
||||
dljob->addNetAction(Net::Download::makeByteArray(QUrl(url), &changelogData));
|
||||
connect(dljob.get(), &NetJob::succeeded, this, &UpdateDialog::changelogLoaded);
|
||||
connect(dljob.get(), &NetJob::failed, this, &UpdateDialog::changelogFailed);
|
||||
dljob->start();
|
||||
}
|
||||
|
||||
QString reprocessMarkdown(QByteArray markdown)
|
||||
{
|
||||
HoeDown hoedown;
|
||||
QString output = hoedown.process(markdown);
|
||||
HoeDown hoedown;
|
||||
QString output = hoedown.process(markdown);
|
||||
|
||||
// HACK: easier than customizing hoedown
|
||||
output.replace(QRegExp("GH-([0-9]+)"), "<a href=\"https://github.com/MultiMC/MultiMC5/issues/\\1\">GH-\\1</a>");
|
||||
qDebug() << output;
|
||||
return output;
|
||||
// HACK: easier than customizing hoedown
|
||||
output.replace(QRegExp("GH-([0-9]+)"), "<a href=\"https://github.com/MultiMC/MultiMC5/issues/\\1\">GH-\\1</a>");
|
||||
qDebug() << output;
|
||||
return output;
|
||||
}
|
||||
|
||||
QString reprocessCommits(QByteArray json)
|
||||
{
|
||||
auto channel = MMC->settings()->get("UpdateChannel").toString();
|
||||
try
|
||||
{
|
||||
QString result;
|
||||
auto document = Json::requireDocument(json);
|
||||
auto rootobject = Json::requireObject(document);
|
||||
auto status = Json::requireString(rootobject, "status");
|
||||
auto diff_url = Json::requireString(rootobject, "html_url");
|
||||
auto channel = MMC->settings()->get("UpdateChannel").toString();
|
||||
try
|
||||
{
|
||||
QString result;
|
||||
auto document = Json::requireDocument(json);
|
||||
auto rootobject = Json::requireObject(document);
|
||||
auto status = Json::requireString(rootobject, "status");
|
||||
auto diff_url = Json::requireString(rootobject, "html_url");
|
||||
|
||||
auto print_commits = [&]()
|
||||
{
|
||||
result += "<table cellspacing=0 cellpadding=2 style='border-width: 1px; border-style: solid'>";
|
||||
auto commitarray = Json::requireArray(rootobject, "commits");
|
||||
for(int i = commitarray.size() - 1; i >= 0; i--)
|
||||
{
|
||||
const auto & commitval = commitarray[i];
|
||||
auto commitobj = Json::requireObject(commitval);
|
||||
auto parents_info = Json::ensureArray(commitobj, "parents");
|
||||
// NOTE: this ignores merge commits, because they have more than one parent
|
||||
if(parents_info.size() > 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
auto commit_url = Json::requireString(commitobj, "html_url");
|
||||
auto commit_info = Json::requireObject(commitobj, "commit");
|
||||
auto commit_message = Json::requireString(commit_info, "message");
|
||||
auto lines = commit_message.split('\n');
|
||||
QRegularExpression regexp("(?<prefix>(GH-(?<issuenr>[0-9]+))|(NOISSUE)|(SCRATCH))? *(?<rest>.*) *");
|
||||
auto match = regexp.match(lines.takeFirst(), 0, QRegularExpression::NormalMatch);
|
||||
auto issuenr = match.captured("issuenr");
|
||||
auto prefix = match.captured("prefix");
|
||||
auto rest = match.captured("rest");
|
||||
result += "<tr><td>";
|
||||
if(issuenr.length())
|
||||
{
|
||||
result += QString("<a href=\"https://github.com/MultiMC/MultiMC5/issues/%1\">GH-%2</a>").arg(issuenr, issuenr);
|
||||
}
|
||||
else if(prefix.length())
|
||||
{
|
||||
result += QString("<a href=\"%1\">%2</a>").arg(commit_url, prefix);
|
||||
}
|
||||
else
|
||||
{
|
||||
result += QString("<a href=\"%1\">NOISSUE</a>").arg(commit_url);
|
||||
}
|
||||
result += "</td>";
|
||||
lines.prepend(rest);
|
||||
result += "<td><p>" + lines.join("<br />") + "</p></td></tr>";
|
||||
}
|
||||
result += "</table>";
|
||||
};
|
||||
auto print_commits = [&]()
|
||||
{
|
||||
result += "<table cellspacing=0 cellpadding=2 style='border-width: 1px; border-style: solid'>";
|
||||
auto commitarray = Json::requireArray(rootobject, "commits");
|
||||
for(int i = commitarray.size() - 1; i >= 0; i--)
|
||||
{
|
||||
const auto & commitval = commitarray[i];
|
||||
auto commitobj = Json::requireObject(commitval);
|
||||
auto parents_info = Json::ensureArray(commitobj, "parents");
|
||||
// NOTE: this ignores merge commits, because they have more than one parent
|
||||
if(parents_info.size() > 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
auto commit_url = Json::requireString(commitobj, "html_url");
|
||||
auto commit_info = Json::requireObject(commitobj, "commit");
|
||||
auto commit_message = Json::requireString(commit_info, "message");
|
||||
auto lines = commit_message.split('\n');
|
||||
QRegularExpression regexp("(?<prefix>(GH-(?<issuenr>[0-9]+))|(NOISSUE)|(SCRATCH))? *(?<rest>.*) *");
|
||||
auto match = regexp.match(lines.takeFirst(), 0, QRegularExpression::NormalMatch);
|
||||
auto issuenr = match.captured("issuenr");
|
||||
auto prefix = match.captured("prefix");
|
||||
auto rest = match.captured("rest");
|
||||
result += "<tr><td>";
|
||||
if(issuenr.length())
|
||||
{
|
||||
result += QString("<a href=\"https://github.com/MultiMC/MultiMC5/issues/%1\">GH-%2</a>").arg(issuenr, issuenr);
|
||||
}
|
||||
else if(prefix.length())
|
||||
{
|
||||
result += QString("<a href=\"%1\">%2</a>").arg(commit_url, prefix);
|
||||
}
|
||||
else
|
||||
{
|
||||
result += QString("<a href=\"%1\">NOISSUE</a>").arg(commit_url);
|
||||
}
|
||||
result += "</td>";
|
||||
lines.prepend(rest);
|
||||
result += "<td><p>" + lines.join("<br />") + "</p></td></tr>";
|
||||
}
|
||||
result += "</table>";
|
||||
};
|
||||
|
||||
if(status == "identical")
|
||||
{
|
||||
return QObject::tr("<p>There are no code changes between your current version and latest %1.</p>").arg(channel);
|
||||
}
|
||||
else if(status == "ahead")
|
||||
{
|
||||
result += QObject::tr("<p>Following commits were added since last update:</p>");
|
||||
print_commits();
|
||||
}
|
||||
else if(status == "diverged")
|
||||
{
|
||||
auto commit_ahead = Json::requireInteger(rootobject, "ahead_by");
|
||||
auto commit_behind = Json::requireInteger(rootobject, "behind_by");
|
||||
result += QObject::tr("<p>The update removes %1 commits and adds the following %2:</p>").arg(commit_behind).arg(commit_ahead);
|
||||
print_commits();
|
||||
}
|
||||
result += QObject::tr("<p>You can <a href=\"%1\">look at the changes on github</a>.</p>").arg(diff_url);
|
||||
return result;
|
||||
}
|
||||
catch (const JSONValidationError &e)
|
||||
{
|
||||
qWarning() << "Got an unparseable commit log from github:" << e.what();
|
||||
qDebug() << json;
|
||||
}
|
||||
return QString();
|
||||
if(status == "identical")
|
||||
{
|
||||
return QObject::tr("<p>There are no code changes between your current version and latest %1.</p>").arg(channel);
|
||||
}
|
||||
else if(status == "ahead")
|
||||
{
|
||||
result += QObject::tr("<p>Following commits were added since last update:</p>");
|
||||
print_commits();
|
||||
}
|
||||
else if(status == "diverged")
|
||||
{
|
||||
auto commit_ahead = Json::requireInteger(rootobject, "ahead_by");
|
||||
auto commit_behind = Json::requireInteger(rootobject, "behind_by");
|
||||
result += QObject::tr("<p>The update removes %1 commits and adds the following %2:</p>").arg(commit_behind).arg(commit_ahead);
|
||||
print_commits();
|
||||
}
|
||||
result += QObject::tr("<p>You can <a href=\"%1\">look at the changes on github</a>.</p>").arg(diff_url);
|
||||
return result;
|
||||
}
|
||||
catch (const JSONValidationError &e)
|
||||
{
|
||||
qWarning() << "Got an unparseable commit log from github:" << e.what();
|
||||
qDebug() << json;
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
void UpdateDialog::changelogLoaded()
|
||||
{
|
||||
QString result;
|
||||
switch(m_changelogType)
|
||||
{
|
||||
case CHANGELOG_COMMITS:
|
||||
result = reprocessCommits(changelogData);
|
||||
break;
|
||||
case CHANGELOG_MARKDOWN:
|
||||
result = reprocessMarkdown(changelogData);
|
||||
break;
|
||||
}
|
||||
changelogData.clear();
|
||||
ui->changelogBrowser->setHtml(result);
|
||||
QString result;
|
||||
switch(m_changelogType)
|
||||
{
|
||||
case CHANGELOG_COMMITS:
|
||||
result = reprocessCommits(changelogData);
|
||||
break;
|
||||
case CHANGELOG_MARKDOWN:
|
||||
result = reprocessMarkdown(changelogData);
|
||||
break;
|
||||
}
|
||||
changelogData.clear();
|
||||
ui->changelogBrowser->setHtml(result);
|
||||
}
|
||||
|
||||
void UpdateDialog::changelogFailed(QString reason)
|
||||
{
|
||||
ui->changelogBrowser->setHtml(tr("<p align=\"center\" <span style=\"font-size:22pt;\">Failed to fetch changelog... Error: %1</span></p>").arg(reason));
|
||||
ui->changelogBrowser->setHtml(tr("<p align=\"center\" <span style=\"font-size:22pt;\">Failed to fetch changelog... Error: %1</span></p>").arg(reason));
|
||||
}
|
||||
|
||||
void UpdateDialog::on_btnUpdateLater_clicked()
|
||||
{
|
||||
reject();
|
||||
reject();
|
||||
}
|
||||
|
||||
void UpdateDialog::on_btnUpdateNow_clicked()
|
||||
{
|
||||
done(UPDATE_NOW);
|
||||
done(UPDATE_NOW);
|
||||
}
|
||||
|
||||
void UpdateDialog::closeEvent(QCloseEvent* evt)
|
||||
{
|
||||
MMC->settings()->set("UpdateDialogGeometry", saveGeometry().toBase64());
|
||||
QDialog::closeEvent(evt);
|
||||
MMC->settings()->set("UpdateDialogGeometry", saveGeometry().toBase64());
|
||||
QDialog::closeEvent(evt);
|
||||
}
|
||||
|
@ -25,43 +25,43 @@ class UpdateDialog;
|
||||
|
||||
enum UpdateAction
|
||||
{
|
||||
UPDATE_LATER = QDialog::Rejected,
|
||||
UPDATE_NOW = QDialog::Accepted,
|
||||
UPDATE_LATER = QDialog::Rejected,
|
||||
UPDATE_NOW = QDialog::Accepted,
|
||||
};
|
||||
|
||||
enum ChangelogType
|
||||
{
|
||||
CHANGELOG_MARKDOWN,
|
||||
CHANGELOG_COMMITS
|
||||
CHANGELOG_MARKDOWN,
|
||||
CHANGELOG_COMMITS
|
||||
};
|
||||
|
||||
class UpdateDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit UpdateDialog(bool hasUpdate = true, QWidget *parent = 0);
|
||||
~UpdateDialog();
|
||||
explicit UpdateDialog(bool hasUpdate = true, QWidget *parent = 0);
|
||||
~UpdateDialog();
|
||||
|
||||
public slots:
|
||||
void on_btnUpdateNow_clicked();
|
||||
void on_btnUpdateLater_clicked();
|
||||
void on_btnUpdateNow_clicked();
|
||||
void on_btnUpdateLater_clicked();
|
||||
|
||||
/// Starts loading the changelog
|
||||
void loadChangelog();
|
||||
/// Starts loading the changelog
|
||||
void loadChangelog();
|
||||
|
||||
/// Slot for when the chengelog loads successfully.
|
||||
void changelogLoaded();
|
||||
/// Slot for when the chengelog loads successfully.
|
||||
void changelogLoaded();
|
||||
|
||||
/// Slot for when the chengelog fails to load...
|
||||
void changelogFailed(QString reason);
|
||||
/// Slot for when the chengelog fails to load...
|
||||
void changelogFailed(QString reason);
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent * ) override;
|
||||
void closeEvent(QCloseEvent * ) override;
|
||||
|
||||
private:
|
||||
Ui::UpdateDialog *ui;
|
||||
QByteArray changelogData;
|
||||
NetJobPtr dljob;
|
||||
ChangelogType m_changelogType = CHANGELOG_MARKDOWN;
|
||||
Ui::UpdateDialog *ui;
|
||||
QByteArray changelogData;
|
||||
NetJobPtr dljob;
|
||||
ChangelogType m_changelogType = CHANGELOG_MARKDOWN;
|
||||
};
|
||||
|
@ -33,109 +33,109 @@
|
||||
#include <widgets/VersionSelectWidget.h>
|
||||
|
||||
VersionSelectDialog::VersionSelectDialog(BaseVersionList *vlist, QString title, QWidget *parent, bool cancelable)
|
||||
: QDialog(parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
setObjectName(QStringLiteral("VersionSelectDialog"));
|
||||
resize(400, 347);
|
||||
m_verticalLayout = new QVBoxLayout(this);
|
||||
m_verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
|
||||
setObjectName(QStringLiteral("VersionSelectDialog"));
|
||||
resize(400, 347);
|
||||
m_verticalLayout = new QVBoxLayout(this);
|
||||
m_verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
|
||||
|
||||
m_versionWidget = new VersionSelectWidget(parent);
|
||||
m_verticalLayout->addWidget(m_versionWidget);
|
||||
m_versionWidget = new VersionSelectWidget(parent);
|
||||
m_verticalLayout->addWidget(m_versionWidget);
|
||||
|
||||
m_horizontalLayout = new QHBoxLayout();
|
||||
m_horizontalLayout->setObjectName(QStringLiteral("horizontalLayout"));
|
||||
m_horizontalLayout = new QHBoxLayout();
|
||||
m_horizontalLayout->setObjectName(QStringLiteral("horizontalLayout"));
|
||||
|
||||
m_refreshButton = new QPushButton(this);
|
||||
m_refreshButton->setObjectName(QStringLiteral("refreshButton"));
|
||||
m_horizontalLayout->addWidget(m_refreshButton);
|
||||
m_refreshButton = new QPushButton(this);
|
||||
m_refreshButton->setObjectName(QStringLiteral("refreshButton"));
|
||||
m_horizontalLayout->addWidget(m_refreshButton);
|
||||
|
||||
m_buttonBox = new QDialogButtonBox(this);
|
||||
m_buttonBox->setObjectName(QStringLiteral("buttonBox"));
|
||||
m_buttonBox->setOrientation(Qt::Horizontal);
|
||||
m_buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
|
||||
m_horizontalLayout->addWidget(m_buttonBox);
|
||||
m_buttonBox = new QDialogButtonBox(this);
|
||||
m_buttonBox->setObjectName(QStringLiteral("buttonBox"));
|
||||
m_buttonBox->setOrientation(Qt::Horizontal);
|
||||
m_buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
|
||||
m_horizontalLayout->addWidget(m_buttonBox);
|
||||
|
||||
m_verticalLayout->addLayout(m_horizontalLayout);
|
||||
m_verticalLayout->addLayout(m_horizontalLayout);
|
||||
|
||||
retranslate();
|
||||
retranslate();
|
||||
|
||||
QObject::connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
|
||||
QObject::connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
||||
QObject::connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
|
||||
QObject::connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
||||
|
||||
QMetaObject::connectSlotsByName(this);
|
||||
setWindowModality(Qt::WindowModal);
|
||||
setWindowTitle(title);
|
||||
QMetaObject::connectSlotsByName(this);
|
||||
setWindowModality(Qt::WindowModal);
|
||||
setWindowTitle(title);
|
||||
|
||||
m_vlist = vlist;
|
||||
m_vlist = vlist;
|
||||
|
||||
if (!cancelable)
|
||||
{
|
||||
m_buttonBox->button(QDialogButtonBox::Cancel)->setEnabled(false);
|
||||
}
|
||||
if (!cancelable)
|
||||
{
|
||||
m_buttonBox->button(QDialogButtonBox::Cancel)->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void VersionSelectDialog::retranslate()
|
||||
{
|
||||
// FIXME: overrides custom title given in constructor!
|
||||
setWindowTitle(tr("Choose Version"));
|
||||
m_refreshButton->setToolTip(tr("Reloads the version list."));
|
||||
m_refreshButton->setText(tr("&Refresh"));
|
||||
// FIXME: overrides custom title given in constructor!
|
||||
setWindowTitle(tr("Choose Version"));
|
||||
m_refreshButton->setToolTip(tr("Reloads the version list."));
|
||||
m_refreshButton->setText(tr("&Refresh"));
|
||||
}
|
||||
|
||||
void VersionSelectDialog::setCurrentVersion(const QString& version)
|
||||
{
|
||||
m_currentVersion = version;
|
||||
m_versionWidget->setCurrentVersion(version);
|
||||
m_currentVersion = version;
|
||||
m_versionWidget->setCurrentVersion(version);
|
||||
}
|
||||
|
||||
void VersionSelectDialog::setEmptyString(QString emptyString)
|
||||
{
|
||||
m_versionWidget->setEmptyString(emptyString);
|
||||
m_versionWidget->setEmptyString(emptyString);
|
||||
}
|
||||
|
||||
void VersionSelectDialog::setEmptyErrorString(QString emptyErrorString)
|
||||
{
|
||||
m_versionWidget->setEmptyErrorString(emptyErrorString);
|
||||
m_versionWidget->setEmptyErrorString(emptyErrorString);
|
||||
}
|
||||
|
||||
void VersionSelectDialog::setResizeOn(int column)
|
||||
{
|
||||
resizeOnColumn = column;
|
||||
resizeOnColumn = column;
|
||||
}
|
||||
|
||||
int VersionSelectDialog::exec()
|
||||
{
|
||||
QDialog::open();
|
||||
m_versionWidget->initialize(m_vlist);
|
||||
if(resizeOnColumn != -1)
|
||||
{
|
||||
m_versionWidget->setResizeOn(resizeOnColumn);
|
||||
}
|
||||
return QDialog::exec();
|
||||
QDialog::open();
|
||||
m_versionWidget->initialize(m_vlist);
|
||||
if(resizeOnColumn != -1)
|
||||
{
|
||||
m_versionWidget->setResizeOn(resizeOnColumn);
|
||||
}
|
||||
return QDialog::exec();
|
||||
}
|
||||
|
||||
void VersionSelectDialog::selectRecommended()
|
||||
{
|
||||
m_versionWidget->selectRecommended();
|
||||
m_versionWidget->selectRecommended();
|
||||
}
|
||||
|
||||
BaseVersionPtr VersionSelectDialog::selectedVersion() const
|
||||
{
|
||||
return m_versionWidget->selectedVersion();
|
||||
return m_versionWidget->selectedVersion();
|
||||
}
|
||||
|
||||
void VersionSelectDialog::on_refreshButton_clicked()
|
||||
{
|
||||
m_versionWidget->loadList();
|
||||
m_versionWidget->loadList();
|
||||
}
|
||||
|
||||
void VersionSelectDialog::setExactFilter(BaseVersionList::ModelRoles role, QString filter)
|
||||
{
|
||||
m_versionWidget->setExactFilter(role, filter);
|
||||
m_versionWidget->setExactFilter(role, filter);
|
||||
}
|
||||
|
||||
void VersionSelectDialog::setFuzzyFilter(BaseVersionList::ModelRoles role, QString filter)
|
||||
{
|
||||
m_versionWidget->setFuzzyFilter(role, filter);
|
||||
m_versionWidget->setFuzzyFilter(role, filter);
|
||||
}
|
||||
|
@ -36,43 +36,43 @@ class VersionProxyModel;
|
||||
|
||||
class VersionSelectDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit VersionSelectDialog(BaseVersionList *vlist, QString title, QWidget *parent = 0, bool cancelable = true);
|
||||
virtual ~VersionSelectDialog() {};
|
||||
explicit VersionSelectDialog(BaseVersionList *vlist, QString title, QWidget *parent = 0, bool cancelable = true);
|
||||
virtual ~VersionSelectDialog() {};
|
||||
|
||||
int exec() override;
|
||||
int exec() override;
|
||||
|
||||
BaseVersionPtr selectedVersion() const;
|
||||
BaseVersionPtr selectedVersion() const;
|
||||
|
||||
void setCurrentVersion(const QString & version);
|
||||
void setFuzzyFilter(BaseVersionList::ModelRoles role, QString filter);
|
||||
void setExactFilter(BaseVersionList::ModelRoles role, QString filter);
|
||||
void setEmptyString(QString emptyString);
|
||||
void setEmptyErrorString(QString emptyErrorString);
|
||||
void setResizeOn(int column);
|
||||
void setCurrentVersion(const QString & version);
|
||||
void setFuzzyFilter(BaseVersionList::ModelRoles role, QString filter);
|
||||
void setExactFilter(BaseVersionList::ModelRoles role, QString filter);
|
||||
void setEmptyString(QString emptyString);
|
||||
void setEmptyErrorString(QString emptyErrorString);
|
||||
void setResizeOn(int column);
|
||||
|
||||
private slots:
|
||||
void on_refreshButton_clicked();
|
||||
void on_refreshButton_clicked();
|
||||
|
||||
private:
|
||||
void retranslate();
|
||||
void selectRecommended();
|
||||
void retranslate();
|
||||
void selectRecommended();
|
||||
|
||||
private:
|
||||
QString m_currentVersion;
|
||||
VersionSelectWidget *m_versionWidget = nullptr;
|
||||
QVBoxLayout *m_verticalLayout = nullptr;
|
||||
QHBoxLayout *m_horizontalLayout = nullptr;
|
||||
QPushButton *m_refreshButton = nullptr;
|
||||
QDialogButtonBox *m_buttonBox = nullptr;
|
||||
QString m_currentVersion;
|
||||
VersionSelectWidget *m_versionWidget = nullptr;
|
||||
QVBoxLayout *m_verticalLayout = nullptr;
|
||||
QHBoxLayout *m_horizontalLayout = nullptr;
|
||||
QPushButton *m_refreshButton = nullptr;
|
||||
QDialogButtonBox *m_buttonBox = nullptr;
|
||||
|
||||
BaseVersionList *m_vlist = nullptr;
|
||||
BaseVersionList *m_vlist = nullptr;
|
||||
|
||||
VersionProxyModel *m_proxyModel = nullptr;
|
||||
VersionProxyModel *m_proxyModel = nullptr;
|
||||
|
||||
int resizeOnColumn = -1;
|
||||
int resizeOnColumn = -1;
|
||||
|
||||
Task * loadTask = nullptr;
|
||||
Task * loadTask = nullptr;
|
||||
};
|
||||
|
Reference in New Issue
Block a user