NOISSUE tabs -> spaces

This commit is contained in:
Petr Mrázek
2018-07-15 14:51:05 +02:00
parent 03280cc62e
commit bbb3b3e6f6
577 changed files with 51938 additions and 51938 deletions

View File

@ -5,50 +5,50 @@ Config BuildConfig;
Config::Config()
{
// Version information
VERSION_MAJOR = @MultiMC_VERSION_MAJOR@;
VERSION_MINOR = @MultiMC_VERSION_MINOR@;
VERSION_HOTFIX = @MultiMC_VERSION_HOTFIX@;
VERSION_BUILD = @MultiMC_VERSION_BUILD@;
// Version information
VERSION_MAJOR = @MultiMC_VERSION_MAJOR@;
VERSION_MINOR = @MultiMC_VERSION_MINOR@;
VERSION_HOTFIX = @MultiMC_VERSION_HOTFIX@;
VERSION_BUILD = @MultiMC_VERSION_BUILD@;
BUILD_PLATFORM = "@MultiMC_BUILD_PLATFORM@";
CHANLIST_URL = "@MultiMC_CHANLIST_URL@";
ANALYTICS_ID = "@MultiMC_ANALYTICS_ID@";
NOTIFICATION_URL = "@MultiMC_NOTIFICATION_URL@";
FULL_VERSION_STR = "@MultiMC_VERSION_MAJOR@.@MultiMC_VERSION_MINOR@.@MultiMC_VERSION_BUILD@";
BUILD_PLATFORM = "@MultiMC_BUILD_PLATFORM@";
CHANLIST_URL = "@MultiMC_CHANLIST_URL@";
ANALYTICS_ID = "@MultiMC_ANALYTICS_ID@";
NOTIFICATION_URL = "@MultiMC_NOTIFICATION_URL@";
FULL_VERSION_STR = "@MultiMC_VERSION_MAJOR@.@MultiMC_VERSION_MINOR@.@MultiMC_VERSION_BUILD@";
GIT_COMMIT = "@MultiMC_GIT_COMMIT@";
GIT_REFSPEC = "@MultiMC_GIT_REFSPEC@";
if(GIT_REFSPEC.startsWith("refs/heads/") && !CHANLIST_URL.isEmpty() && VERSION_BUILD >= 0)
{
VERSION_CHANNEL = GIT_REFSPEC;
VERSION_CHANNEL.remove("refs/heads/");
UPDATER_ENABLED = true;
}
else
{
VERSION_CHANNEL = QObject::tr("custom");
}
GIT_COMMIT = "@MultiMC_GIT_COMMIT@";
GIT_REFSPEC = "@MultiMC_GIT_REFSPEC@";
if(GIT_REFSPEC.startsWith("refs/heads/") && !CHANLIST_URL.isEmpty() && VERSION_BUILD >= 0)
{
VERSION_CHANNEL = GIT_REFSPEC;
VERSION_CHANNEL.remove("refs/heads/");
UPDATER_ENABLED = true;
}
else
{
VERSION_CHANNEL = QObject::tr("custom");
}
VERSION_STR = "@MultiMC_VERSION_STRING@";
NEWS_RSS_URL = "@MultiMC_NEWS_RSS_URL@";
PASTE_EE_KEY = "@MultiMC_PASTE_EE_API_KEY@";
VERSION_STR = "@MultiMC_VERSION_STRING@";
NEWS_RSS_URL = "@MultiMC_NEWS_RSS_URL@";
PASTE_EE_KEY = "@MultiMC_PASTE_EE_API_KEY@";
}
QString Config::printableVersionString() const
{
QString vstr = QString("%1.%2.%3").arg(QString::number(VERSION_MAJOR), QString::number(VERSION_MINOR), QString::number(VERSION_HOTFIX));
QString vstr = QString("%1.%2.%3").arg(QString::number(VERSION_MAJOR), QString::number(VERSION_MINOR), QString::number(VERSION_HOTFIX));
// If the build is not a main release, append the channel
if(VERSION_CHANNEL != "stable")
{
vstr += "-" + VERSION_CHANNEL;
}
// If the build is not a main release, append the channel
if(VERSION_CHANNEL != "stable")
{
vstr += "-" + VERSION_CHANNEL;
}
// if a build number is set, also add it to the end
if(VERSION_BUILD >= 0)
{
vstr += "-" + QString::number(VERSION_BUILD);
}
return vstr;
// if a build number is set, also add it to the end
if(VERSION_BUILD >= 0)
{
vstr += "-" + QString::number(VERSION_BUILD);
}
return vstr;
}

View File

@ -7,64 +7,64 @@
class Config
{
public:
Config();
/// The major version number.
int VERSION_MAJOR;
/// The minor version number.
int VERSION_MINOR;
/// The hotfix number.
int VERSION_HOTFIX;
/// The build number.
int VERSION_BUILD;
Config();
/// The major version number.
int VERSION_MAJOR;
/// The minor version number.
int VERSION_MINOR;
/// The hotfix number.
int VERSION_HOTFIX;
/// The build number.
int VERSION_BUILD;
/**
* The version channel
* This is used by the updater to determine what channel the current version came from.
*/
QString VERSION_CHANNEL;
/**
* The version channel
* This is used by the updater to determine what channel the current version came from.
*/
QString VERSION_CHANNEL;
bool UPDATER_ENABLED = false;
bool UPDATER_ENABLED = false;
/// A short string identifying this build's platform. For example, "lin64" or "win32".
QString BUILD_PLATFORM;
/// A short string identifying this build's platform. For example, "lin64" or "win32".
QString BUILD_PLATFORM;
/// URL for the updater's channel
QString CHANLIST_URL;
/// URL for the updater's channel
QString CHANLIST_URL;
/// Google analytics ID
QString ANALYTICS_ID;
/// Google analytics ID
QString ANALYTICS_ID;
/// URL for notifications
QString NOTIFICATION_URL;
/// URL for notifications
QString NOTIFICATION_URL;
/// Used for matching notifications
QString FULL_VERSION_STR;
/// Used for matching notifications
QString FULL_VERSION_STR;
/// The git commit hash of this build
QString GIT_COMMIT;
/// The git commit hash of this build
QString GIT_COMMIT;
/// The git refspec of this build
QString GIT_REFSPEC;
/// The git refspec of this build
QString GIT_REFSPEC;
/// This is printed on start to standard output
QString VERSION_STR;
/// This is printed on start to standard output
QString VERSION_STR;
/**
* This is used to fetch the news RSS feed.
* It defaults in CMakeLists.txt to "http://multimc.org/rss.xml"
*/
QString NEWS_RSS_URL;
/**
* This is used to fetch the news RSS feed.
* It defaults in CMakeLists.txt to "http://multimc.org/rss.xml"
*/
QString NEWS_RSS_URL;
/**
* API key you can get from paste.ee when you register an account
*/
QString PASTE_EE_KEY;
/**
* API key you can get from paste.ee when you register an account
*/
QString PASTE_EE_KEY;
/**
* \brief Converts the Version to a string.
* \return The version number in string format (major.minor.revision.build).
*/
QString printableVersionString() const;
/**
* \brief Converts the Version to a string.
* \return The version number in string format (major.minor.revision.build).
*/
QString printableVersionString() const;
};
extern Config BuildConfig;

View File

@ -6,13 +6,13 @@
*/
QColor ColorCache::blend(QColor color)
{
if (Rainbow::luma(m_front) > Rainbow::luma(m_back))
{
// for dark color schemes, produce a fitting color first
color = Rainbow::tint(m_front, color, 0.5);
}
// adapt contrast
return Rainbow::mix(m_front, color, m_bias);
if (Rainbow::luma(m_front) > Rainbow::luma(m_back))
{
// for dark color schemes, produce a fitting color first
color = Rainbow::tint(m_front, color, 0.5);
}
// adapt contrast
return Rainbow::mix(m_front, color, m_bias);
}
/**
@ -20,16 +20,16 @@ QColor ColorCache::blend(QColor color)
*/
QColor ColorCache::blendBackground(QColor color)
{
// adapt contrast
return Rainbow::mix(m_back, color, m_bias);
// adapt contrast
return Rainbow::mix(m_back, color, m_bias);
}
void ColorCache::recolorAll()
{
auto iter = m_colors.begin();
while(iter != m_colors.end())
{
iter->front = blend(iter->original);
iter->back = blendBackground(iter->original);
}
auto iter = m_colors.begin();
while(iter != m_colors.end())
{
iter->front = blend(iter->original);
iter->back = blendBackground(iter->original);
}
}

View File

@ -7,113 +7,113 @@
class ColorCache
{
public:
ColorCache(QColor front, QColor back, qreal bias)
{
m_front = front;
m_back = back;
m_bias = bias;
};
ColorCache(QColor front, QColor back, qreal bias)
{
m_front = front;
m_back = back;
m_bias = bias;
};
void addColor(int key, QColor color)
{
m_colors[key] = {color, blend(color), blendBackground(color)};
}
void addColor(int key, QColor color)
{
m_colors[key] = {color, blend(color), blendBackground(color)};
}
void setForeground(QColor front)
{
if(m_front != front)
{
m_front = front;
recolorAll();
}
}
void setForeground(QColor front)
{
if(m_front != front)
{
m_front = front;
recolorAll();
}
}
void setBackground(QColor back)
{
if(m_back != back)
{
m_back = back;
recolorAll();
}
}
void setBackground(QColor back)
{
if(m_back != back)
{
m_back = back;
recolorAll();
}
}
QColor getFront(int key)
{
auto iter = m_colors.find(key);
if(iter == m_colors.end())
{
return QColor();
}
return (*iter).front;
}
QColor getFront(int key)
{
auto iter = m_colors.find(key);
if(iter == m_colors.end())
{
return QColor();
}
return (*iter).front;
}
QColor getBack(int key)
{
auto iter = m_colors.find(key);
if(iter == m_colors.end())
{
return QColor();
}
return (*iter).back;
}
QColor getBack(int key)
{
auto iter = m_colors.find(key);
if(iter == m_colors.end())
{
return QColor();
}
return (*iter).back;
}
/**
* Blend the color with the front color, adapting to the back color
*/
QColor blend(QColor color);
/**
* Blend the color with the front color, adapting to the back color
*/
QColor blend(QColor color);
/**
* Blend the color with the back color
*/
QColor blendBackground(QColor color);
/**
* Blend the color with the back color
*/
QColor blendBackground(QColor color);
protected:
void recolorAll();
void recolorAll();
protected:
struct ColorEntry
{
QColor original;
QColor front;
QColor back;
};
struct ColorEntry
{
QColor original;
QColor front;
QColor back;
};
protected:
qreal m_bias;
QColor m_front;
QColor m_back;
QMap<int, ColorEntry> m_colors;
qreal m_bias;
QColor m_front;
QColor m_back;
QMap<int, ColorEntry> m_colors;
};
class LogColorCache : public ColorCache
{
public:
LogColorCache(QColor front, QColor back)
: ColorCache(front, back, 1.0)
{
addColor((int)MessageLevel::MultiMC, QColor("purple"));
addColor((int)MessageLevel::Debug, QColor("green"));
addColor((int)MessageLevel::Warning, QColor("orange"));
addColor((int)MessageLevel::Error, QColor("red"));
addColor((int)MessageLevel::Fatal, QColor("red"));
addColor((int)MessageLevel::Message, front);
}
LogColorCache(QColor front, QColor back)
: ColorCache(front, back, 1.0)
{
addColor((int)MessageLevel::MultiMC, QColor("purple"));
addColor((int)MessageLevel::Debug, QColor("green"));
addColor((int)MessageLevel::Warning, QColor("orange"));
addColor((int)MessageLevel::Error, QColor("red"));
addColor((int)MessageLevel::Fatal, QColor("red"));
addColor((int)MessageLevel::Message, front);
}
QColor getFront(MessageLevel::Enum level)
{
if(!m_colors.contains((int) level))
{
return ColorCache::getFront((int)MessageLevel::Message);
}
return ColorCache::getFront((int)level);
}
QColor getFront(MessageLevel::Enum level)
{
if(!m_colors.contains((int) level))
{
return ColorCache::getFront((int)MessageLevel::Message);
}
return ColorCache::getFront((int)level);
}
QColor getBack(MessageLevel::Enum level)
{
if(level == MessageLevel::Fatal)
{
return QColor(Qt::black);
}
return QColor(Qt::transparent);
}
QColor getBack(MessageLevel::Enum level)
{
if(level == MessageLevel::Fatal)
{
return QColor(Qt::black);
}
return QColor(Qt::transparent);
}
};

View File

@ -14,67 +14,67 @@
class FormLayoutWidgetItem : public QWidgetItem
{
public:
FormLayoutWidgetItem(QWidget* widget, QFormLayout* formLayout, QFormLayout::ItemRole itemRole)
: QWidgetItem(widget)
, m_width(-1)
, m_formLayout(formLayout)
, m_itemRole(itemRole)
{}
FormLayoutWidgetItem(QWidget* widget, QFormLayout* formLayout, QFormLayout::ItemRole itemRole)
: QWidgetItem(widget)
, m_width(-1)
, m_formLayout(formLayout)
, m_itemRole(itemRole)
{}
QSize sizeHint() const
{
QSize size = QWidgetItem::sizeHint();
if (m_width != -1) {
size.setWidth(m_width);
}
return size;
}
QSize sizeHint() const
{
QSize size = QWidgetItem::sizeHint();
if (m_width != -1) {
size.setWidth(m_width);
}
return size;
}
QSize minimumSize() const
{
QSize size = QWidgetItem::minimumSize();
if (m_width != -1) {
size.setWidth(m_width);
}
return size;
}
QSize minimumSize() const
{
QSize size = QWidgetItem::minimumSize();
if (m_width != -1) {
size.setWidth(m_width);
}
return size;
}
QSize maximumSize() const
{
QSize size = QWidgetItem::maximumSize();
if (m_width != -1) {
size.setWidth(m_width);
}
return size;
}
QSize maximumSize() const
{
QSize size = QWidgetItem::maximumSize();
if (m_width != -1) {
size.setWidth(m_width);
}
return size;
}
void setWidth(int width)
{
if (width != m_width) {
m_width = width;
invalidate();
}
}
void setWidth(int width)
{
if (width != m_width) {
m_width = width;
invalidate();
}
}
void setGeometry(const QRect& _rect)
{
QRect rect = _rect;
int width = widget()->sizeHint().width();
if (m_itemRole == QFormLayout::LabelRole && m_formLayout->labelAlignment() & Qt::AlignRight) {
rect.setLeft(rect.right() - width);
}
QWidgetItem::setGeometry(rect);
}
void setGeometry(const QRect& _rect)
{
QRect rect = _rect;
int width = widget()->sizeHint().width();
if (m_itemRole == QFormLayout::LabelRole && m_formLayout->labelAlignment() & Qt::AlignRight) {
rect.setLeft(rect.right() - width);
}
QWidgetItem::setGeometry(rect);
}
QFormLayout* formLayout() const
{
return m_formLayout;
}
QFormLayout* formLayout() const
{
return m_formLayout;
}
private:
int m_width;
QFormLayout* m_formLayout;
QFormLayout::ItemRole m_itemRole;
int m_width;
QFormLayout* m_formLayout;
QFormLayout::ItemRole m_itemRole;
};
typedef QPair<QGridLayout*, int> GridColumnInfo;
@ -82,25 +82,25 @@ typedef QPair<QGridLayout*, int> GridColumnInfo;
class ColumnResizerPrivate
{
public:
ColumnResizerPrivate(ColumnResizer* q_ptr)
: q(q_ptr)
, m_updateTimer(new QTimer(q))
{
m_updateTimer->setSingleShot(true);
m_updateTimer->setInterval(0);
QObject::connect(m_updateTimer, SIGNAL(timeout()), q, SLOT(updateWidth()));
}
ColumnResizerPrivate(ColumnResizer* q_ptr)
: q(q_ptr)
, m_updateTimer(new QTimer(q))
{
m_updateTimer->setSingleShot(true);
m_updateTimer->setInterval(0);
QObject::connect(m_updateTimer, SIGNAL(timeout()), q, SLOT(updateWidth()));
}
void scheduleWidthUpdate()
{
m_updateTimer->start();
}
void scheduleWidthUpdate()
{
m_updateTimer->start();
}
ColumnResizer* q;
QTimer* m_updateTimer;
QList<QWidget*> m_widgets;
QList<FormLayoutWidgetItem*> m_wrWidgetItemList;
QList<GridColumnInfo> m_gridColumnInfoList;
ColumnResizer* q;
QTimer* m_updateTimer;
QList<QWidget*> m_widgets;
QList<FormLayoutWidgetItem*> m_wrWidgetItemList;
QList<GridColumnInfo> m_gridColumnInfoList;
};
ColumnResizer::ColumnResizer(QObject* parent)
@ -110,90 +110,90 @@ ColumnResizer::ColumnResizer(QObject* parent)
ColumnResizer::~ColumnResizer()
{
delete d;
delete d;
}
void ColumnResizer::addWidget(QWidget* widget)
{
d->m_widgets.append(widget);
widget->installEventFilter(this);
d->scheduleWidthUpdate();
d->m_widgets.append(widget);
widget->installEventFilter(this);
d->scheduleWidthUpdate();
}
void ColumnResizer::updateWidth()
{
int width = 0;
Q_FOREACH(QWidget* widget, d->m_widgets) {
width = qMax(widget->sizeHint().width(), width);
}
Q_FOREACH(FormLayoutWidgetItem* item, d->m_wrWidgetItemList) {
item->setWidth(width);
item->formLayout()->update();
}
Q_FOREACH(GridColumnInfo info, d->m_gridColumnInfoList) {
info.first->setColumnMinimumWidth(info.second, width);
}
int width = 0;
Q_FOREACH(QWidget* widget, d->m_widgets) {
width = qMax(widget->sizeHint().width(), width);
}
Q_FOREACH(FormLayoutWidgetItem* item, d->m_wrWidgetItemList) {
item->setWidth(width);
item->formLayout()->update();
}
Q_FOREACH(GridColumnInfo info, d->m_gridColumnInfoList) {
info.first->setColumnMinimumWidth(info.second, width);
}
}
bool ColumnResizer::eventFilter(QObject*, QEvent* event)
{
if (event->type() == QEvent::Resize) {
d->scheduleWidthUpdate();
}
return false;
if (event->type() == QEvent::Resize) {
d->scheduleWidthUpdate();
}
return false;
}
void ColumnResizer::addWidgetsFromLayout(QLayout* layout, int column)
{
Q_ASSERT(column >= 0);
QGridLayout* gridLayout = qobject_cast<QGridLayout*>(layout);
QFormLayout* formLayout = qobject_cast<QFormLayout*>(layout);
if (gridLayout) {
addWidgetsFromGridLayout(gridLayout, column);
} else if (formLayout) {
if (column > QFormLayout::SpanningRole) {
qCritical() << "column should not be more than" << QFormLayout::SpanningRole << "for QFormLayout";
return;
}
QFormLayout::ItemRole role = static_cast<QFormLayout::ItemRole>(column);
addWidgetsFromFormLayout(formLayout, role);
} else {
qCritical() << "Don't know how to handle layout" << layout;
}
Q_ASSERT(column >= 0);
QGridLayout* gridLayout = qobject_cast<QGridLayout*>(layout);
QFormLayout* formLayout = qobject_cast<QFormLayout*>(layout);
if (gridLayout) {
addWidgetsFromGridLayout(gridLayout, column);
} else if (formLayout) {
if (column > QFormLayout::SpanningRole) {
qCritical() << "column should not be more than" << QFormLayout::SpanningRole << "for QFormLayout";
return;
}
QFormLayout::ItemRole role = static_cast<QFormLayout::ItemRole>(column);
addWidgetsFromFormLayout(formLayout, role);
} else {
qCritical() << "Don't know how to handle layout" << layout;
}
}
void ColumnResizer::addWidgetsFromGridLayout(QGridLayout* layout, int column)
{
for (int row = 0; row < layout->rowCount(); ++row) {
QLayoutItem* item = layout->itemAtPosition(row, column);
if (!item) {
continue;
}
QWidget* widget = item->widget();
if (!widget) {
continue;
}
addWidget(widget);
}
d->m_gridColumnInfoList << GridColumnInfo(layout, column);
for (int row = 0; row < layout->rowCount(); ++row) {
QLayoutItem* item = layout->itemAtPosition(row, column);
if (!item) {
continue;
}
QWidget* widget = item->widget();
if (!widget) {
continue;
}
addWidget(widget);
}
d->m_gridColumnInfoList << GridColumnInfo(layout, column);
}
void ColumnResizer::addWidgetsFromFormLayout(QFormLayout* layout, QFormLayout::ItemRole role)
{
for (int row = 0; row < layout->rowCount(); ++row) {
QLayoutItem* item = layout->itemAt(row, role);
if (!item) {
continue;
}
QWidget* widget = item->widget();
if (!widget) {
continue;
}
layout->removeItem(item);
delete item;
FormLayoutWidgetItem* newItem = new FormLayoutWidgetItem(widget, layout, role);
layout->setItem(row, role, newItem);
addWidget(widget);
d->m_wrWidgetItemList << newItem;
}
for (int row = 0; row < layout->rowCount(); ++row) {
QLayoutItem* item = layout->itemAt(row, role);
if (!item) {
continue;
}
QWidget* widget = item->widget();
if (!widget) {
continue;
}
layout->removeItem(item);
delete item;
FormLayoutWidgetItem* newItem = new FormLayoutWidgetItem(widget, layout, role);
layout->setItem(row, role, newItem);
addWidget(widget);
d->m_wrWidgetItemList << newItem;
}
}

View File

@ -18,24 +18,24 @@ class QWidget;
class ColumnResizerPrivate;
class ColumnResizer : public QObject
{
Q_OBJECT
Q_OBJECT
public:
ColumnResizer(QObject* parent = 0);
~ColumnResizer();
ColumnResizer(QObject* parent = 0);
~ColumnResizer();
void addWidget(QWidget* widget);
void addWidgetsFromLayout(QLayout*, int column);
void addWidgetsFromGridLayout(QGridLayout*, int column);
void addWidgetsFromFormLayout(QFormLayout*, QFormLayout::ItemRole role);
void addWidget(QWidget* widget);
void addWidgetsFromLayout(QLayout*, int column);
void addWidgetsFromGridLayout(QGridLayout*, int column);
void addWidgetsFromFormLayout(QFormLayout*, QFormLayout::ItemRole role);
private Q_SLOTS:
void updateWidth();
void updateWidth();
protected:
bool eventFilter(QObject*, QEvent* event);
bool eventFilter(QObject*, QEvent* event);
private:
ColumnResizerPrivate* const d;
ColumnResizerPrivate* const d;
};
#endif /* COLUMNRESIZER_H */

View File

@ -15,117 +15,117 @@
QString GuiUtil::uploadPaste(const QString &text, QWidget *parentWidget)
{
ProgressDialog dialog(parentWidget);
auto APIKeySetting = MMC->settings()->get("PasteEEAPIKey").toString();
if(APIKeySetting == "multimc")
{
APIKeySetting = BuildConfig.PASTE_EE_KEY;
}
std::unique_ptr<PasteUpload> paste(new PasteUpload(parentWidget, text, APIKeySetting));
ProgressDialog dialog(parentWidget);
auto APIKeySetting = MMC->settings()->get("PasteEEAPIKey").toString();
if(APIKeySetting == "multimc")
{
APIKeySetting = BuildConfig.PASTE_EE_KEY;
}
std::unique_ptr<PasteUpload> paste(new PasteUpload(parentWidget, text, APIKeySetting));
if (!paste->validateText())
{
CustomMessageBox::selectable(
parentWidget, QObject::tr("Upload failed"),
QObject::tr("The log file is too big. You'll have to upload it manually."),
QMessageBox::Warning)->exec();
return QString();
}
if (!paste->validateText())
{
CustomMessageBox::selectable(
parentWidget, QObject::tr("Upload failed"),
QObject::tr("The log file is too big. You'll have to upload it manually."),
QMessageBox::Warning)->exec();
return QString();
}
dialog.execWithTask(paste.get());
if (!paste->wasSuccessful())
{
CustomMessageBox::selectable(parentWidget, QObject::tr("Upload failed"),
paste->failReason(), QMessageBox::Critical)->exec();
return QString();
}
else
{
const QString link = paste->pasteLink();
setClipboardText(link);
CustomMessageBox::selectable(
parentWidget, QObject::tr("Upload finished"),
QObject::tr("The <a href=\"%1\">link to the uploaded log</a> has been placed in your clipboard.").arg(link),
QMessageBox::Information)->exec();
return link;
}
dialog.execWithTask(paste.get());
if (!paste->wasSuccessful())
{
CustomMessageBox::selectable(parentWidget, QObject::tr("Upload failed"),
paste->failReason(), QMessageBox::Critical)->exec();
return QString();
}
else
{
const QString link = paste->pasteLink();
setClipboardText(link);
CustomMessageBox::selectable(
parentWidget, QObject::tr("Upload finished"),
QObject::tr("The <a href=\"%1\">link to the uploaded log</a> has been placed in your clipboard.").arg(link),
QMessageBox::Information)->exec();
return link;
}
}
void GuiUtil::setClipboardText(const QString &text)
{
QApplication::clipboard()->setText(text);
QApplication::clipboard()->setText(text);
}
static QStringList BrowseForFileInternal(QString context, QString caption, QString filter, QString defaultPath, QWidget *parentWidget, bool single)
{
static QMap<QString, QString> savedPaths;
static QMap<QString, QString> savedPaths;
QFileDialog w(parentWidget, caption);
QSet<QString> locations;
auto f = [&](QStandardPaths::StandardLocation l)
{
QString location = QStandardPaths::writableLocation(l);
QFileInfo finfo(location);
if (!finfo.exists())
return;
locations.insert(location);
};
f(QStandardPaths::DesktopLocation);
f(QStandardPaths::DocumentsLocation);
f(QStandardPaths::DownloadLocation);
f(QStandardPaths::HomeLocation);
QList<QUrl> urls;
for (auto location : locations)
{
urls.append(QUrl::fromLocalFile(location));
}
urls.append(QUrl::fromLocalFile(defaultPath));
QFileDialog w(parentWidget, caption);
QSet<QString> locations;
auto f = [&](QStandardPaths::StandardLocation l)
{
QString location = QStandardPaths::writableLocation(l);
QFileInfo finfo(location);
if (!finfo.exists())
return;
locations.insert(location);
};
f(QStandardPaths::DesktopLocation);
f(QStandardPaths::DocumentsLocation);
f(QStandardPaths::DownloadLocation);
f(QStandardPaths::HomeLocation);
QList<QUrl> urls;
for (auto location : locations)
{
urls.append(QUrl::fromLocalFile(location));
}
urls.append(QUrl::fromLocalFile(defaultPath));
w.setFileMode(single ? QFileDialog::ExistingFile : QFileDialog::ExistingFiles);
w.setAcceptMode(QFileDialog::AcceptOpen);
w.setNameFilter(filter);
w.setFileMode(single ? QFileDialog::ExistingFile : QFileDialog::ExistingFiles);
w.setAcceptMode(QFileDialog::AcceptOpen);
w.setNameFilter(filter);
QString pathToOpen;
if(savedPaths.contains(context))
{
pathToOpen = savedPaths[context];
}
else
{
pathToOpen = defaultPath;
}
if(!pathToOpen.isEmpty())
{
QFileInfo finfo(pathToOpen);
if(finfo.exists() && finfo.isDir())
{
w.setDirectory(finfo.absoluteFilePath());
}
}
QString pathToOpen;
if(savedPaths.contains(context))
{
pathToOpen = savedPaths[context];
}
else
{
pathToOpen = defaultPath;
}
if(!pathToOpen.isEmpty())
{
QFileInfo finfo(pathToOpen);
if(finfo.exists() && finfo.isDir())
{
w.setDirectory(finfo.absoluteFilePath());
}
}
w.setSidebarUrls(urls);
w.setSidebarUrls(urls);
if (w.exec())
{
savedPaths[context] = w.directory().absolutePath();
return w.selectedFiles();
}
savedPaths[context] = w.directory().absolutePath();
return {};
if (w.exec())
{
savedPaths[context] = w.directory().absolutePath();
return w.selectedFiles();
}
savedPaths[context] = w.directory().absolutePath();
return {};
}
QString GuiUtil::BrowseForFile(QString context, QString caption, QString filter, QString defaultPath, QWidget *parentWidget)
{
auto resultList = BrowseForFileInternal(context, caption, filter, defaultPath, parentWidget, true);
if(resultList.size())
{
return resultList[0];
}
return QString();
auto resultList = BrowseForFileInternal(context, caption, filter, defaultPath, parentWidget, true);
if(resultList.size())
{
return resultList[0];
}
return QString();
}
QStringList GuiUtil::BrowseForFiles(QString context, QString caption, QString filter, QString defaultPath, QWidget *parentWidget)
{
return BrowseForFileInternal(context, caption, filter, defaultPath, parentWidget, false);
return BrowseForFileInternal(context, caption, filter, defaultPath, parentWidget, false);
}

View File

@ -25,52 +25,52 @@
class HoeDown
{
public:
class buffer
{
public:
buffer(size_t unit = 4096)
{
buf = hoedown_buffer_new(unit);
}
~buffer()
{
hoedown_buffer_free(buf);
}
const char * cstr()
{
return hoedown_buffer_cstr(buf);
}
void put(QByteArray input)
{
hoedown_buffer_put(buf, (uint8_t *) input.data(), input.size());
}
const uint8_t * data() const
{
return buf->data;
}
size_t size() const
{
return buf->size;
}
hoedown_buffer * buf;
} ib, ob;
HoeDown()
{
renderer = hoedown_html_renderer_new((hoedown_html_flags) 0,0);
document = hoedown_document_new(renderer, (hoedown_extensions) 0, 8);
}
~HoeDown()
{
hoedown_document_free(document);
hoedown_html_renderer_free(renderer);
}
QString process(QByteArray input)
{
ib.put(input);
hoedown_document_render(document, ob.buf, ib.data(), ib.size());
return ob.cstr();
}
class buffer
{
public:
buffer(size_t unit = 4096)
{
buf = hoedown_buffer_new(unit);
}
~buffer()
{
hoedown_buffer_free(buf);
}
const char * cstr()
{
return hoedown_buffer_cstr(buf);
}
void put(QByteArray input)
{
hoedown_buffer_put(buf, (uint8_t *) input.data(), input.size());
}
const uint8_t * data() const
{
return buf->data;
}
size_t size() const
{
return buf->size;
}
hoedown_buffer * buf;
} ib, ob;
HoeDown()
{
renderer = hoedown_html_renderer_new((hoedown_html_flags) 0,0);
document = hoedown_document_new(renderer, (hoedown_extensions) 0, 8);
}
~HoeDown()
{
hoedown_document_free(document);
hoedown_html_renderer_free(renderer);
}
QString process(QByteArray input)
{
ib.put(input);
hoedown_document_render(document, ob.buf, ib.data(), ib.size());
return ob.cstr();
}
private:
hoedown_document * document;
hoedown_renderer * renderer;
hoedown_document * document;
hoedown_renderer * renderer;
};

View File

@ -21,57 +21,57 @@
class InstancePageProvider : public QObject, public BasePageProvider
{
Q_OBJECT
Q_OBJECT
public:
explicit InstancePageProvider(InstancePtr parent)
{
inst = parent;
}
explicit InstancePageProvider(InstancePtr parent)
{
inst = parent;
}
virtual ~InstancePageProvider() {};
virtual QList<BasePage *> getPages() override
{
QList<BasePage *> values;
values.append(new LogPage(inst));
std::shared_ptr<MinecraftInstance> onesix = std::dynamic_pointer_cast<MinecraftInstance>(inst);
if(onesix)
{
values.append(new VersionPage(onesix.get()));
auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList(), "mods", "loadermods", tr("Loader mods"), "Loader-mods");
modsPage->setFilter("%1 (*.zip *.jar *.litemod)");
values.append(modsPage);
auto modsPage2 = new NewModFolderPage(onesix.get(), onesix->modsModel(), "newmods", "newloadermods", tr("New loader mods"), "New-loader-mods");
modsPage2->setFilter("%1 (*.zip *.jar *.litemod)");
values.append(modsPage2);
values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList(), "coremods", "coremods", tr("Core mods"), "Core-mods"));
values.append(new ResourcePackPage(onesix.get()));
values.append(new TexturePackPage(onesix.get()));
values.append(new NotesPage(onesix.get()));
values.append(new WorldListPage(onesix.get(), onesix->worldList(), "worlds", "worlds", tr("Worlds"), "Worlds"));
values.append(new ServersPage(onesix.get()));
values.append(new ScreenshotsPage(FS::PathCombine(onesix->minecraftRoot(), "screenshots")));
values.append(new InstanceSettingsPage(onesix.get()));
}
std::shared_ptr<LegacyInstance> legacy = std::dynamic_pointer_cast<LegacyInstance>(inst);
if(legacy)
{
values.append(new LegacyUpgradePage(legacy));
values.append(new NotesPage(legacy.get()));
values.append(new WorldListPage(legacy.get(), legacy->worldList(), "worlds", "worlds", tr("Worlds"), "Worlds"));
values.append(new ScreenshotsPage(FS::PathCombine(legacy->minecraftRoot(), "screenshots")));
}
auto logMatcher = inst->getLogFileMatcher();
if(logMatcher)
{
values.append(new OtherLogsPage(inst->getLogFileRoot(), logMatcher));
}
return values;
}
virtual ~InstancePageProvider() {};
virtual QList<BasePage *> getPages() override
{
QList<BasePage *> values;
values.append(new LogPage(inst));
std::shared_ptr<MinecraftInstance> onesix = std::dynamic_pointer_cast<MinecraftInstance>(inst);
if(onesix)
{
values.append(new VersionPage(onesix.get()));
auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList(), "mods", "loadermods", tr("Loader mods"), "Loader-mods");
modsPage->setFilter("%1 (*.zip *.jar *.litemod)");
values.append(modsPage);
auto modsPage2 = new NewModFolderPage(onesix.get(), onesix->modsModel(), "newmods", "newloadermods", tr("New loader mods"), "New-loader-mods");
modsPage2->setFilter("%1 (*.zip *.jar *.litemod)");
values.append(modsPage2);
values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList(), "coremods", "coremods", tr("Core mods"), "Core-mods"));
values.append(new ResourcePackPage(onesix.get()));
values.append(new TexturePackPage(onesix.get()));
values.append(new NotesPage(onesix.get()));
values.append(new WorldListPage(onesix.get(), onesix->worldList(), "worlds", "worlds", tr("Worlds"), "Worlds"));
values.append(new ServersPage(onesix.get()));
values.append(new ScreenshotsPage(FS::PathCombine(onesix->minecraftRoot(), "screenshots")));
values.append(new InstanceSettingsPage(onesix.get()));
}
std::shared_ptr<LegacyInstance> legacy = std::dynamic_pointer_cast<LegacyInstance>(inst);
if(legacy)
{
values.append(new LegacyUpgradePage(legacy));
values.append(new NotesPage(legacy.get()));
values.append(new WorldListPage(legacy.get(), legacy->worldList(), "worlds", "worlds", tr("Worlds"), "Worlds"));
values.append(new ScreenshotsPage(FS::PathCombine(legacy->minecraftRoot(), "screenshots")));
}
auto logMatcher = inst->getLogFileMatcher();
if(logMatcher)
{
values.append(new OtherLogsPage(inst->getLogFileRoot(), logMatcher));
}
return values;
}
virtual QString dialogTitle() override
{
return tr("Edit Instance (%1)").arg(inst->name());
}
virtual QString dialogTitle() override
{
return tr("Edit Instance (%1)").arg(inst->name());
}
protected:
InstancePtr inst;
InstancePtr inst;
};

View File

@ -9,26 +9,26 @@ InstanceProxyModel::InstanceProxyModel(QObject *parent) : GroupedProxyModel(pare
QVariant InstanceProxyModel::data(const QModelIndex & index, int role) const
{
QVariant data = QSortFilterProxyModel::data(index, role);
if(role == Qt::DecorationRole)
{
return QVariant(MMC->icons()->getIcon(data.toString()));
}
return data;
QVariant data = QSortFilterProxyModel::data(index, role);
if(role == Qt::DecorationRole)
{
return QVariant(MMC->icons()->getIcon(data.toString()));
}
return data;
}
bool InstanceProxyModel::subSortLessThan(const QModelIndex &left,
const QModelIndex &right) const
const QModelIndex &right) const
{
BaseInstance *pdataLeft = static_cast<BaseInstance *>(left.internalPointer());
BaseInstance *pdataRight = static_cast<BaseInstance *>(right.internalPointer());
QString sortMode = MMC->settings()->get("InstSortMode").toString();
if (sortMode == "LastLaunch")
{
return pdataLeft->lastLaunch() > pdataRight->lastLaunch();
}
else
{
return QString::localeAwareCompare(pdataLeft->name(), pdataRight->name()) < 0;
}
BaseInstance *pdataLeft = static_cast<BaseInstance *>(left.internalPointer());
BaseInstance *pdataRight = static_cast<BaseInstance *>(right.internalPointer());
QString sortMode = MMC->settings()->get("InstSortMode").toString();
if (sortMode == "LastLaunch")
{
return pdataLeft->lastLaunch() > pdataRight->lastLaunch();
}
else
{
return QString::localeAwareCompare(pdataLeft->name(), pdataRight->name()) < 0;
}
}

View File

@ -8,9 +8,9 @@
class InstanceProxyModel : public GroupedProxyModel
{
public:
explicit InstanceProxyModel(QObject *parent = 0);
QVariant data(const QModelIndex & index, int role) const override;
explicit InstanceProxyModel(QObject *parent = 0);
QVariant data(const QModelIndex & index, int role) const override;
protected:
virtual bool subSortLessThan(const QModelIndex &left, const QModelIndex &right) const override;
virtual bool subSortLessThan(const QModelIndex &left, const QModelIndex &right) const override;
};

View File

@ -31,184 +31,184 @@
#include "icons/IconList.h"
InstanceWindow::InstanceWindow(InstancePtr instance, QWidget *parent)
: QMainWindow(parent), m_instance(instance)
: QMainWindow(parent), m_instance(instance)
{
setAttribute(Qt::WA_DeleteOnClose);
setAttribute(Qt::WA_DeleteOnClose);
auto icon = MMC->icons()->getIcon(m_instance->iconKey());
QString windowTitle = tr("Console window for ") + m_instance->name();
auto icon = MMC->icons()->getIcon(m_instance->iconKey());
QString windowTitle = tr("Console window for ") + m_instance->name();
// Set window properties
{
setWindowIcon(icon);
setWindowTitle(windowTitle);
}
// Set window properties
{
setWindowIcon(icon);
setWindowTitle(windowTitle);
}
// Add page container
{
auto provider = std::make_shared<InstancePageProvider>(m_instance);
m_container = new PageContainer(provider.get(), "console", this);
m_container->setParentContainer(this);
setCentralWidget(m_container);
}
// Add page container
{
auto provider = std::make_shared<InstancePageProvider>(m_instance);
m_container = new PageContainer(provider.get(), "console", this);
m_container->setParentContainer(this);
setCentralWidget(m_container);
}
// Add custom buttons to the page container layout.
{
auto horizontalLayout = new QHBoxLayout();
horizontalLayout->setObjectName(QStringLiteral("horizontalLayout"));
horizontalLayout->setContentsMargins(6, -1, 6, -1);
// Add custom buttons to the page container layout.
{
auto horizontalLayout = new QHBoxLayout();
horizontalLayout->setObjectName(QStringLiteral("horizontalLayout"));
horizontalLayout->setContentsMargins(6, -1, 6, -1);
auto btnHelp = new QPushButton();
btnHelp->setText(tr("Help"));
horizontalLayout->addWidget(btnHelp);
connect(btnHelp, SIGNAL(clicked(bool)), m_container, SLOT(help()));
auto btnHelp = new QPushButton();
btnHelp->setText(tr("Help"));
horizontalLayout->addWidget(btnHelp);
connect(btnHelp, SIGNAL(clicked(bool)), m_container, SLOT(help()));
auto spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
horizontalLayout->addSpacerItem(spacer);
auto spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
horizontalLayout->addSpacerItem(spacer);
m_killButton = new QPushButton();
horizontalLayout->addWidget(m_killButton);
connect(m_killButton, SIGNAL(clicked(bool)), SLOT(on_btnKillMinecraft_clicked()));
m_killButton = new QPushButton();
horizontalLayout->addWidget(m_killButton);
connect(m_killButton, SIGNAL(clicked(bool)), SLOT(on_btnKillMinecraft_clicked()));
m_launchOfflineButton = new QPushButton();
horizontalLayout->addWidget(m_launchOfflineButton);
m_launchOfflineButton->setText(tr("Launch Offline"));
updateLaunchButtons();
connect(m_launchOfflineButton, SIGNAL(clicked(bool)), SLOT(on_btnLaunchMinecraftOffline_clicked()));
m_launchOfflineButton = new QPushButton();
horizontalLayout->addWidget(m_launchOfflineButton);
m_launchOfflineButton->setText(tr("Launch Offline"));
updateLaunchButtons();
connect(m_launchOfflineButton, SIGNAL(clicked(bool)), SLOT(on_btnLaunchMinecraftOffline_clicked()));
m_closeButton = new QPushButton();
m_closeButton->setText(tr("Close"));
horizontalLayout->addWidget(m_closeButton);
connect(m_closeButton, SIGNAL(clicked(bool)), SLOT(on_closeButton_clicked()));
m_closeButton = new QPushButton();
m_closeButton->setText(tr("Close"));
horizontalLayout->addWidget(m_closeButton);
connect(m_closeButton, SIGNAL(clicked(bool)), SLOT(on_closeButton_clicked()));
m_container->addButtons(horizontalLayout);
}
m_container->addButtons(horizontalLayout);
}
// restore window state
{
auto base64State = MMC->settings()->get("ConsoleWindowState").toByteArray();
restoreState(QByteArray::fromBase64(base64State));
auto base64Geometry = MMC->settings()->get("ConsoleWindowGeometry").toByteArray();
restoreGeometry(QByteArray::fromBase64(base64Geometry));
}
// restore window state
{
auto base64State = MMC->settings()->get("ConsoleWindowState").toByteArray();
restoreState(QByteArray::fromBase64(base64State));
auto base64Geometry = MMC->settings()->get("ConsoleWindowGeometry").toByteArray();
restoreGeometry(QByteArray::fromBase64(base64Geometry));
}
// set up instance and launch process recognition
{
auto launchTask = m_instance->getLaunchTask();
on_InstanceLaunchTask_changed(launchTask);
connect(m_instance.get(), &BaseInstance::launchTaskChanged, this, &InstanceWindow::on_InstanceLaunchTask_changed);
connect(m_instance.get(), &BaseInstance::runningStatusChanged, this, &InstanceWindow::on_RunningState_changed);
}
// set up instance and launch process recognition
{
auto launchTask = m_instance->getLaunchTask();
on_InstanceLaunchTask_changed(launchTask);
connect(m_instance.get(), &BaseInstance::launchTaskChanged, this, &InstanceWindow::on_InstanceLaunchTask_changed);
connect(m_instance.get(), &BaseInstance::runningStatusChanged, this, &InstanceWindow::on_RunningState_changed);
}
// set up instance destruction detection
{
connect(m_instance.get(), &BaseInstance::statusChanged, this, &InstanceWindow::on_instanceStatusChanged);
}
show();
// set up instance destruction detection
{
connect(m_instance.get(), &BaseInstance::statusChanged, this, &InstanceWindow::on_instanceStatusChanged);
}
show();
}
void InstanceWindow::on_instanceStatusChanged(BaseInstance::Status, BaseInstance::Status newStatus)
{
if(newStatus == BaseInstance::Status::Gone)
{
m_doNotSave = true;
close();
}
if(newStatus == BaseInstance::Status::Gone)
{
m_doNotSave = true;
close();
}
}
void InstanceWindow::updateLaunchButtons()
{
if(m_instance->isRunning())
{
m_launchOfflineButton->setEnabled(false);
m_killButton->setText(tr("Kill"));
m_killButton->setToolTip(tr("Kill the running instance"));
}
else if(!m_instance->canLaunch())
{
m_launchOfflineButton->setEnabled(false);
m_killButton->setText(tr("Launch"));
m_killButton->setToolTip(tr("Launch the instance"));
m_killButton->setEnabled(false);
}
else
{
m_launchOfflineButton->setEnabled(true);
m_killButton->setText(tr("Launch"));
m_killButton->setToolTip(tr("Launch the instance"));
}
if(m_instance->isRunning())
{
m_launchOfflineButton->setEnabled(false);
m_killButton->setText(tr("Kill"));
m_killButton->setToolTip(tr("Kill the running instance"));
}
else if(!m_instance->canLaunch())
{
m_launchOfflineButton->setEnabled(false);
m_killButton->setText(tr("Launch"));
m_killButton->setToolTip(tr("Launch the instance"));
m_killButton->setEnabled(false);
}
else
{
m_launchOfflineButton->setEnabled(true);
m_killButton->setText(tr("Launch"));
m_killButton->setToolTip(tr("Launch the instance"));
}
}
void InstanceWindow::on_btnLaunchMinecraftOffline_clicked()
{
MMC->launch(m_instance, false, nullptr);
MMC->launch(m_instance, false, nullptr);
}
void InstanceWindow::on_InstanceLaunchTask_changed(std::shared_ptr<LaunchTask> proc)
{
m_proc = proc;
m_proc = proc;
}
void InstanceWindow::on_RunningState_changed(bool)
{
updateLaunchButtons();
m_container->refreshContainer();
updateLaunchButtons();
m_container->refreshContainer();
}
void InstanceWindow::on_closeButton_clicked()
{
close();
close();
}
void InstanceWindow::closeEvent(QCloseEvent *event)
{
bool proceed = true;
if(!m_doNotSave)
{
proceed &= m_container->prepareToClose();
}
bool proceed = true;
if(!m_doNotSave)
{
proceed &= m_container->prepareToClose();
}
if(!proceed)
{
return;
}
if(!proceed)
{
return;
}
MMC->settings()->set("ConsoleWindowState", saveState().toBase64());
MMC->settings()->set("ConsoleWindowGeometry", saveGeometry().toBase64());
emit isClosing();
event->accept();
MMC->settings()->set("ConsoleWindowState", saveState().toBase64());
MMC->settings()->set("ConsoleWindowGeometry", saveGeometry().toBase64());
emit isClosing();
event->accept();
}
bool InstanceWindow::saveAll()
{
return m_container->saveAll();
return m_container->saveAll();
}
void InstanceWindow::on_btnKillMinecraft_clicked()
{
if(m_instance->isRunning())
{
MMC->kill(m_instance);
}
else
{
MMC->launch(m_instance, true, nullptr);
}
if(m_instance->isRunning())
{
MMC->kill(m_instance);
}
else
{
MMC->launch(m_instance, true, nullptr);
}
}
QString InstanceWindow::instanceId()
{
return m_instance->id();
return m_instance->id();
}
bool InstanceWindow::selectPage(QString pageId)
{
return m_container->selectPage(pageId);
return m_container->selectPage(pageId);
}
void InstanceWindow::refreshContainer()
{
m_container->refreshContainer();
m_container->refreshContainer();
}
InstanceWindow::~InstanceWindow()
@ -217,10 +217,10 @@ InstanceWindow::~InstanceWindow()
bool InstanceWindow::requestClose()
{
if(m_container->prepareToClose())
{
close();
return true;
}
return false;
if(m_container->prepareToClose())
{
close();
return true;
}
return false;
}

View File

@ -26,48 +26,48 @@ class QPushButton;
class PageContainer;
class InstanceWindow : public QMainWindow, public BasePageContainer
{
Q_OBJECT
Q_OBJECT
public:
explicit InstanceWindow(InstancePtr proc, QWidget *parent = 0);
virtual ~InstanceWindow();
explicit InstanceWindow(InstancePtr proc, QWidget *parent = 0);
virtual ~InstanceWindow();
bool selectPage(QString pageId) override;
void refreshContainer() override;
bool selectPage(QString pageId) override;
void refreshContainer() override;
QString instanceId();
QString instanceId();
// save all settings and changes (prepare for launch)
bool saveAll();
// save all settings and changes (prepare for launch)
bool saveAll();
// request closing the window (from a page)
bool requestClose() override;
// request closing the window (from a page)
bool requestClose() override;
signals:
void isClosing();
void isClosing();
private
slots:
void on_closeButton_clicked();
void on_btnKillMinecraft_clicked();
void on_btnLaunchMinecraftOffline_clicked();
void on_closeButton_clicked();
void on_btnKillMinecraft_clicked();
void on_btnLaunchMinecraftOffline_clicked();
void on_InstanceLaunchTask_changed(std::shared_ptr<LaunchTask> proc);
void on_RunningState_changed(bool running);
void on_instanceStatusChanged(BaseInstance::Status, BaseInstance::Status newStatus);
void on_InstanceLaunchTask_changed(std::shared_ptr<LaunchTask> proc);
void on_RunningState_changed(bool running);
void on_instanceStatusChanged(BaseInstance::Status, BaseInstance::Status newStatus);
protected:
void closeEvent(QCloseEvent *) override;
void closeEvent(QCloseEvent *) override;
private:
void updateLaunchButtons();
void updateLaunchButtons();
private:
std::shared_ptr<LaunchTask> m_proc;
InstancePtr m_instance;
bool m_doNotSave = false;
PageContainer *m_container = nullptr;
QPushButton *m_closeButton = nullptr;
QPushButton *m_killButton = nullptr;
QPushButton *m_launchOfflineButton = nullptr;
std::shared_ptr<LaunchTask> m_proc;
InstancePtr m_instance;
bool m_doNotSave = false;
PageContainer *m_container = nullptr;
QPushButton *m_closeButton = nullptr;
QPushButton *m_killButton = nullptr;
QPushButton *m_launchOfflineButton = nullptr;
};

View File

@ -4,100 +4,100 @@
bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget *parent)
{
if (jvmargs.contains("-XX:PermSize=") || jvmargs.contains(QRegExp("-Xm[sx]"))
|| jvmargs.contains("-XX-MaxHeapSize") || jvmargs.contains("-XX:InitialHeapSize"))
{
auto warnStr = QObject::tr(
"You tried to manually set a JVM memory option (using \"-XX:PermSize\", \"-XX-MaxHeapSize\", \"-XX:InitialHeapSize\", \"-Xmx\" or \"-Xms\").\n"
"There are dedicated boxes for these in the settings (Java tab, in the Memory group at the top).\n"
"This message will be displayed until you remove them from the JVM arguments.");
CustomMessageBox::selectable(
parent, QObject::tr("JVM arguments warning"),
warnStr,
QMessageBox::Warning)->exec();
return false;
}
return true;
if (jvmargs.contains("-XX:PermSize=") || jvmargs.contains(QRegExp("-Xm[sx]"))
|| jvmargs.contains("-XX-MaxHeapSize") || jvmargs.contains("-XX:InitialHeapSize"))
{
auto warnStr = QObject::tr(
"You tried to manually set a JVM memory option (using \"-XX:PermSize\", \"-XX-MaxHeapSize\", \"-XX:InitialHeapSize\", \"-Xmx\" or \"-Xms\").\n"
"There are dedicated boxes for these in the settings (Java tab, in the Memory group at the top).\n"
"This message will be displayed until you remove them from the JVM arguments.");
CustomMessageBox::selectable(
parent, QObject::tr("JVM arguments warning"),
warnStr,
QMessageBox::Warning)->exec();
return false;
}
return true;
}
void JavaCommon::javaWasOk(QWidget *parent, JavaCheckResult result)
{
QString text;
text += QObject::tr("Java test succeeded!<br />Platform reported: %1<br />Java version "
"reported: %2<br />").arg(result.realPlatform, result.javaVersion.toString());
if (result.errorLog.size())
{
auto htmlError = result.errorLog;
htmlError.replace('\n', "<br />");
text += QObject::tr("<br />Warnings:<br /><font color=\"orange\">%1</font>").arg(htmlError);
}
CustomMessageBox::selectable(parent, QObject::tr("Java test success"), text, QMessageBox::Information)->show();
QString text;
text += QObject::tr("Java test succeeded!<br />Platform reported: %1<br />Java version "
"reported: %2<br />").arg(result.realPlatform, result.javaVersion.toString());
if (result.errorLog.size())
{
auto htmlError = result.errorLog;
htmlError.replace('\n', "<br />");
text += QObject::tr("<br />Warnings:<br /><font color=\"orange\">%1</font>").arg(htmlError);
}
CustomMessageBox::selectable(parent, QObject::tr("Java test success"), text, QMessageBox::Information)->show();
}
void JavaCommon::javaArgsWereBad(QWidget *parent, JavaCheckResult result)
{
auto htmlError = result.errorLog;
QString text;
htmlError.replace('\n', "<br />");
text += QObject::tr("The specified java binary didn't work with the arguments you provided:<br />");
text += QString("<font color=\"red\">%1</font>").arg(htmlError);
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
auto htmlError = result.errorLog;
QString text;
htmlError.replace('\n', "<br />");
text += QObject::tr("The specified java binary didn't work with the arguments you provided:<br />");
text += QString("<font color=\"red\">%1</font>").arg(htmlError);
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
}
void JavaCommon::javaBinaryWasBad(QWidget *parent, JavaCheckResult result)
{
QString text;
text += QObject::tr(
"The specified java binary didn't work.<br />You should use the auto-detect feature, "
"or set the path to the java executable.<br />");
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
QString text;
text += QObject::tr(
"The specified java binary didn't work.<br />You should use the auto-detect feature, "
"or set the path to the java executable.<br />");
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
}
void JavaCommon::TestCheck::run()
{
if (!JavaCommon::checkJVMArgs(m_args, m_parent))
{
emit finished();
return;
}
checker.reset(new JavaChecker());
connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this,
SLOT(checkFinished(JavaCheckResult)));
checker->m_path = m_path;
checker->performCheck();
if (!JavaCommon::checkJVMArgs(m_args, m_parent))
{
emit finished();
return;
}
checker.reset(new JavaChecker());
connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this,
SLOT(checkFinished(JavaCheckResult)));
checker->m_path = m_path;
checker->performCheck();
}
void JavaCommon::TestCheck::checkFinished(JavaCheckResult result)
{
if (result.validity != JavaCheckResult::Validity::Valid)
{
javaBinaryWasBad(m_parent, result);
emit finished();
return;
}
checker.reset(new JavaChecker());
connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this,
SLOT(checkFinishedWithArgs(JavaCheckResult)));
checker->m_path = m_path;
checker->m_args = m_args;
checker->m_minMem = m_minMem;
checker->m_maxMem = m_maxMem;
if (result.javaVersion.requiresPermGen())
{
checker->m_permGen = m_permGen;
}
checker->performCheck();
if (result.validity != JavaCheckResult::Validity::Valid)
{
javaBinaryWasBad(m_parent, result);
emit finished();
return;
}
checker.reset(new JavaChecker());
connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this,
SLOT(checkFinishedWithArgs(JavaCheckResult)));
checker->m_path = m_path;
checker->m_args = m_args;
checker->m_minMem = m_minMem;
checker->m_maxMem = m_maxMem;
if (result.javaVersion.requiresPermGen())
{
checker->m_permGen = m_permGen;
}
checker->performCheck();
}
void JavaCommon::TestCheck::checkFinishedWithArgs(JavaCheckResult result)
{
if (result.validity == JavaCheckResult::Validity::Valid)
{
javaWasOk(m_parent, result);
emit finished();
return;
}
javaArgsWereBad(m_parent, result);
emit finished();
if (result.validity == JavaCheckResult::Validity::Valid)
{
javaWasOk(m_parent, result);
emit finished();
return;
}
javaArgsWereBad(m_parent, result);
emit finished();
}

View File

@ -8,41 +8,41 @@ class QWidget;
*/
namespace JavaCommon
{
bool checkJVMArgs(QString args, QWidget *parent);
bool checkJVMArgs(QString args, QWidget *parent);
// Show a dialog saying that the Java binary was not usable
void javaBinaryWasBad(QWidget *parent, JavaCheckResult result);
// Show a dialog saying that the Java binary was not usable because of bad options
void javaArgsWereBad(QWidget *parent, JavaCheckResult result);
// Show a dialog saying that the Java binary was usable
void javaWasOk(QWidget *parent, JavaCheckResult result);
// Show a dialog saying that the Java binary was not usable
void javaBinaryWasBad(QWidget *parent, JavaCheckResult result);
// Show a dialog saying that the Java binary was not usable because of bad options
void javaArgsWereBad(QWidget *parent, JavaCheckResult result);
// Show a dialog saying that the Java binary was usable
void javaWasOk(QWidget *parent, JavaCheckResult result);
class TestCheck : public QObject
{
Q_OBJECT
public:
TestCheck(QWidget *parent, QString path, QString args, int minMem, int maxMem, int permGen)
:m_parent(parent), m_path(path), m_args(args), m_minMem(minMem), m_maxMem(maxMem), m_permGen(permGen)
{
}
virtual ~TestCheck() {};
class TestCheck : public QObject
{
Q_OBJECT
public:
TestCheck(QWidget *parent, QString path, QString args, int minMem, int maxMem, int permGen)
:m_parent(parent), m_path(path), m_args(args), m_minMem(minMem), m_maxMem(maxMem), m_permGen(permGen)
{
}
virtual ~TestCheck() {};
void run();
void run();
signals:
void finished();
signals:
void finished();
private slots:
void checkFinished(JavaCheckResult result);
void checkFinishedWithArgs(JavaCheckResult result);
private slots:
void checkFinished(JavaCheckResult result);
void checkFinishedWithArgs(JavaCheckResult result);
private:
std::shared_ptr<JavaChecker> checker;
QWidget *m_parent = nullptr;
QString m_path;
QString m_args;
int m_minMem = 0;
int m_maxMem = 0;
int m_permGen = 64;
};
private:
std::shared_ptr<JavaChecker> checker;
QWidget *m_parent = nullptr;
QString m_path;
QString m_args;
int m_minMem = 0;
int m_maxMem = 0;
int m_permGen = 64;
};
}

View File

@ -6,13 +6,13 @@
namespace {
const std::array<Qt::Key, 10> konamiCode =
{
{
Qt::Key_Up, Qt::Key_Up,
Qt::Key_Down, Qt::Key_Down,
Qt::Key_Left, Qt::Key_Right,
Qt::Key_Left, Qt::Key_Right,
Qt::Key_B, Qt::Key_A
}
{
Qt::Key_Up, Qt::Key_Up,
Qt::Key_Down, Qt::Key_Down,
Qt::Key_Left, Qt::Key_Right,
Qt::Key_Left, Qt::Key_Right,
Qt::Key_B, Qt::Key_A
}
};
}
@ -23,22 +23,22 @@ KonamiCode::KonamiCode(QObject* parent) : QObject(parent)
void KonamiCode::input(QEvent* event)
{
if( event->type() == QEvent::KeyPress )
{
QKeyEvent *keyEvent = static_cast<QKeyEvent*>( event );
auto key = Qt::Key(keyEvent->key());
if(key == konamiCode[m_progress])
{
m_progress ++;
}
else
{
m_progress = 0;
}
if(m_progress == konamiCode.size())
{
m_progress = 0;
emit triggered();
}
}
if( event->type() == QEvent::KeyPress )
{
QKeyEvent *keyEvent = static_cast<QKeyEvent*>( event );
auto key = Qt::Key(keyEvent->key());
if(key == konamiCode[m_progress])
{
m_progress ++;
}
else
{
m_progress = 0;
}
if(m_progress == konamiCode.size())
{
m_progress = 0;
emit triggered();
}
}
}

View File

@ -4,14 +4,14 @@
class KonamiCode : public QObject
{
Q_OBJECT
Q_OBJECT
public:
KonamiCode(QObject *parent = 0);
void input(QEvent *event);
KonamiCode(QObject *parent = 0);
void input(QEvent *event);
signals:
void triggered();
void triggered();
private:
int m_progress = 0;
int m_progress = 0;
};

View File

@ -23,291 +23,291 @@ LaunchController::LaunchController(QObject *parent) : Task(parent)
void LaunchController::executeTask()
{
if (!m_instance)
{
emitFailed(tr("No instance specified"));
return;
}
if (!m_instance)
{
emitFailed(tr("No instance specified"));
return;
}
login();
login();
}
// FIXME: minecraft specific
void LaunchController::login()
{
JavaCommon::checkJVMArgs(m_instance->settings()->get("JvmArgs").toString(), m_parentWidget);
JavaCommon::checkJVMArgs(m_instance->settings()->get("JvmArgs").toString(), m_parentWidget);
// Find an account to use.
std::shared_ptr<MojangAccountList> accounts = MMC->accounts();
MojangAccountPtr account = accounts->activeAccount();
if (accounts->count() <= 0)
{
// Tell the user they need to log in at least one account in order to play.
auto reply = CustomMessageBox::selectable(
m_parentWidget, tr("No Accounts"),
tr("In order to play Minecraft, you must have at least one Mojang or Minecraft "
"account logged in to MultiMC."
"Would you like to open the account manager to add an account now?"),
QMessageBox::Information, QMessageBox::Yes | QMessageBox::No)->exec();
// Find an account to use.
std::shared_ptr<MojangAccountList> accounts = MMC->accounts();
MojangAccountPtr account = accounts->activeAccount();
if (accounts->count() <= 0)
{
// Tell the user they need to log in at least one account in order to play.
auto reply = CustomMessageBox::selectable(
m_parentWidget, tr("No Accounts"),
tr("In order to play Minecraft, you must have at least one Mojang or Minecraft "
"account logged in to MultiMC."
"Would you like to open the account manager to add an account now?"),
QMessageBox::Information, QMessageBox::Yes | QMessageBox::No)->exec();
if (reply == QMessageBox::Yes)
{
// Open the account manager.
SettingsUI::ShowPageDialog(MMC->globalSettingsPages(), m_parentWidget, "accounts");
}
}
else if (account.get() == nullptr)
{
// If no default account is set, ask the user which one to use.
ProfileSelectDialog selectDialog(tr("Which profile would you like to use?"),
ProfileSelectDialog::GlobalDefaultCheckbox, m_parentWidget);
if (reply == QMessageBox::Yes)
{
// Open the account manager.
SettingsUI::ShowPageDialog(MMC->globalSettingsPages(), m_parentWidget, "accounts");
}
}
else if (account.get() == nullptr)
{
// If no default account is set, ask the user which one to use.
ProfileSelectDialog selectDialog(tr("Which profile would you like to use?"),
ProfileSelectDialog::GlobalDefaultCheckbox, m_parentWidget);
selectDialog.exec();
selectDialog.exec();
// Launch the instance with the selected account.
account = selectDialog.selectedAccount();
// Launch the instance with the selected account.
account = selectDialog.selectedAccount();
// If the user said to use the account as default, do that.
if (selectDialog.useAsGlobalDefault() && account.get() != nullptr)
accounts->setActiveAccount(account->username());
}
// If the user said to use the account as default, do that.
if (selectDialog.useAsGlobalDefault() && account.get() != nullptr)
accounts->setActiveAccount(account->username());
}
// if no account is selected, we bail
if (!account.get())
{
emitFailed(tr("No account selected for launch"));
return;
}
// if no account is selected, we bail
if (!account.get())
{
emitFailed(tr("No account selected for launch"));
return;
}
// we try empty password first :)
QString password;
// we loop until the user succeeds in logging in or gives up
bool tryagain = true;
// the failure. the default failure.
const QString needLoginAgain = tr("Your account is currently not logged in. Please enter "
"your password to log in again.");
QString failReason = needLoginAgain;
// we try empty password first :)
QString password;
// we loop until the user succeeds in logging in or gives up
bool tryagain = true;
// the failure. the default failure.
const QString needLoginAgain = tr("Your account is currently not logged in. Please enter "
"your password to log in again.");
QString failReason = needLoginAgain;
while (tryagain)
{
m_session = std::make_shared<AuthSession>();
m_session->wants_online = m_online;
auto task = account->login(m_session, password);
if (task)
{
// We'll need to validate the access token to make sure the account
// is still logged in.
ProgressDialog progDialog(m_parentWidget);
if (m_online)
{
progDialog.setSkipButton(true, tr("Play Offline"));
}
progDialog.execWithTask(task.get());
if (!task->wasSuccessful())
{
auto failReasonNew = task->failReason();
if(failReasonNew == "Invalid token.")
{
account->invalidateClientToken();
failReason = needLoginAgain;
}
else failReason = failReasonNew;
}
}
switch (m_session->status)
{
case AuthSession::Undetermined:
{
qCritical() << "Received undetermined session status during login. Bye.";
tryagain = false;
emitFailed(tr("Received undetermined session status during login."));
break;
}
case AuthSession::RequiresPassword:
{
EditAccountDialog passDialog(failReason, m_parentWidget, EditAccountDialog::PasswordField);
auto username = m_session->username;
auto chopN = [](QString toChop, int N) -> QString
{
if(toChop.size() > N)
{
auto left = toChop.left(N);
left += QString("\u25CF").repeated(toChop.size() - N);
return left;
}
return toChop;
};
while (tryagain)
{
m_session = std::make_shared<AuthSession>();
m_session->wants_online = m_online;
auto task = account->login(m_session, password);
if (task)
{
// We'll need to validate the access token to make sure the account
// is still logged in.
ProgressDialog progDialog(m_parentWidget);
if (m_online)
{
progDialog.setSkipButton(true, tr("Play Offline"));
}
progDialog.execWithTask(task.get());
if (!task->wasSuccessful())
{
auto failReasonNew = task->failReason();
if(failReasonNew == "Invalid token.")
{
account->invalidateClientToken();
failReason = needLoginAgain;
}
else failReason = failReasonNew;
}
}
switch (m_session->status)
{
case AuthSession::Undetermined:
{
qCritical() << "Received undetermined session status during login. Bye.";
tryagain = false;
emitFailed(tr("Received undetermined session status during login."));
break;
}
case AuthSession::RequiresPassword:
{
EditAccountDialog passDialog(failReason, m_parentWidget, EditAccountDialog::PasswordField);
auto username = m_session->username;
auto chopN = [](QString toChop, int N) -> QString
{
if(toChop.size() > N)
{
auto left = toChop.left(N);
left += QString("\u25CF").repeated(toChop.size() - N);
return left;
}
return toChop;
};
if(username.contains('@'))
{
auto parts = username.split('@');
auto mailbox = chopN(parts[0],3);
QString domain = chopN(parts[1], 3);
username = mailbox + '@' + domain;
}
passDialog.setUsername(username);
if (passDialog.exec() == QDialog::Accepted)
{
password = passDialog.password();
}
else
{
tryagain = false;
}
break;
}
case AuthSession::PlayableOffline:
{
// we ask the user for a player name
bool ok = false;
QString usedname = m_session->player_name;
QString name = QInputDialog::getText(m_parentWidget, tr("Player name"),
tr("Choose your offline mode player name."),
QLineEdit::Normal, m_session->player_name, &ok);
if (!ok)
{
tryagain = false;
break;
}
if (name.length())
{
usedname = name;
}
m_session->MakeOffline(usedname);
// offline flavored game from here :3
}
case AuthSession::PlayableOnline:
{
launchInstance();
tryagain = false;
return;
}
}
}
emitFailed(tr("Failed to launch."));
if(username.contains('@'))
{
auto parts = username.split('@');
auto mailbox = chopN(parts[0],3);
QString domain = chopN(parts[1], 3);
username = mailbox + '@' + domain;
}
passDialog.setUsername(username);
if (passDialog.exec() == QDialog::Accepted)
{
password = passDialog.password();
}
else
{
tryagain = false;
}
break;
}
case AuthSession::PlayableOffline:
{
// we ask the user for a player name
bool ok = false;
QString usedname = m_session->player_name;
QString name = QInputDialog::getText(m_parentWidget, tr("Player name"),
tr("Choose your offline mode player name."),
QLineEdit::Normal, m_session->player_name, &ok);
if (!ok)
{
tryagain = false;
break;
}
if (name.length())
{
usedname = name;
}
m_session->MakeOffline(usedname);
// offline flavored game from here :3
}
case AuthSession::PlayableOnline:
{
launchInstance();
tryagain = false;
return;
}
}
}
emitFailed(tr("Failed to launch."));
}
void LaunchController::launchInstance()
{
Q_ASSERT_X(m_instance != NULL, "launchInstance", "instance is NULL");
Q_ASSERT_X(m_session.get() != nullptr, "launchInstance", "session is NULL");
Q_ASSERT_X(m_instance != NULL, "launchInstance", "instance is NULL");
Q_ASSERT_X(m_session.get() != nullptr, "launchInstance", "session is NULL");
if(!m_instance->reloadSettings())
{
QMessageBox::critical(m_parentWidget, tr("Error"), tr("Couldn't load the instance profile."));
emitFailed(tr("Couldn't load the instance profile."));
return;
}
if(!m_instance->reloadSettings())
{
QMessageBox::critical(m_parentWidget, tr("Error"), tr("Couldn't load the instance profile."));
emitFailed(tr("Couldn't load the instance profile."));
return;
}
m_launcher = m_instance->createLaunchTask(m_session);
if (!m_launcher)
{
emitFailed(tr("Couldn't instantiate a launcher."));
return;
}
m_launcher = m_instance->createLaunchTask(m_session);
if (!m_launcher)
{
emitFailed(tr("Couldn't instantiate a launcher."));
return;
}
auto console = qobject_cast<InstanceWindow *>(m_parentWidget);
auto showConsole = m_instance->settings()->get("ShowConsole").toBool();
if(!console && showConsole)
{
MMC->showInstanceWindow(m_instance);
}
connect(m_launcher.get(), &LaunchTask::readyForLaunch, this, &LaunchController::readyForLaunch);
connect(m_launcher.get(), &LaunchTask::succeeded, this, &LaunchController::onSucceeded);
connect(m_launcher.get(), &LaunchTask::failed, this, &LaunchController::onFailed);
connect(m_launcher.get(), &LaunchTask::requestProgress, this, &LaunchController::onProgressRequested);
auto console = qobject_cast<InstanceWindow *>(m_parentWidget);
auto showConsole = m_instance->settings()->get("ShowConsole").toBool();
if(!console && showConsole)
{
MMC->showInstanceWindow(m_instance);
}
connect(m_launcher.get(), &LaunchTask::readyForLaunch, this, &LaunchController::readyForLaunch);
connect(m_launcher.get(), &LaunchTask::succeeded, this, &LaunchController::onSucceeded);
connect(m_launcher.get(), &LaunchTask::failed, this, &LaunchController::onFailed);
connect(m_launcher.get(), &LaunchTask::requestProgress, this, &LaunchController::onProgressRequested);
m_launcher->prependStep(std::make_shared<TextPrint>(m_launcher.get(), "MultiMC version: " + BuildConfig.printableVersionString() + "\n\n", MessageLevel::MultiMC));
m_launcher->start();
m_launcher->prependStep(std::make_shared<TextPrint>(m_launcher.get(), "MultiMC version: " + BuildConfig.printableVersionString() + "\n\n", MessageLevel::MultiMC));
m_launcher->start();
}
void LaunchController::readyForLaunch()
{
if (!m_profiler)
{
m_launcher->proceed();
return;
}
if (!m_profiler)
{
m_launcher->proceed();
return;
}
QString error;
if (!m_profiler->check(&error))
{
m_launcher->abort();
QMessageBox::critical(m_parentWidget, tr("Error"), tr("Couldn't start profiler: %1").arg(error));
emitFailed("Profiler startup failed");
return;
}
BaseProfiler *profilerInstance = m_profiler->createProfiler(m_launcher->instance(), this);
QString error;
if (!m_profiler->check(&error))
{
m_launcher->abort();
QMessageBox::critical(m_parentWidget, tr("Error"), tr("Couldn't start profiler: %1").arg(error));
emitFailed("Profiler startup failed");
return;
}
BaseProfiler *profilerInstance = m_profiler->createProfiler(m_launcher->instance(), this);
connect(profilerInstance, &BaseProfiler::readyToLaunch, [this](const QString & message)
{
QMessageBox msg;
msg.setText(tr("The game launch is delayed until you press the "
"button. This is the right time to setup the profiler, as the "
"profiler server is running now.\n\n%1").arg(message));
msg.setWindowTitle(tr("Waiting"));
msg.setIcon(QMessageBox::Information);
msg.addButton(tr("Launch"), QMessageBox::AcceptRole);
msg.setModal(true);
msg.exec();
m_launcher->proceed();
});
connect(profilerInstance, &BaseProfiler::abortLaunch, [this](const QString & message)
{
QMessageBox msg;
msg.setText(tr("Couldn't start the profiler: %1").arg(message));
msg.setWindowTitle(tr("Error"));
msg.setIcon(QMessageBox::Critical);
msg.addButton(QMessageBox::Ok);
msg.setModal(true);
msg.exec();
m_launcher->abort();
emitFailed("Profiler startup failed");
});
profilerInstance->beginProfiling(m_launcher);
connect(profilerInstance, &BaseProfiler::readyToLaunch, [this](const QString & message)
{
QMessageBox msg;
msg.setText(tr("The game launch is delayed until you press the "
"button. This is the right time to setup the profiler, as the "
"profiler server is running now.\n\n%1").arg(message));
msg.setWindowTitle(tr("Waiting"));
msg.setIcon(QMessageBox::Information);
msg.addButton(tr("Launch"), QMessageBox::AcceptRole);
msg.setModal(true);
msg.exec();
m_launcher->proceed();
});
connect(profilerInstance, &BaseProfiler::abortLaunch, [this](const QString & message)
{
QMessageBox msg;
msg.setText(tr("Couldn't start the profiler: %1").arg(message));
msg.setWindowTitle(tr("Error"));
msg.setIcon(QMessageBox::Critical);
msg.addButton(QMessageBox::Ok);
msg.setModal(true);
msg.exec();
m_launcher->abort();
emitFailed("Profiler startup failed");
});
profilerInstance->beginProfiling(m_launcher);
}
void LaunchController::onSucceeded()
{
emitSucceeded();
emitSucceeded();
}
void LaunchController::onFailed(QString reason)
{
if(m_instance->settings()->get("ShowConsoleOnError").toBool())
{
MMC->showInstanceWindow(m_instance, "console");
}
emitFailed(reason);
if(m_instance->settings()->get("ShowConsoleOnError").toBool())
{
MMC->showInstanceWindow(m_instance, "console");
}
emitFailed(reason);
}
void LaunchController::onProgressRequested(Task* task)
{
ProgressDialog progDialog(m_parentWidget);
progDialog.setSkipButton(true, tr("Abort"));
m_launcher->proceed();
progDialog.execWithTask(task);
ProgressDialog progDialog(m_parentWidget);
progDialog.setSkipButton(true, tr("Abort"));
m_launcher->proceed();
progDialog.execWithTask(task);
}
bool LaunchController::abort()
{
if(!m_launcher)
{
return true;
}
if(!m_launcher->canAbort())
{
return false;
}
auto response = CustomMessageBox::selectable(
m_parentWidget, tr("Kill Minecraft?"),
tr("This can cause the instance to get corrupted and should only be used if Minecraft "
"is frozen for some reason"),
QMessageBox::Question, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)->exec();
if (response == QMessageBox::Yes)
{
return m_launcher->abort();
}
return false;
if(!m_launcher)
{
return true;
}
if(!m_launcher->canAbort())
{
return false;
}
auto response = CustomMessageBox::selectable(
m_parentWidget, tr("Kill Minecraft?"),
tr("This can cause the instance to get corrupted and should only be used if Minecraft "
"is frozen for some reason"),
QMessageBox::Question, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)->exec();
if (response == QMessageBox::Yes)
{
return m_launcher->abort();
}
return false;
}

View File

@ -6,56 +6,56 @@
class InstanceWindow;
class LaunchController: public Task
{
Q_OBJECT
Q_OBJECT
public:
void executeTask() override;
void executeTask() override;
LaunchController(QObject * parent = nullptr);
virtual ~LaunchController(){};
LaunchController(QObject * parent = nullptr);
virtual ~LaunchController(){};
void setInstance(InstancePtr instance)
{
m_instance = instance;
}
InstancePtr instance()
{
return m_instance;
}
void setOnline(bool online)
{
m_online = online;
}
void setProfiler(BaseProfilerFactory *profiler)
{
m_profiler = profiler;
}
void setParentWidget(QWidget * widget)
{
m_parentWidget = widget;
}
QString id()
{
return m_instance->id();
}
bool abort() override;
void setInstance(InstancePtr instance)
{
m_instance = instance;
}
InstancePtr instance()
{
return m_instance;
}
void setOnline(bool online)
{
m_online = online;
}
void setProfiler(BaseProfilerFactory *profiler)
{
m_profiler = profiler;
}
void setParentWidget(QWidget * widget)
{
m_parentWidget = widget;
}
QString id()
{
return m_instance->id();
}
bool abort() override;
private:
void login();
void launchInstance();
void login();
void launchInstance();
private slots:
void readyForLaunch();
void readyForLaunch();
void onSucceeded();
void onFailed(QString reason);
void onProgressRequested(Task *task);
void onSucceeded();
void onFailed(QString reason);
void onProgressRequested(Task *task);
private:
BaseProfilerFactory *m_profiler = nullptr;
bool m_online = true;
InstancePtr m_instance;
QWidget * m_parentWidget = nullptr;
InstanceWindow *m_console = nullptr;
AuthSessionPtr m_session;
std::shared_ptr <LaunchTask> m_launcher;
BaseProfilerFactory *m_profiler = nullptr;
bool m_online = true;
InstancePtr m_instance;
QWidget * m_parentWidget = nullptr;
InstanceWindow *m_console = nullptr;
AuthSessionPtr m_session;
std::shared_ptr <LaunchTask> m_launcher;
};

File diff suppressed because it is too large Load Diff

View File

@ -42,174 +42,174 @@ class InstanceTask;
class MainWindow : public QMainWindow
{
Q_OBJECT
Q_OBJECT
class Ui;
class Ui;
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
bool eventFilter(QObject *obj, QEvent *ev) override;
void closeEvent(QCloseEvent *event) override;
void changeEvent(QEvent * event) override;
bool eventFilter(QObject *obj, QEvent *ev) override;
void closeEvent(QCloseEvent *event) override;
void changeEvent(QEvent * event) override;
void checkInstancePathForProblems();
void checkInstancePathForProblems();
void updatesAllowedChanged(bool allowed);
void updatesAllowedChanged(bool allowed);
signals:
void isClosing();
void isClosing();
private slots:
void onCatToggled(bool);
void onCatToggled(bool);
void on_actionAbout_triggered();
void on_actionAbout_triggered();
void on_actionAddInstance_triggered();
void on_actionAddInstance_triggered();
void on_actionREDDIT_triggered();
void on_actionREDDIT_triggered();
void on_actionDISCORD_triggered();
void on_actionDISCORD_triggered();
void on_actionCopyInstance_triggered();
void on_actionCopyInstance_triggered();
void on_actionChangeInstGroup_triggered();
void on_actionChangeInstGroup_triggered();
void on_actionChangeInstIcon_triggered();
void on_changeIconButton_clicked(bool)
{
on_actionChangeInstIcon_triggered();
}
void on_actionChangeInstIcon_triggered();
void on_changeIconButton_clicked(bool)
{
on_actionChangeInstIcon_triggered();
}
void on_actionViewInstanceFolder_triggered();
void on_actionViewInstanceFolder_triggered();
void on_actionConfig_Folder_triggered();
void on_actionConfig_Folder_triggered();
void on_actionViewSelectedInstFolder_triggered();
void on_actionViewSelectedInstFolder_triggered();
void refreshInstances();
void refreshInstances();
void on_actionViewCentralModsFolder_triggered();
void on_actionViewCentralModsFolder_triggered();
void checkForUpdates();
void checkForUpdates();
void on_actionSettings_triggered();
void on_actionSettings_triggered();
void on_actionInstanceSettings_triggered();
void on_actionInstanceSettings_triggered();
void on_actionManageAccounts_triggered();
void on_actionManageAccounts_triggered();
void on_actionReportBug_triggered();
void on_actionReportBug_triggered();
void on_actionPatreon_triggered();
void on_actionPatreon_triggered();
void on_actionMoreNews_triggered();
void on_actionMoreNews_triggered();
void newsButtonClicked();
void newsButtonClicked();
void on_mainToolBar_visibilityChanged(bool);
void on_mainToolBar_visibilityChanged(bool);
void on_actionLaunchInstance_triggered();
void on_actionLaunchInstance_triggered();
void on_actionLaunchInstanceOffline_triggered();
void on_actionLaunchInstanceOffline_triggered();
void on_actionDeleteInstance_triggered();
void on_actionDeleteInstance_triggered();
void deleteGroup();
void deleteGroup();
void on_actionExportInstance_triggered();
void on_actionExportInstance_triggered();
void on_actionRenameInstance_triggered();
void on_renameButton_clicked(bool)
{
on_actionRenameInstance_triggered();
}
void on_actionRenameInstance_triggered();
void on_renameButton_clicked(bool)
{
on_actionRenameInstance_triggered();
}
void on_actionEditInstance_triggered();
void on_actionEditInstance_triggered();
void on_actionEditInstNotes_triggered();
void on_actionEditInstNotes_triggered();
void on_actionWorlds_triggered();
void on_actionWorlds_triggered();
void on_actionScreenshots_triggered();
void on_actionScreenshots_triggered();
void taskEnd();
void taskEnd();
/**
* called when an icon is changed in the icon model.
*/
void iconUpdated(QString);
/**
* called when an icon is changed in the icon model.
*/
void iconUpdated(QString);
void showInstanceContextMenu(const QPoint &);
void showInstanceContextMenu(const QPoint &);
void updateToolsMenu();
void updateToolsMenu();
void skinJobFinished();
void skinJobFinished();
void instanceActivated(QModelIndex);
void instanceActivated(QModelIndex);
void instanceChanged(const QModelIndex &current, const QModelIndex &previous);
void instanceChanged(const QModelIndex &current, const QModelIndex &previous);
void instanceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
void instanceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
void selectionBad();
void selectionBad();
void startTask(Task *task);
void startTask(Task *task);
void updateAvailable(GoUpdate::Status status);
void updateAvailable(GoUpdate::Status status);
void updateNotAvailable();
void updateNotAvailable();
void notificationsChanged();
void notificationsChanged();
void activeAccountChanged();
void activeAccountChanged();
void changeActiveAccount();
void changeActiveAccount();
void repopulateAccountsMenu();
void repopulateAccountsMenu();
void updateNewsLabel();
void updateNewsLabel();
/*!
* Runs the DownloadTask and installs updates.
*/
void downloadUpdates(GoUpdate::Status status);
/*!
* Runs the DownloadTask and installs updates.
*/
void downloadUpdates(GoUpdate::Status status);
void droppedURLs(QList<QUrl> urls);
void droppedURLs(QList<QUrl> urls);
void konamiTriggered();
void konamiTriggered();
private:
void addInstance(QString url = QString());
void activateInstance(InstancePtr instance);
void setCatBackground(bool enabled);
void updateInstanceToolIcon(QString new_icon);
void setSelectedInstanceById(const QString &id);
void addInstance(QString url = QString());
void activateInstance(InstancePtr instance);
void setCatBackground(bool enabled);
void updateInstanceToolIcon(QString new_icon);
void setSelectedInstanceById(const QString &id);
void runModalTask(Task *task);
void instanceFromInstanceTask(InstanceTask *task);
void finalizeInstance(InstancePtr inst);
void runModalTask(Task *task);
void instanceFromInstanceTask(InstanceTask *task);
void finalizeInstance(InstancePtr inst);
private:
std::unique_ptr<Ui> ui;
std::unique_ptr<Ui> ui;
// these are managed by Qt's memory management model!
GroupView *view = nullptr;
InstanceProxyModel *proxymodel = nullptr;
QToolButton *newsLabel = nullptr;
QLabel *m_statusLeft = nullptr;
ServerStatus *m_statusRight = nullptr;
QMenu *accountMenu = nullptr;
QToolButton *accountMenuButton = nullptr;
KonamiCode * secretEventFilter = nullptr;
// these are managed by Qt's memory management model!
GroupView *view = nullptr;
InstanceProxyModel *proxymodel = nullptr;
QToolButton *newsLabel = nullptr;
QLabel *m_statusLeft = nullptr;
ServerStatus *m_statusRight = nullptr;
QMenu *accountMenu = nullptr;
QToolButton *accountMenuButton = nullptr;
KonamiCode * secretEventFilter = nullptr;
unique_qobject_ptr<NetJob> skin_download_job;
unique_qobject_ptr<NewsChecker> m_newsChecker;
unique_qobject_ptr<NotificationChecker> m_notificationChecker;
unique_qobject_ptr<NetJob> skin_download_job;
unique_qobject_ptr<NewsChecker> m_newsChecker;
unique_qobject_ptr<NotificationChecker> m_notificationChecker;
InstancePtr m_selectedInstance;
QString m_currentInstIcon;
InstancePtr m_selectedInstance;
QString m_currentInstIcon;
// managed by the application object
Task *m_versionLoadTask = nullptr;
// managed by the application object
Task *m_versionLoadTask = nullptr;
};

File diff suppressed because it is too large Load Diff

View File

@ -40,187 +40,187 @@ class GAnalytics;
class MultiMC : public QApplication
{
// friends for the purpose of limiting access to deprecated stuff
Q_OBJECT
// friends for the purpose of limiting access to deprecated stuff
Q_OBJECT
public:
enum Status
{
StartingUp,
Failed,
Succeeded,
Initialized
};
enum Status
{
StartingUp,
Failed,
Succeeded,
Initialized
};
public:
MultiMC(int &argc, char **argv);
virtual ~MultiMC();
MultiMC(int &argc, char **argv);
virtual ~MultiMC();
GAnalytics *analytics() const
{
return m_analytics;
}
GAnalytics *analytics() const
{
return m_analytics;
}
std::shared_ptr<SettingsObject> settings() const
{
return m_settings;
}
std::shared_ptr<SettingsObject> settings() const
{
return m_settings;
}
std::shared_ptr<GenericPageProvider> globalSettingsPages() const
{
return m_globalSettingsProvider;
}
std::shared_ptr<GenericPageProvider> globalSettingsPages() const
{
return m_globalSettingsProvider;
}
qint64 timeSinceStart() const
{
return startTime.msecsTo(QDateTime::currentDateTime());
}
qint64 timeSinceStart() const
{
return startTime.msecsTo(QDateTime::currentDateTime());
}
QIcon getThemedIcon(const QString& name);
QIcon getThemedIcon(const QString& name);
void setIconTheme(const QString& name);
void setIconTheme(const QString& name);
std::vector<ITheme *> getValidApplicationThemes();
std::vector<ITheme *> getValidApplicationThemes();
void setApplicationTheme(const QString& name, bool initial);
void setApplicationTheme(const QString& name, bool initial);
// DownloadUpdateTask
std::shared_ptr<UpdateChecker> updateChecker()
{
return m_updateChecker;
}
// DownloadUpdateTask
std::shared_ptr<UpdateChecker> updateChecker()
{
return m_updateChecker;
}
std::shared_ptr<TranslationsModel> translations();
std::shared_ptr<TranslationsModel> translations();
std::shared_ptr<JavaInstallList> javalist();
std::shared_ptr<JavaInstallList> javalist();
std::shared_ptr<InstanceList> instances() const
{
return m_instances;
}
std::shared_ptr<InstanceList> instances() const
{
return m_instances;
}
FolderInstanceProvider * folderProvider() const
{
return m_instanceFolder;
}
FolderInstanceProvider * folderProvider() const
{
return m_instanceFolder;
}
std::shared_ptr<IconList> icons() const
{
return m_icons;
}
std::shared_ptr<IconList> icons() const
{
return m_icons;
}
MCEditTool *mcedit() const
{
return m_mcedit.get();
}
MCEditTool *mcedit() const
{
return m_mcedit.get();
}
std::shared_ptr<MojangAccountList> accounts() const
{
return m_accounts;
}
std::shared_ptr<MojangAccountList> accounts() const
{
return m_accounts;
}
Status status() const
{
return m_status;
}
Status status() const
{
return m_status;
}
const QMap<QString, std::shared_ptr<BaseProfilerFactory>> &profilers() const
{
return m_profilers;
}
const QMap<QString, std::shared_ptr<BaseProfilerFactory>> &profilers() const
{
return m_profilers;
}
/// this is the root of the 'installation'. Used for automatic updates
const QString &root()
{
return m_rootPath;
}
/// this is the root of the 'installation'. Used for automatic updates
const QString &root()
{
return m_rootPath;
}
/*!
* Opens a json file using either a system default editor, or, if not empty, the editor
* specified in the settings
*/
bool openJsonEditor(const QString &filename);
/*!
* Opens a json file using either a system default editor, or, if not empty, the editor
* specified in the settings
*/
bool openJsonEditor(const QString &filename);
InstanceWindow *showInstanceWindow(InstancePtr instance, QString page = QString());
MainWindow *showMainWindow(bool minimized = false);
InstanceWindow *showInstanceWindow(InstancePtr instance, QString page = QString());
MainWindow *showMainWindow(bool minimized = false);
void updateIsRunning(bool running);
bool updatesAreAllowed();
void updateIsRunning(bool running);
bool updatesAreAllowed();
signals:
void updateAllowedChanged(bool status);
void updateAllowedChanged(bool status);
public slots:
bool launch(InstancePtr instance, bool online = true, BaseProfilerFactory *profiler = nullptr);
bool kill(InstancePtr instance);
bool launch(InstancePtr instance, bool online = true, BaseProfilerFactory *profiler = nullptr);
bool kill(InstancePtr instance);
private slots:
void on_windowClose();
void messageReceived(const QString & message);
void controllerSucceeded();
void controllerFailed(const QString & error);
void analyticsSettingChanged(const Setting &setting, QVariant value);
void setupWizardFinished(int status);
void on_windowClose();
void messageReceived(const QString & message);
void controllerSucceeded();
void controllerFailed(const QString & error);
void analyticsSettingChanged(const Setting &setting, QVariant value);
void setupWizardFinished(int status);
private:
bool createSetupWizard();
void performMainStartupAction();
bool createSetupWizard();
void performMainStartupAction();
// sets the fatal error message and m_status to Failed.
void showFatalErrorMessage(const QString & title, const QString & content);
// sets the fatal error message and m_status to Failed.
void showFatalErrorMessage(const QString & title, const QString & content);
private:
void addRunningInstance();
void subRunningInstance();
bool shouldExitNow() const;
void addRunningInstance();
void subRunningInstance();
bool shouldExitNow() const;
private:
QDateTime startTime;
QDateTime startTime;
std::shared_ptr<SettingsObject> m_settings;
std::shared_ptr<InstanceList> m_instances;
FolderInstanceProvider * m_instanceFolder = nullptr;
std::shared_ptr<IconList> m_icons;
std::shared_ptr<UpdateChecker> m_updateChecker;
std::shared_ptr<MojangAccountList> m_accounts;
std::shared_ptr<JavaInstallList> m_javalist;
std::shared_ptr<TranslationsModel> m_translations;
std::shared_ptr<GenericPageProvider> m_globalSettingsProvider;
std::map<QString, std::unique_ptr<ITheme>> m_themes;
std::unique_ptr<MCEditTool> m_mcedit;
std::shared_ptr<SettingsObject> m_settings;
std::shared_ptr<InstanceList> m_instances;
FolderInstanceProvider * m_instanceFolder = nullptr;
std::shared_ptr<IconList> m_icons;
std::shared_ptr<UpdateChecker> m_updateChecker;
std::shared_ptr<MojangAccountList> m_accounts;
std::shared_ptr<JavaInstallList> m_javalist;
std::shared_ptr<TranslationsModel> m_translations;
std::shared_ptr<GenericPageProvider> m_globalSettingsProvider;
std::map<QString, std::unique_ptr<ITheme>> m_themes;
std::unique_ptr<MCEditTool> m_mcedit;
QMap<QString, std::shared_ptr<BaseProfilerFactory>> m_profilers;
QMap<QString, std::shared_ptr<BaseProfilerFactory>> m_profilers;
QString m_rootPath;
Status m_status = MultiMC::StartingUp;
QString m_rootPath;
Status m_status = MultiMC::StartingUp;
#if defined Q_OS_WIN32
// used on Windows to attach the standard IO streams
bool consoleAttached = false;
// used on Windows to attach the standard IO streams
bool consoleAttached = false;
#endif
// FIXME: attach to instances instead.
struct InstanceXtras
{
InstanceWindow * window = nullptr;
shared_qobject_ptr<LaunchController> controller;
};
std::map<QString, InstanceXtras> m_instanceExtras;
// FIXME: attach to instances instead.
struct InstanceXtras
{
InstanceWindow * window = nullptr;
shared_qobject_ptr<LaunchController> controller;
};
std::map<QString, InstanceXtras> m_instanceExtras;
// main state variables
size_t m_openWindows = 0;
size_t m_runningInstances = 0;
bool m_updateRunning = false;
// main state variables
size_t m_openWindows = 0;
size_t m_runningInstances = 0;
bool m_updateRunning = false;
// main window, if any
MainWindow * m_mainWindow = nullptr;
// main window, if any
MainWindow * m_mainWindow = nullptr;
// peer MultiMC instance connector - used to implement single instance MultiMC and signalling
LocalPeer * m_peerInstance = nullptr;
// peer MultiMC instance connector - used to implement single instance MultiMC and signalling
LocalPeer * m_peerInstance = nullptr;
GAnalytics * m_analytics = nullptr;
SetupWizard * m_setupWizard = nullptr;
GAnalytics * m_analytics = nullptr;
SetupWizard * m_setupWizard = nullptr;
public:
QString m_instanceIdToLaunch;
bool m_liveCheck = false;
std::unique_ptr<QFile> logFile;
QString m_instanceIdToLaunch;
bool m_liveCheck = false;
std::unique_ptr<QFile> logFile;
};

View File

@ -14,13 +14,13 @@ namespace SettingsUI
template <typename T>
void ShowPageDialog(T raw_provider, QWidget * parent, QString open_page = QString())
{
auto provider = std::dynamic_pointer_cast<BasePageProvider>(raw_provider);
if(!provider)
return;
{
SettingsObject::Lock lock(MMC->settings());
PageDialog dlg(provider.get(), open_page, parent);
dlg.exec();
}
auto provider = std::dynamic_pointer_cast<BasePageProvider>(raw_provider);
if(!provider)
return;
{
SettingsObject::Lock lock(MMC->settings());
PageDialog dlg(provider.get(), open_page, parent);
dlg.exec();
}
}
}

View File

@ -27,423 +27,423 @@
#endif
static QFile::Permissions unixModeToPermissions(const int mode)
{
QFile::Permissions perms;
QFile::Permissions perms;
if (mode & S_IRUSR)
{
perms |= QFile::ReadUser;
}
if (mode & S_IWUSR)
{
perms |= QFile::WriteUser;
}
if (mode & S_IXUSR)
{
perms |= QFile::ExeUser;
}
if (mode & S_IRUSR)
{
perms |= QFile::ReadUser;
}
if (mode & S_IWUSR)
{
perms |= QFile::WriteUser;
}
if (mode & S_IXUSR)
{
perms |= QFile::ExeUser;
}
if (mode & S_IRGRP)
{
perms |= QFile::ReadGroup;
}
if (mode & S_IWGRP)
{
perms |= QFile::WriteGroup;
}
if (mode & S_IXGRP)
{
perms |= QFile::ExeGroup;
}
if (mode & S_IRGRP)
{
perms |= QFile::ReadGroup;
}
if (mode & S_IWGRP)
{
perms |= QFile::WriteGroup;
}
if (mode & S_IXGRP)
{
perms |= QFile::ExeGroup;
}
if (mode & S_IROTH)
{
perms |= QFile::ReadOther;
}
if (mode & S_IWOTH)
{
perms |= QFile::WriteOther;
}
if (mode & S_IXOTH)
{
perms |= QFile::ExeOther;
}
return perms;
if (mode & S_IROTH)
{
perms |= QFile::ReadOther;
}
if (mode & S_IWOTH)
{
perms |= QFile::WriteOther;
}
if (mode & S_IXOTH)
{
perms |= QFile::ExeOther;
}
return perms;
}
static const QLatin1String liveCheckFile("live.check");
UpdateController::UpdateController(QWidget * parent, const QString& root, const QString updateFilesDir, GoUpdate::OperationList operations)
{
m_parent = parent;
m_root = root;
m_updateFilesDir = updateFilesDir;
m_operations = operations;
m_parent = parent;
m_root = root;
m_updateFilesDir = updateFilesDir;
m_operations = operations;
}
void UpdateController::installUpdates()
{
qint64 pid = -1;
QStringList args;
bool started = false;
qint64 pid = -1;
QStringList args;
bool started = false;
qDebug() << "Installing updates.";
qDebug() << "Installing updates.";
#ifdef Q_OS_WIN
QString finishCmd = QApplication::applicationFilePath();
QString finishCmd = QApplication::applicationFilePath();
#elif defined Q_OS_LINUX
QString finishCmd = FS::PathCombine(m_root, "MultiMC");
QString finishCmd = FS::PathCombine(m_root, "MultiMC");
#elif defined Q_OS_MAC
QString finishCmd = QApplication::applicationFilePath();
QString finishCmd = QApplication::applicationFilePath();
#else
#error Unsupported operating system.
#endif
QString backupPath = FS::PathCombine(m_root, "update", "backup");
QDir origin(m_root);
QString backupPath = FS::PathCombine(m_root, "update", "backup");
QDir origin(m_root);
// clean up the backup folder. it should be empty before we start
if(!FS::deletePath(backupPath))
{
qWarning() << "couldn't remove previous backup folder" << backupPath;
}
// and it should exist.
if(!FS::ensureFolderPathExists(backupPath))
{
qWarning() << "couldn't create folder" << backupPath;
return;
}
// clean up the backup folder. it should be empty before we start
if(!FS::deletePath(backupPath))
{
qWarning() << "couldn't remove previous backup folder" << backupPath;
}
// and it should exist.
if(!FS::ensureFolderPathExists(backupPath))
{
qWarning() << "couldn't create folder" << backupPath;
return;
}
bool useXPHack = false;
QString exePath;
QString exeOrigin;
QString exeBackup;
bool useXPHack = false;
QString exePath;
QString exeOrigin;
QString exeBackup;
// perform the update operations
for(auto op: m_operations)
{
switch(op.type)
{
// replace = move original out to backup, if it exists, move the new file in its place
case GoUpdate::Operation::OP_REPLACE:
{
// perform the update operations
for(auto op: m_operations)
{
switch(op.type)
{
// replace = move original out to backup, if it exists, move the new file in its place
case GoUpdate::Operation::OP_REPLACE:
{
#ifdef Q_OS_WIN32
// hack for people renaming the .exe because ... reasons :)
if(op.destination == "MultiMC.exe")
{
op.destination = QFileInfo(QApplication::applicationFilePath()).fileName();
}
// hack for people renaming the .exe because ... reasons :)
if(op.destination == "MultiMC.exe")
{
op.destination = QFileInfo(QApplication::applicationFilePath()).fileName();
}
#endif
QFileInfo destination (FS::PathCombine(m_root, op.destination));
QFileInfo destination (FS::PathCombine(m_root, op.destination));
#ifdef Q_OS_WIN32
if(QSysInfo::windowsVersion() < QSysInfo::WV_VISTA)
{
if(destination.fileName() == "MultiMC.exe")
{
QDir rootDir(m_root);
exeOrigin = rootDir.relativeFilePath(op.source);
exePath = rootDir.relativeFilePath(op.destination);
exeBackup = rootDir.relativeFilePath(FS::PathCombine(backupPath, destination.fileName()));
useXPHack = true;
continue;
}
}
if(QSysInfo::windowsVersion() < QSysInfo::WV_VISTA)
{
if(destination.fileName() == "MultiMC.exe")
{
QDir rootDir(m_root);
exeOrigin = rootDir.relativeFilePath(op.source);
exePath = rootDir.relativeFilePath(op.destination);
exeBackup = rootDir.relativeFilePath(FS::PathCombine(backupPath, destination.fileName()));
useXPHack = true;
continue;
}
}
#endif
if(destination.exists())
{
QString backupName = op.destination;
backupName.replace('/', '_');
QString backupFilePath = FS::PathCombine(backupPath, backupName);
if(!QFile::rename(destination.absoluteFilePath(), backupFilePath))
{
qWarning() << "Couldn't move:" << destination.absoluteFilePath() << "to" << backupFilePath;
m_failedOperationType = Replace;
m_failedFile = op.destination;
fail();
return;
}
BackupEntry be;
be.original = destination.absoluteFilePath();
be.backup = backupFilePath;
be.update = op.source;
m_replace_backups.append(be);
}
// make sure the folder we are putting this into exists
if(!FS::ensureFilePathExists(destination.absoluteFilePath()))
{
qWarning() << "REPLACE: Couldn't create folder:" << destination.absoluteFilePath();
m_failedOperationType = Replace;
m_failedFile = op.destination;
fail();
return;
}
// now move the new file in
if(!QFile::rename(op.source, destination.absoluteFilePath()))
{
qWarning() << "REPLACE: Couldn't move:" << op.source << "to" << destination.absoluteFilePath();
m_failedOperationType = Replace;
m_failedFile = op.destination;
fail();
return;
}
QFile::setPermissions(destination.absoluteFilePath(), unixModeToPermissions(op.destinationMode));
}
break;
// delete = move original to backup
case GoUpdate::Operation::OP_DELETE:
{
QString destFilePath = FS::PathCombine(m_root, op.destination);
if(QFile::exists(destFilePath))
{
QString backupName = op.destination;
backupName.replace('/', '_');
QString trashFilePath = FS::PathCombine(backupPath, backupName);
if(destination.exists())
{
QString backupName = op.destination;
backupName.replace('/', '_');
QString backupFilePath = FS::PathCombine(backupPath, backupName);
if(!QFile::rename(destination.absoluteFilePath(), backupFilePath))
{
qWarning() << "Couldn't move:" << destination.absoluteFilePath() << "to" << backupFilePath;
m_failedOperationType = Replace;
m_failedFile = op.destination;
fail();
return;
}
BackupEntry be;
be.original = destination.absoluteFilePath();
be.backup = backupFilePath;
be.update = op.source;
m_replace_backups.append(be);
}
// make sure the folder we are putting this into exists
if(!FS::ensureFilePathExists(destination.absoluteFilePath()))
{
qWarning() << "REPLACE: Couldn't create folder:" << destination.absoluteFilePath();
m_failedOperationType = Replace;
m_failedFile = op.destination;
fail();
return;
}
// now move the new file in
if(!QFile::rename(op.source, destination.absoluteFilePath()))
{
qWarning() << "REPLACE: Couldn't move:" << op.source << "to" << destination.absoluteFilePath();
m_failedOperationType = Replace;
m_failedFile = op.destination;
fail();
return;
}
QFile::setPermissions(destination.absoluteFilePath(), unixModeToPermissions(op.destinationMode));
}
break;
// delete = move original to backup
case GoUpdate::Operation::OP_DELETE:
{
QString destFilePath = FS::PathCombine(m_root, op.destination);
if(QFile::exists(destFilePath))
{
QString backupName = op.destination;
backupName.replace('/', '_');
QString trashFilePath = FS::PathCombine(backupPath, backupName);
if(!QFile::rename(destFilePath, trashFilePath))
{
qWarning() << "DELETE: Couldn't move:" << op.destination << "to" << trashFilePath;
m_failedFile = op.destination;
m_failedOperationType = Delete;
fail();
return;
}
BackupEntry be;
be.original = destFilePath;
be.backup = trashFilePath;
m_delete_backups.append(be);
}
}
break;
}
}
if(!QFile::rename(destFilePath, trashFilePath))
{
qWarning() << "DELETE: Couldn't move:" << op.destination << "to" << trashFilePath;
m_failedFile = op.destination;
m_failedOperationType = Delete;
fail();
return;
}
BackupEntry be;
be.original = destFilePath;
be.backup = trashFilePath;
m_delete_backups.append(be);
}
}
break;
}
}
// try to start the new binary
args = qApp->arguments();
args.removeFirst();
// try to start the new binary
args = qApp->arguments();
args.removeFirst();
// on old Windows, do insane things... no error checking here, this is just to have something.
if(useXPHack)
{
QString script;
auto nativePath = QDir::toNativeSeparators(exePath);
auto nativeOriginPath = QDir::toNativeSeparators(exeOrigin);
auto nativeBackupPath = QDir::toNativeSeparators(exeBackup);
// on old Windows, do insane things... no error checking here, this is just to have something.
if(useXPHack)
{
QString script;
auto nativePath = QDir::toNativeSeparators(exePath);
auto nativeOriginPath = QDir::toNativeSeparators(exeOrigin);
auto nativeBackupPath = QDir::toNativeSeparators(exeBackup);
// so we write this vbscript thing...
QTextStream out(&script);
out << "WScript.Sleep 1000\n";
out << "Set fso=CreateObject(\"Scripting.FileSystemObject\")\n";
out << "Set shell=CreateObject(\"WScript.Shell\")\n";
out << "fso.MoveFile \"" << nativePath << "\", \"" << nativeBackupPath << "\"\n";
out << "fso.MoveFile \"" << nativeOriginPath << "\", \"" << nativePath << "\"\n";
out << "shell.Run \"" << nativePath << "\"\n";
// so we write this vbscript thing...
QTextStream out(&script);
out << "WScript.Sleep 1000\n";
out << "Set fso=CreateObject(\"Scripting.FileSystemObject\")\n";
out << "Set shell=CreateObject(\"WScript.Shell\")\n";
out << "fso.MoveFile \"" << nativePath << "\", \"" << nativeBackupPath << "\"\n";
out << "fso.MoveFile \"" << nativeOriginPath << "\", \"" << nativePath << "\"\n";
out << "shell.Run \"" << nativePath << "\"\n";
QString scriptPath = FS::PathCombine(m_root, "update", "update.vbs");
QString scriptPath = FS::PathCombine(m_root, "update", "update.vbs");
// we save it
QFile scriptFile(scriptPath);
scriptFile.open(QIODevice::WriteOnly);
scriptFile.write(script.toLocal8Bit().replace("\n", "\r\n"));
scriptFile.close();
// we save it
QFile scriptFile(scriptPath);
scriptFile.open(QIODevice::WriteOnly);
scriptFile.write(script.toLocal8Bit().replace("\n", "\r\n"));
scriptFile.close();
// we run it
started = QProcess::startDetached("wscript", {scriptPath}, m_root);
// we run it
started = QProcess::startDetached("wscript", {scriptPath}, m_root);
// and we quit. conscious thought.
qApp->quit();
return;
}
bool doLiveCheck = true;
bool startFailed = false;
// and we quit. conscious thought.
qApp->quit();
return;
}
bool doLiveCheck = true;
bool startFailed = false;
// remove live check file, if any
if(QFile::exists(liveCheckFile))
{
if(!QFile::remove(liveCheckFile))
{
qWarning() << "Couldn't remove the" << liveCheckFile << "file! We will proceed without :(";
doLiveCheck = false;
}
}
// remove live check file, if any
if(QFile::exists(liveCheckFile))
{
if(!QFile::remove(liveCheckFile))
{
qWarning() << "Couldn't remove the" << liveCheckFile << "file! We will proceed without :(";
doLiveCheck = false;
}
}
if(doLiveCheck)
{
if(!args.contains("--alive"))
{
args.append("--alive");
}
}
if(doLiveCheck)
{
if(!args.contains("--alive"))
{
args.append("--alive");
}
}
// FIXME: reparse args and construct a safe variant from scratch. This is a workaround for GH-1874:
QStringList realargs;
int skip = 0;
for(auto & arg: args)
{
if(skip)
{
skip--;
continue;
}
if(arg == "-l")
{
skip = 1;
continue;
}
realargs.append(arg);
}
// FIXME: reparse args and construct a safe variant from scratch. This is a workaround for GH-1874:
QStringList realargs;
int skip = 0;
for(auto & arg: args)
{
if(skip)
{
skip--;
continue;
}
if(arg == "-l")
{
skip = 1;
continue;
}
realargs.append(arg);
}
// start the updated application
started = QProcess::startDetached(finishCmd, realargs, QDir::currentPath(), &pid);
// much dumber check - just find out if the call
if(!started || pid == -1)
{
qWarning() << "Couldn't start new process properly!";
startFailed = true;
}
if(!startFailed && doLiveCheck)
{
int attempts = 0;
while(attempts < 10)
{
attempts++;
QString key;
std::this_thread::sleep_for(std::chrono::milliseconds(250));
if(!QFile::exists(liveCheckFile))
{
qWarning() << "Couldn't find the" << liveCheckFile << "file!";
startFailed = true;
continue;
}
try
{
key = QString::fromUtf8(FS::read(liveCheckFile));
auto id = ApplicationId::fromRawString(key);
LocalPeer peer(nullptr, id);
if(peer.isClient())
{
startFailed = false;
qDebug() << "Found process started with key " << key;
break;
}
else
{
startFailed = true;
qDebug() << "Process started with key " << key << "apparently died or is not reponding...";
break;
}
}
catch (const Exception &e)
{
qWarning() << "Couldn't read the" << liveCheckFile << "file!";
startFailed = true;
continue;
}
}
}
if(startFailed)
{
m_failedOperationType = Start;
fail();
return;
}
else
{
origin.rmdir(m_updateFilesDir);
qApp->quit();
return;
}
// start the updated application
started = QProcess::startDetached(finishCmd, realargs, QDir::currentPath(), &pid);
// much dumber check - just find out if the call
if(!started || pid == -1)
{
qWarning() << "Couldn't start new process properly!";
startFailed = true;
}
if(!startFailed && doLiveCheck)
{
int attempts = 0;
while(attempts < 10)
{
attempts++;
QString key;
std::this_thread::sleep_for(std::chrono::milliseconds(250));
if(!QFile::exists(liveCheckFile))
{
qWarning() << "Couldn't find the" << liveCheckFile << "file!";
startFailed = true;
continue;
}
try
{
key = QString::fromUtf8(FS::read(liveCheckFile));
auto id = ApplicationId::fromRawString(key);
LocalPeer peer(nullptr, id);
if(peer.isClient())
{
startFailed = false;
qDebug() << "Found process started with key " << key;
break;
}
else
{
startFailed = true;
qDebug() << "Process started with key " << key << "apparently died or is not reponding...";
break;
}
}
catch (const Exception &e)
{
qWarning() << "Couldn't read the" << liveCheckFile << "file!";
startFailed = true;
continue;
}
}
}
if(startFailed)
{
m_failedOperationType = Start;
fail();
return;
}
else
{
origin.rmdir(m_updateFilesDir);
qApp->quit();
return;
}
}
void UpdateController::fail()
{
qWarning() << "Update failed!";
qWarning() << "Update failed!";
QString msg;
bool doRollback = false;
QString failTitle = QObject::tr("Update failed!");
QString rollFailTitle = QObject::tr("Rollback failed!");
switch (m_failedOperationType)
{
case Replace:
{
msg = QObject::tr("Couldn't replace file %1. Changes will be reverted.\n"
"See the MultiMC log file for details.").arg(m_failedFile);
doRollback = true;
QMessageBox::critical(m_parent, failTitle, msg);
break;
}
case Delete:
{
msg = QObject::tr("Couldn't remove file %1. Changes will be reverted.\n"
"See the MultiMC log file for details.").arg(m_failedFile);
doRollback = true;
QMessageBox::critical(m_parent, failTitle, msg);
break;
}
case Start:
{
msg = QObject::tr("The new version didn't start or is too old and doesn't respond to startup checks.\n"
"\n"
"Roll back to previous version?");
auto result = QMessageBox::critical(
m_parent,
failTitle,
msg,
QMessageBox::Yes | QMessageBox::No,
QMessageBox::Yes
);
doRollback = (result == QMessageBox::Yes);
break;
}
case Nothing:
default:
return;
}
if(doRollback)
{
auto rollbackOK = rollback();
if(!rollbackOK)
{
msg = QObject::tr("The rollback failed too.\n"
"You will have to repair MultiMC manually.\n"
"Please let us know why and how this happened.").arg(m_failedFile);
QMessageBox::critical(m_parent, rollFailTitle, msg);
qApp->quit();
}
}
else
{
qApp->quit();
}
QString msg;
bool doRollback = false;
QString failTitle = QObject::tr("Update failed!");
QString rollFailTitle = QObject::tr("Rollback failed!");
switch (m_failedOperationType)
{
case Replace:
{
msg = QObject::tr("Couldn't replace file %1. Changes will be reverted.\n"
"See the MultiMC log file for details.").arg(m_failedFile);
doRollback = true;
QMessageBox::critical(m_parent, failTitle, msg);
break;
}
case Delete:
{
msg = QObject::tr("Couldn't remove file %1. Changes will be reverted.\n"
"See the MultiMC log file for details.").arg(m_failedFile);
doRollback = true;
QMessageBox::critical(m_parent, failTitle, msg);
break;
}
case Start:
{
msg = QObject::tr("The new version didn't start or is too old and doesn't respond to startup checks.\n"
"\n"
"Roll back to previous version?");
auto result = QMessageBox::critical(
m_parent,
failTitle,
msg,
QMessageBox::Yes | QMessageBox::No,
QMessageBox::Yes
);
doRollback = (result == QMessageBox::Yes);
break;
}
case Nothing:
default:
return;
}
if(doRollback)
{
auto rollbackOK = rollback();
if(!rollbackOK)
{
msg = QObject::tr("The rollback failed too.\n"
"You will have to repair MultiMC manually.\n"
"Please let us know why and how this happened.").arg(m_failedFile);
QMessageBox::critical(m_parent, rollFailTitle, msg);
qApp->quit();
}
}
else
{
qApp->quit();
}
}
bool UpdateController::rollback()
{
bool revertOK = true;
// if the above failed, roll back changes
for(auto backup:m_replace_backups)
{
qWarning() << "restoring" << backup.original << "from" << backup.backup;
if(!QFile::rename(backup.original, backup.update))
{
revertOK = false;
qWarning() << "moving new" << backup.original << "back to" << backup.update << "failed!";
continue;
}
bool revertOK = true;
// if the above failed, roll back changes
for(auto backup:m_replace_backups)
{
qWarning() << "restoring" << backup.original << "from" << backup.backup;
if(!QFile::rename(backup.original, backup.update))
{
revertOK = false;
qWarning() << "moving new" << backup.original << "back to" << backup.update << "failed!";
continue;
}
if(!QFile::rename(backup.backup, backup.original))
{
revertOK = false;
qWarning() << "restoring" << backup.original << "failed!";
}
}
for(auto backup:m_delete_backups)
{
qWarning() << "restoring" << backup.original << "from" << backup.backup;
if(!QFile::rename(backup.backup, backup.original))
{
revertOK = false;
qWarning() << "restoring" << backup.original << "failed!";
}
}
return revertOK;
if(!QFile::rename(backup.backup, backup.original))
{
revertOK = false;
qWarning() << "restoring" << backup.original << "failed!";
}
}
for(auto backup:m_delete_backups)
{
qWarning() << "restoring" << backup.original << "from" << backup.backup;
if(!QFile::rename(backup.backup, backup.original))
{
revertOK = false;
qWarning() << "restoring" << backup.original << "failed!";
}
}
return revertOK;
}

View File

@ -9,36 +9,36 @@ class QWidget;
class UpdateController
{
public:
UpdateController(QWidget * parent, const QString &root, const QString updateFilesDir, GoUpdate::OperationList operations);
void installUpdates();
UpdateController(QWidget * parent, const QString &root, const QString updateFilesDir, GoUpdate::OperationList operations);
void installUpdates();
private:
void fail();
bool rollback();
void fail();
bool rollback();
private:
QString m_root;
QString m_updateFilesDir;
GoUpdate::OperationList m_operations;
QWidget * m_parent;
QString m_root;
QString m_updateFilesDir;
GoUpdate::OperationList m_operations;
QWidget * m_parent;
struct BackupEntry
{
// path where we got the new file from
QString update;
// path of what is being actually updated
QString original;
// path where the backup of the updated file was placed
QString backup;
};
QList <BackupEntry> m_replace_backups;
QList <BackupEntry> m_delete_backups;
enum Failure
{
Replace,
Delete,
Start,
Nothing
} m_failedOperationType = Nothing;
QString m_failedFile;
struct BackupEntry
{
// path where we got the new file from
QString update;
// path of what is being actually updated
QString original;
// path where the backup of the updated file was placed
QString backup;
};
QList <BackupEntry> m_replace_backups;
QList <BackupEntry> m_delete_backups;
enum Failure
{
Replace,
Delete,
Start,
Nothing
} m_failedOperationType = Nothing;
QString m_failedFile;
};

View File

@ -7,429 +7,429 @@
class VersionFilterModel : public QSortFilterProxyModel
{
Q_OBJECT
Q_OBJECT
public:
VersionFilterModel(VersionProxyModel *parent) : QSortFilterProxyModel(parent)
{
m_parent = parent;
setSortRole(BaseVersionList::SortRole);
sort(0, Qt::DescendingOrder);
}
VersionFilterModel(VersionProxyModel *parent) : QSortFilterProxyModel(parent)
{
m_parent = parent;
setSortRole(BaseVersionList::SortRole);
sort(0, Qt::DescendingOrder);
}
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
const auto &filters = m_parent->filters();
for (auto it = filters.begin(); it != filters.end(); ++it)
{
auto idx = sourceModel()->index(source_row, 0, source_parent);
auto data = sourceModel()->data(idx, it.key());
auto match = data.toString();
if(!it.value()->accepts(match))
{
return false;
}
}
return true;
}
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
const auto &filters = m_parent->filters();
for (auto it = filters.begin(); it != filters.end(); ++it)
{
auto idx = sourceModel()->index(source_row, 0, source_parent);
auto data = sourceModel()->data(idx, it.key());
auto match = data.toString();
if(!it.value()->accepts(match))
{
return false;
}
}
return true;
}
void filterChanged()
{
invalidateFilter();
}
void filterChanged()
{
invalidateFilter();
}
private:
VersionProxyModel *m_parent;
VersionProxyModel *m_parent;
};
VersionProxyModel::VersionProxyModel(QObject *parent) : QAbstractProxyModel(parent)
{
filterModel = new VersionFilterModel(this);
connect(filterModel, &QAbstractItemModel::dataChanged, this, &VersionProxyModel::sourceDataChanged);
connect(filterModel, &QAbstractItemModel::rowsAboutToBeInserted, this, &VersionProxyModel::sourceRowsAboutToBeInserted);
connect(filterModel, &QAbstractItemModel::rowsInserted, this, &VersionProxyModel::sourceRowsInserted);
connect(filterModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &VersionProxyModel::sourceRowsAboutToBeRemoved);
connect(filterModel, &QAbstractItemModel::rowsRemoved, this, &VersionProxyModel::sourceRowsRemoved);
// FIXME: implement when needed
/*
connect(replacing, &QAbstractItemModel::rowsAboutToBeMoved, this, &VersionProxyModel::sourceRowsAboutToBeMoved);
connect(replacing, &QAbstractItemModel::rowsMoved, this, &VersionProxyModel::sourceRowsMoved);
connect(replacing, &QAbstractItemModel::layoutAboutToBeChanged, this, &VersionProxyModel::sourceLayoutAboutToBeChanged);
connect(replacing, &QAbstractItemModel::layoutChanged, this, &VersionProxyModel::sourceLayoutChanged);
*/
connect(filterModel, &QAbstractItemModel::modelAboutToBeReset, this, &VersionProxyModel::sourceAboutToBeReset);
connect(filterModel, &QAbstractItemModel::modelReset, this, &VersionProxyModel::sourceReset);
filterModel = new VersionFilterModel(this);
connect(filterModel, &QAbstractItemModel::dataChanged, this, &VersionProxyModel::sourceDataChanged);
connect(filterModel, &QAbstractItemModel::rowsAboutToBeInserted, this, &VersionProxyModel::sourceRowsAboutToBeInserted);
connect(filterModel, &QAbstractItemModel::rowsInserted, this, &VersionProxyModel::sourceRowsInserted);
connect(filterModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &VersionProxyModel::sourceRowsAboutToBeRemoved);
connect(filterModel, &QAbstractItemModel::rowsRemoved, this, &VersionProxyModel::sourceRowsRemoved);
// FIXME: implement when needed
/*
connect(replacing, &QAbstractItemModel::rowsAboutToBeMoved, this, &VersionProxyModel::sourceRowsAboutToBeMoved);
connect(replacing, &QAbstractItemModel::rowsMoved, this, &VersionProxyModel::sourceRowsMoved);
connect(replacing, &QAbstractItemModel::layoutAboutToBeChanged, this, &VersionProxyModel::sourceLayoutAboutToBeChanged);
connect(replacing, &QAbstractItemModel::layoutChanged, this, &VersionProxyModel::sourceLayoutChanged);
*/
connect(filterModel, &QAbstractItemModel::modelAboutToBeReset, this, &VersionProxyModel::sourceAboutToBeReset);
connect(filterModel, &QAbstractItemModel::modelReset, this, &VersionProxyModel::sourceReset);
QAbstractProxyModel::setSourceModel(filterModel);
QAbstractProxyModel::setSourceModel(filterModel);
}
QVariant VersionProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if(section < 0 || section >= m_columns.size())
return QVariant();
if(orientation != Qt::Horizontal)
return QVariant();
auto column = m_columns[section];
if(role == Qt::DisplayRole)
{
switch(column)
{
case Name:
return tr("Version");
case ParentVersion:
return tr("Minecraft"); //FIXME: this should come from metadata
case Branch:
return tr("Branch");
case Type:
return tr("Type");
case Architecture:
return tr("Architecture");
case Path:
return tr("Path");
case Time:
return tr("Released");
}
}
else if(role == Qt::ToolTipRole)
{
switch(column)
{
case Name:
return tr("The name of the version.");
case ParentVersion:
return tr("Minecraft version"); //FIXME: this should come from metadata
case Branch:
return tr("The version's branch");
case Type:
return tr("The version's type");
case Architecture:
return tr("CPU Architecture");
case Path:
return tr("Filesystem path to this version");
case Time:
return tr("Release date of this version");
}
}
return QVariant();
if(section < 0 || section >= m_columns.size())
return QVariant();
if(orientation != Qt::Horizontal)
return QVariant();
auto column = m_columns[section];
if(role == Qt::DisplayRole)
{
switch(column)
{
case Name:
return tr("Version");
case ParentVersion:
return tr("Minecraft"); //FIXME: this should come from metadata
case Branch:
return tr("Branch");
case Type:
return tr("Type");
case Architecture:
return tr("Architecture");
case Path:
return tr("Path");
case Time:
return tr("Released");
}
}
else if(role == Qt::ToolTipRole)
{
switch(column)
{
case Name:
return tr("The name of the version.");
case ParentVersion:
return tr("Minecraft version"); //FIXME: this should come from metadata
case Branch:
return tr("The version's branch");
case Type:
return tr("The version's type");
case Architecture:
return tr("CPU Architecture");
case Path:
return tr("Filesystem path to this version");
case Time:
return tr("Release date of this version");
}
}
return QVariant();
}
QVariant VersionProxyModel::data(const QModelIndex &index, int role) const
{
if(!index.isValid())
{
return QVariant();
}
auto column = m_columns[index.column()];
auto parentIndex = mapToSource(index);
switch(role)
{
case Qt::DisplayRole:
{
switch(column)
{
case Name:
return sourceModel()->data(parentIndex, BaseVersionList::VersionRole);
case ParentVersion:
return sourceModel()->data(parentIndex, BaseVersionList::ParentVersionRole);
case Branch:
return sourceModel()->data(parentIndex, BaseVersionList::BranchRole);
case Type:
return sourceModel()->data(parentIndex, BaseVersionList::TypeRole);
case Architecture:
return sourceModel()->data(parentIndex, BaseVersionList::ArchitectureRole);
case Path:
return sourceModel()->data(parentIndex, BaseVersionList::PathRole);
case Time:
return sourceModel()->data(parentIndex, Meta::VersionList::TimeRole).toDate();
default:
return QVariant();
}
}
case Qt::ToolTipRole:
{
switch(column)
{
case Name:
{
if(hasRecommended)
{
auto value = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole);
if(value.toBool())
{
return tr("Recommended");
}
else if(hasLatest)
{
auto value = sourceModel()->data(parentIndex, BaseVersionList::LatestRole);
if(value.toBool())
{
return tr("Latest");
}
}
else if(index.row() == 0)
{
return tr("Latest");
}
}
}
default:
{
return sourceModel()->data(parentIndex, BaseVersionList::VersionIdRole);
}
}
}
case Qt::DecorationRole:
{
switch(column)
{
case Name:
{
if(hasRecommended)
{
auto value = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole);
if(value.toBool())
{
return MMC->getThemedIcon("star");
}
else if(hasLatest)
{
auto value = sourceModel()->data(parentIndex, BaseVersionList::LatestRole);
if(value.toBool())
{
return MMC->getThemedIcon("bug");
}
}
else if(index.row() == 0)
{
return MMC->getThemedIcon("bug");
}
auto pixmap = QPixmapCache::find("placeholder");
if(!pixmap)
{
QPixmap px(16,16);
px.fill(Qt::transparent);
QPixmapCache::insert("placeholder", px);
return px;
}
return *pixmap;
}
}
default:
{
return QVariant();
}
}
}
default:
{
if(roles.contains((BaseVersionList::ModelRoles)role))
{
return sourceModel()->data(parentIndex, role);
}
return QVariant();
}
}
if(!index.isValid())
{
return QVariant();
}
auto column = m_columns[index.column()];
auto parentIndex = mapToSource(index);
switch(role)
{
case Qt::DisplayRole:
{
switch(column)
{
case Name:
return sourceModel()->data(parentIndex, BaseVersionList::VersionRole);
case ParentVersion:
return sourceModel()->data(parentIndex, BaseVersionList::ParentVersionRole);
case Branch:
return sourceModel()->data(parentIndex, BaseVersionList::BranchRole);
case Type:
return sourceModel()->data(parentIndex, BaseVersionList::TypeRole);
case Architecture:
return sourceModel()->data(parentIndex, BaseVersionList::ArchitectureRole);
case Path:
return sourceModel()->data(parentIndex, BaseVersionList::PathRole);
case Time:
return sourceModel()->data(parentIndex, Meta::VersionList::TimeRole).toDate();
default:
return QVariant();
}
}
case Qt::ToolTipRole:
{
switch(column)
{
case Name:
{
if(hasRecommended)
{
auto value = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole);
if(value.toBool())
{
return tr("Recommended");
}
else if(hasLatest)
{
auto value = sourceModel()->data(parentIndex, BaseVersionList::LatestRole);
if(value.toBool())
{
return tr("Latest");
}
}
else if(index.row() == 0)
{
return tr("Latest");
}
}
}
default:
{
return sourceModel()->data(parentIndex, BaseVersionList::VersionIdRole);
}
}
}
case Qt::DecorationRole:
{
switch(column)
{
case Name:
{
if(hasRecommended)
{
auto value = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole);
if(value.toBool())
{
return MMC->getThemedIcon("star");
}
else if(hasLatest)
{
auto value = sourceModel()->data(parentIndex, BaseVersionList::LatestRole);
if(value.toBool())
{
return MMC->getThemedIcon("bug");
}
}
else if(index.row() == 0)
{
return MMC->getThemedIcon("bug");
}
auto pixmap = QPixmapCache::find("placeholder");
if(!pixmap)
{
QPixmap px(16,16);
px.fill(Qt::transparent);
QPixmapCache::insert("placeholder", px);
return px;
}
return *pixmap;
}
}
default:
{
return QVariant();
}
}
}
default:
{
if(roles.contains((BaseVersionList::ModelRoles)role))
{
return sourceModel()->data(parentIndex, role);
}
return QVariant();
}
}
}
QModelIndex VersionProxyModel::parent(const QModelIndex &child) const
{
return QModelIndex();
return QModelIndex();
}
QModelIndex VersionProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
{
if(sourceIndex.isValid())
{
return index(sourceIndex.row(), 0);
}
return QModelIndex();
if(sourceIndex.isValid())
{
return index(sourceIndex.row(), 0);
}
return QModelIndex();
}
QModelIndex VersionProxyModel::mapToSource(const QModelIndex &proxyIndex) const
{
if(proxyIndex.isValid())
{
return sourceModel()->index(proxyIndex.row(), 0);
}
return QModelIndex();
if(proxyIndex.isValid())
{
return sourceModel()->index(proxyIndex.row(), 0);
}
return QModelIndex();
}
QModelIndex VersionProxyModel::index(int row, int column, const QModelIndex &parent) const
{
// no trees here... shoo
if(parent.isValid())
{
return QModelIndex();
}
if(row < 0 || row >= sourceModel()->rowCount())
return QModelIndex();
if(column < 0 || column >= columnCount())
return QModelIndex();
return QAbstractItemModel::createIndex(row, column);
// no trees here... shoo
if(parent.isValid())
{
return QModelIndex();
}
if(row < 0 || row >= sourceModel()->rowCount())
return QModelIndex();
if(column < 0 || column >= columnCount())
return QModelIndex();
return QAbstractItemModel::createIndex(row, column);
}
int VersionProxyModel::columnCount(const QModelIndex &parent) const
{
return m_columns.size();
return m_columns.size();
}
int VersionProxyModel::rowCount(const QModelIndex &parent) const
{
if(sourceModel())
{
return sourceModel()->rowCount();
}
return 0;
if(sourceModel())
{
return sourceModel()->rowCount();
}
return 0;
}
void VersionProxyModel::sourceDataChanged(const QModelIndex &source_top_left,
const QModelIndex &source_bottom_right)
const QModelIndex &source_bottom_right)
{
if(source_top_left.parent() != source_bottom_right.parent())
return;
if(source_top_left.parent() != source_bottom_right.parent())
return;
// whole row is getting changed
auto topLeft = createIndex(source_top_left.row(), 0);
auto bottomRight = createIndex(source_bottom_right.row(), columnCount() - 1);
emit dataChanged(topLeft, bottomRight);
// whole row is getting changed
auto topLeft = createIndex(source_top_left.row(), 0);
auto bottomRight = createIndex(source_bottom_right.row(), columnCount() - 1);
emit dataChanged(topLeft, bottomRight);
}
void VersionProxyModel::setSourceModel(QAbstractItemModel *replacingRaw)
{
auto replacing = dynamic_cast<BaseVersionList *>(replacingRaw);
beginResetModel();
auto replacing = dynamic_cast<BaseVersionList *>(replacingRaw);
beginResetModel();
m_columns.clear();
if(!replacing)
{
roles.clear();
filterModel->setSourceModel(replacing);
return;
}
m_columns.clear();
if(!replacing)
{
roles.clear();
filterModel->setSourceModel(replacing);
return;
}
roles = replacing->providesRoles();
if(roles.contains(BaseVersionList::VersionRole))
{
m_columns.push_back(Name);
}
/*
if(roles.contains(BaseVersionList::ParentVersionRole))
{
m_columns.push_back(ParentVersion);
}
*/
if(roles.contains(BaseVersionList::ArchitectureRole))
{
m_columns.push_back(Architecture);
}
if(roles.contains(BaseVersionList::PathRole))
{
m_columns.push_back(Path);
}
if(roles.contains(Meta::VersionList::TimeRole))
{
m_columns.push_back(Time);
}
if(roles.contains(BaseVersionList::BranchRole))
{
m_columns.push_back(Branch);
}
if(roles.contains(BaseVersionList::TypeRole))
{
m_columns.push_back(Type);
}
if(roles.contains(BaseVersionList::RecommendedRole))
{
hasRecommended = true;
}
if(roles.contains(BaseVersionList::LatestRole))
{
hasLatest = true;
}
filterModel->setSourceModel(replacing);
roles = replacing->providesRoles();
if(roles.contains(BaseVersionList::VersionRole))
{
m_columns.push_back(Name);
}
/*
if(roles.contains(BaseVersionList::ParentVersionRole))
{
m_columns.push_back(ParentVersion);
}
*/
if(roles.contains(BaseVersionList::ArchitectureRole))
{
m_columns.push_back(Architecture);
}
if(roles.contains(BaseVersionList::PathRole))
{
m_columns.push_back(Path);
}
if(roles.contains(Meta::VersionList::TimeRole))
{
m_columns.push_back(Time);
}
if(roles.contains(BaseVersionList::BranchRole))
{
m_columns.push_back(Branch);
}
if(roles.contains(BaseVersionList::TypeRole))
{
m_columns.push_back(Type);
}
if(roles.contains(BaseVersionList::RecommendedRole))
{
hasRecommended = true;
}
if(roles.contains(BaseVersionList::LatestRole))
{
hasLatest = true;
}
filterModel->setSourceModel(replacing);
endResetModel();
endResetModel();
}
QModelIndex VersionProxyModel::getRecommended() const
{
if(!roles.contains(BaseVersionList::RecommendedRole))
{
return index(0, 0);
}
int recommended = 0;
for (int i = 0; i < rowCount(); i++)
{
auto value = sourceModel()->data(mapToSource(index(i, 0)), BaseVersionList::RecommendedRole);
if (value.toBool())
{
recommended = i;
}
}
return index(recommended, 0);
if(!roles.contains(BaseVersionList::RecommendedRole))
{
return index(0, 0);
}
int recommended = 0;
for (int i = 0; i < rowCount(); i++)
{
auto value = sourceModel()->data(mapToSource(index(i, 0)), BaseVersionList::RecommendedRole);
if (value.toBool())
{
recommended = i;
}
}
return index(recommended, 0);
}
QModelIndex VersionProxyModel::getVersion(const QString& version) const
{
int found = -1;
for (int i = 0; i < rowCount(); i++)
{
auto value = sourceModel()->data(mapToSource(index(i, 0)), BaseVersionList::VersionRole);
if (value.toString() == version)
{
found = i;
}
}
if(found == -1)
{
return QModelIndex();
}
return index(found, 0);
int found = -1;
for (int i = 0; i < rowCount(); i++)
{
auto value = sourceModel()->data(mapToSource(index(i, 0)), BaseVersionList::VersionRole);
if (value.toString() == version)
{
found = i;
}
}
if(found == -1)
{
return QModelIndex();
}
return index(found, 0);
}
void VersionProxyModel::clearFilters()
{
m_filters.clear();
filterModel->filterChanged();
m_filters.clear();
filterModel->filterChanged();
}
void VersionProxyModel::setFilter(const BaseVersionList::ModelRoles column, Filter * f)
{
m_filters[column].reset(f);
filterModel->filterChanged();
m_filters[column].reset(f);
filterModel->filterChanged();
}
const VersionProxyModel::FilterMap &VersionProxyModel::filters() const
{
return m_filters;
return m_filters;
}
void VersionProxyModel::sourceAboutToBeReset()
{
beginResetModel();
beginResetModel();
}
void VersionProxyModel::sourceReset()
{
endResetModel();
endResetModel();
}
void VersionProxyModel::sourceRowsAboutToBeInserted(const QModelIndex& parent, int first, int last)
{
beginInsertRows(parent, first, last);
beginInsertRows(parent, first, last);
}
void VersionProxyModel::sourceRowsInserted(const QModelIndex& parent, int first, int last)
{
endInsertRows();
endInsertRows();
}
void VersionProxyModel::sourceRowsAboutToBeRemoved(const QModelIndex& parent, int first, int last)
{
beginRemoveRows(parent, first, last);
beginRemoveRows(parent, first, last);
}
void VersionProxyModel::sourceRowsRemoved(const QModelIndex& parent, int first, int last)
{
endRemoveRows();
endRemoveRows();
}

View File

@ -8,58 +8,58 @@ class VersionFilterModel;
class VersionProxyModel: public QAbstractProxyModel
{
Q_OBJECT
Q_OBJECT
public:
enum Column
{
Name,
ParentVersion,
Branch,
Type,
Architecture,
Path,
Time
};
typedef QHash<BaseVersionList::ModelRoles, std::shared_ptr<Filter>> FilterMap;
enum Column
{
Name,
ParentVersion,
Branch,
Type,
Architecture,
Path,
Time
};
typedef QHash<BaseVersionList::ModelRoles, std::shared_ptr<Filter>> FilterMap;
public:
VersionProxyModel ( QObject* parent = 0 );
virtual ~VersionProxyModel() {};
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override;
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override;
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const override;
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
virtual QModelIndex parent(const QModelIndex &child) const override;
virtual void setSourceModel(QAbstractItemModel *sourceModel) override;
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override;
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override;
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const override;
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
virtual QModelIndex parent(const QModelIndex &child) const override;
virtual void setSourceModel(QAbstractItemModel *sourceModel) override;
const FilterMap &filters() const;
void setFilter(const BaseVersionList::ModelRoles column, Filter * filter);
void clearFilters();
QModelIndex getRecommended() const;
QModelIndex getVersion(const QString & version) const;
const FilterMap &filters() const;
void setFilter(const BaseVersionList::ModelRoles column, Filter * filter);
void clearFilters();
QModelIndex getRecommended() const;
QModelIndex getVersion(const QString & version) const;
private slots:
void sourceDataChanged(const QModelIndex &source_top_left,const QModelIndex &source_bottom_right);
void sourceDataChanged(const QModelIndex &source_top_left,const QModelIndex &source_bottom_right);
void sourceAboutToBeReset();
void sourceReset();
void sourceAboutToBeReset();
void sourceReset();
void sourceRowsAboutToBeInserted(const QModelIndex &parent, int first, int last);
void sourceRowsInserted(const QModelIndex &parent, int first, int last);
void sourceRowsAboutToBeInserted(const QModelIndex &parent, int first, int last);
void sourceRowsInserted(const QModelIndex &parent, int first, int last);
void sourceRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last);
void sourceRowsRemoved(const QModelIndex &parent, int first, int last);
void sourceRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last);
void sourceRowsRemoved(const QModelIndex &parent, int first, int last);
private:
QList<Column> m_columns;
FilterMap m_filters;
BaseVersionList::RoleList roles;
VersionFilterModel * filterModel;
bool hasRecommended = false;
bool hasLatest = false;
QList<Column> m_columns;
FilterMap m_filters;
BaseVersionList::RoleList roles;
VersionFilterModel * filterModel;
bool hasRecommended = false;
bool hasLatest = false;
};

View File

@ -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 &lt;<a href='mailto:forkk@forkk.net'>forkk@forkk.net</a>&gt;</p>"
"<p>Petr Mrázek &lt;<a href='mailto:peterix@gmail.com'>peterix@gmail.com</a>&gt;</p>"
"<p>Sky Welch &lt;<a href='mailto:multimc@bunnies.io'>multimc@bunnies.io</a>&gt;</p>"
"<p>Jan (02JanDal) &lt;<a href='mailto:02jandal@gmail.com'>02jandal@gmail.com</a>&gt;</p>"
"<p>RoboSky &lt;<a href='https://twitter.com/RoboSky_'>@RoboSky_</a>&gt;</p>"
""
"<h3>With thanks to</h3>"
"<p>Orochimarufan &lt;<a href='mailto:orochimarufan.x3@gmail.com'>orochimarufan.x3@gmail.com</a>&gt;</p>"
"<p>TakSuyu &lt;<a href='mailto:taksuyu@gmail.com'>taksuyu@gmail.com</a>&gt;</p>"
"<p>Kilobyte &lt;<a href='mailto:stiepen22@gmx.de'>stiepen22@gmx.de</a>&gt;</p>"
"<p>Rootbear75 &lt;<a href='https://twitter.com/rootbear75'>@rootbear75</a>&gt;</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 &lt;<a href='mailto:forkk@forkk.net'>forkk@forkk.net</a>&gt;</p>"
"<p>Petr Mrázek &lt;<a href='mailto:peterix@gmail.com'>peterix@gmail.com</a>&gt;</p>"
"<p>Sky Welch &lt;<a href='mailto:multimc@bunnies.io'>multimc@bunnies.io</a>&gt;</p>"
"<p>Jan (02JanDal) &lt;<a href='mailto:02jandal@gmail.com'>02jandal@gmail.com</a>&gt;</p>"
"<p>RoboSky &lt;<a href='https://twitter.com/RoboSky_'>@RoboSky_</a>&gt;</p>"
""
"<h3>With thanks to</h3>"
"<p>Orochimarufan &lt;<a href='mailto:orochimarufan.x3@gmail.com'>orochimarufan.x3@gmail.com</a>&gt;</p>"
"<p>TakSuyu &lt;<a href='mailto:taksuyu@gmail.com'>taksuyu@gmail.com</a>&gt;</p>"
"<p>Kilobyte &lt;<a href='mailto:stiepen22@gmx.de'>stiepen22@gmx.de</a>&gt;</p>"
"<p>Rootbear75 &lt;<a href='https://twitter.com/rootbear75'>@rootbear75</a>&gt;</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);
}

View File

@ -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;
};

View File

@ -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;
}
}

View File

@ -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;
};

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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;
};

View File

@ -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"

View File

@ -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);
};

View File

@ -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);
}

View File

@ -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();
};

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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());
}

View File

@ -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();
};

View File

@ -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);
}

View File

@ -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

View File

@ -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();
}

View File

@ -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;
};

View File

@ -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);
}
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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;
};

File diff suppressed because it is too large Load Diff

View File

@ -23,126 +23,126 @@
struct GroupViewRoles
{
enum
{
GroupRole = Qt::UserRole,
ProgressValueRole,
ProgressMaximumRole
};
enum
{
GroupRole = Qt::UserRole,
ProgressValueRole,
ProgressMaximumRole
};
};
class GroupView : public QAbstractItemView
{
Q_OBJECT
Q_OBJECT
public:
GroupView(QWidget *parent = 0);
~GroupView();
GroupView(QWidget *parent = 0);
~GroupView();
void setModel(QAbstractItemModel *model) override;
void setModel(QAbstractItemModel *model) override;
/// return geometry rectangle occupied by the specified model item
QRect geometryRect(const QModelIndex &index) const;
/// return visual rectangle occupied by the specified model item
virtual QRect visualRect(const QModelIndex &index) const override;
/// get the model index at the specified visual point
virtual QModelIndex indexAt(const QPoint &point) const override;
QString groupNameAt(const QPoint &point);
void setSelection(const QRect &rect,
const QItemSelectionModel::SelectionFlags commands) override;
/// return geometry rectangle occupied by the specified model item
QRect geometryRect(const QModelIndex &index) const;
/// return visual rectangle occupied by the specified model item
virtual QRect visualRect(const QModelIndex &index) const override;
/// get the model index at the specified visual point
virtual QModelIndex indexAt(const QPoint &point) const override;
QString groupNameAt(const QPoint &point);
void setSelection(const QRect &rect,
const QItemSelectionModel::SelectionFlags commands) override;
virtual int horizontalOffset() const override;
virtual int verticalOffset() const override;
virtual void scrollContentsBy(int dx, int dy) override;
virtual void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible) override;
virtual int horizontalOffset() const override;
virtual int verticalOffset() const override;
virtual void scrollContentsBy(int dx, int dy) override;
virtual void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible) override;
virtual QModelIndex moveCursor(CursorAction cursorAction,
Qt::KeyboardModifiers modifiers) override;
virtual QModelIndex moveCursor(CursorAction cursorAction,
Qt::KeyboardModifiers modifiers) override;
virtual QRegion visualRegionForSelection(const QItemSelection &selection) const override;
virtual QRegion visualRegionForSelection(const QItemSelection &selection) const override;
int spacing() const
{
return m_spacing;
};
int spacing() const
{
return m_spacing;
};
public slots:
virtual void updateGeometries() override;
virtual void updateGeometries() override;
protected slots:
virtual void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
const QVector<int> &roles) override;
virtual void rowsInserted(const QModelIndex &parent, int start, int end) override;
virtual void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) override;
void modelReset();
void rowsRemoved();
virtual void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
const QVector<int> &roles) override;
virtual void rowsInserted(const QModelIndex &parent, int start, int end) override;
virtual void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) override;
void modelReset();
void rowsRemoved();
signals:
void droppedURLs(QList<QUrl> urls);
void droppedURLs(QList<QUrl> urls);
protected:
virtual bool isIndexHidden(const QModelIndex &index) const override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void mouseDoubleClickEvent(QMouseEvent *event) override;
void paintEvent(QPaintEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
virtual bool isIndexHidden(const QModelIndex &index) const override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void mouseDoubleClickEvent(QMouseEvent *event) override;
void paintEvent(QPaintEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
void dragEnterEvent(QDragEnterEvent *event) override;
void dragMoveEvent(QDragMoveEvent *event) override;
void dragLeaveEvent(QDragLeaveEvent *event) override;
void dropEvent(QDropEvent *event) override;
void dragEnterEvent(QDragEnterEvent *event) override;
void dragMoveEvent(QDragMoveEvent *event) override;
void dragLeaveEvent(QDragLeaveEvent *event) override;
void dropEvent(QDropEvent *event) override;
void startDrag(Qt::DropActions supportedActions) override;
void startDrag(Qt::DropActions supportedActions) override;
void updateScrollbar();
void updateScrollbar();
private:
friend struct VisualGroup;
QList<VisualGroup *> m_groups;
friend struct VisualGroup;
QList<VisualGroup *> m_groups;
// geometry
int m_leftMargin = 5;
int m_rightMargin = 5;
int m_bottomMargin = 5;
int m_categoryMargin = 5;
int m_spacing = 5;
int m_itemWidth = 100;
int m_currentItemsPerRow = -1;
int m_currentCursorColumn= -1;
mutable QCache<int, QRect> geometryCache;
// geometry
int m_leftMargin = 5;
int m_rightMargin = 5;
int m_bottomMargin = 5;
int m_categoryMargin = 5;
int m_spacing = 5;
int m_itemWidth = 100;
int m_currentItemsPerRow = -1;
int m_currentCursorColumn= -1;
mutable QCache<int, QRect> geometryCache;
// point where the currently active mouse action started in geometry coordinates
QPoint m_pressedPosition;
QPersistentModelIndex m_pressedIndex;
bool m_pressedAlreadySelected;
VisualGroup *m_pressedCategory;
QItemSelectionModel::SelectionFlag m_ctrlDragSelectionFlag;
QPoint m_lastDragPosition;
// point where the currently active mouse action started in geometry coordinates
QPoint m_pressedPosition;
QPersistentModelIndex m_pressedIndex;
bool m_pressedAlreadySelected;
VisualGroup *m_pressedCategory;
QItemSelectionModel::SelectionFlag m_ctrlDragSelectionFlag;
QPoint m_lastDragPosition;
VisualGroup *category(const QModelIndex &index) const;
VisualGroup *category(const QString &cat) const;
VisualGroup *categoryAt(const QPoint &pos, VisualGroup::HitResults & result) const;
VisualGroup *category(const QModelIndex &index) const;
VisualGroup *category(const QString &cat) const;
VisualGroup *categoryAt(const QPoint &pos, VisualGroup::HitResults & result) const;
int itemsPerRow() const
{
return m_currentItemsPerRow;
};
int contentWidth() const;
int itemsPerRow() const
{
return m_currentItemsPerRow;
};
int contentWidth() const;
private: /* methods */
int itemWidth() const;
int calculateItemsPerRow() const;
int verticalScrollToValue(const QModelIndex &index, const QRect &rect,
QListView::ScrollHint hint) const;
QPixmap renderToPixmap(const QModelIndexList &indices, QRect *r) const;
QList<QPair<QRect, QModelIndex>> draggablePaintPairs(const QModelIndexList &indices,
QRect *r) const;
int itemWidth() const;
int calculateItemsPerRow() const;
int verticalScrollToValue(const QModelIndex &index, const QRect &rect,
QListView::ScrollHint hint) const;
QPixmap renderToPixmap(const QModelIndexList &indices, QRect *r) const;
QList<QPair<QRect, QModelIndex>> draggablePaintPairs(const QModelIndexList &indices,
QRect *r) const;
bool isDragEventAccepted(QDropEvent *event);
bool isDragEventAccepted(QDropEvent *event);
QPair<VisualGroup *, int> rowDropPos(const QPoint &pos);
QPair<VisualGroup *, int> rowDropPos(const QPoint &pos);
QPoint offset() const;
QPoint offset() const;
};

View File

@ -24,25 +24,25 @@ GroupedProxyModel::GroupedProxyModel(QObject *parent) : QSortFilterProxyModel(pa
bool GroupedProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
const QString leftCategory = left.data(GroupViewRoles::GroupRole).toString();
const QString rightCategory = right.data(GroupViewRoles::GroupRole).toString();
if (leftCategory == rightCategory)
{
return subSortLessThan(left, right);
}
else
{
// FIXME: real group sorting happens in GroupView::updateGeometries(), see LocaleString
auto result = leftCategory.localeAwareCompare(rightCategory);
if(result == 0)
{
return subSortLessThan(left, right);
}
return result < 0;
}
const QString leftCategory = left.data(GroupViewRoles::GroupRole).toString();
const QString rightCategory = right.data(GroupViewRoles::GroupRole).toString();
if (leftCategory == rightCategory)
{
return subSortLessThan(left, right);
}
else
{
// FIXME: real group sorting happens in GroupView::updateGeometries(), see LocaleString
auto result = leftCategory.localeAwareCompare(rightCategory);
if(result == 0)
{
return subSortLessThan(left, right);
}
return result < 0;
}
}
bool GroupedProxyModel::subSortLessThan(const QModelIndex &left, const QModelIndex &right) const
{
return left.row() < right.row();
return left.row() < right.row();
}

View File

@ -19,12 +19,12 @@
class GroupedProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
Q_OBJECT
public:
GroupedProxyModel(QObject *parent = 0);
GroupedProxyModel(QObject *parent = 0);
protected:
virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
virtual bool subSortLessThan(const QModelIndex &left, const QModelIndex &right) const;
virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
virtual bool subSortLessThan(const QModelIndex &left, const QModelIndex &right) const;
};

View File

@ -27,25 +27,25 @@
// Origin: Qt
static void viewItemTextLayout(QTextLayout &textLayout, int lineWidth, qreal &height,
qreal &widthUsed)
qreal &widthUsed)
{
height = 0;
widthUsed = 0;
textLayout.beginLayout();
QString str = textLayout.text();
while (true)
{
QTextLine line = textLayout.createLine();
if (!line.isValid())
break;
if (line.textLength() == 0)
break;
line.setLineWidth(lineWidth);
line.setPosition(QPointF(0, height));
height += line.height();
widthUsed = qMax(widthUsed, line.naturalTextWidth());
}
textLayout.endLayout();
height = 0;
widthUsed = 0;
textLayout.beginLayout();
QString str = textLayout.text();
while (true)
{
QTextLine line = textLayout.createLine();
if (!line.isValid())
break;
if (line.textLength() == 0)
break;
line.setLineWidth(lineWidth);
line.setPosition(QPointF(0, height));
height += line.height();
widthUsed = qMax(widthUsed, line.naturalTextWidth());
}
textLayout.endLayout();
}
ListViewDelegate::ListViewDelegate(QObject *parent) : QStyledItemDelegate(parent)
@ -53,291 +53,291 @@ ListViewDelegate::ListViewDelegate(QObject *parent) : QStyledItemDelegate(parent
}
void drawSelectionRect(QPainter *painter, const QStyleOptionViewItem &option,
const QRect &rect)
const QRect &rect)
{
if ((option.state & QStyle::State_Selected))
painter->fillRect(rect, option.palette.brush(QPalette::Highlight));
else
{
QColor backgroundColor = option.palette.color(QPalette::Background);
backgroundColor.setAlpha(160);
painter->fillRect(rect, QBrush(backgroundColor));
}
if ((option.state & QStyle::State_Selected))
painter->fillRect(rect, option.palette.brush(QPalette::Highlight));
else
{
QColor backgroundColor = option.palette.color(QPalette::Background);
backgroundColor.setAlpha(160);
painter->fillRect(rect, QBrush(backgroundColor));
}
}
void drawFocusRect(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect)
{
if (!(option.state & QStyle::State_HasFocus))
return;
QStyleOptionFocusRect opt;
opt.direction = option.direction;
opt.fontMetrics = option.fontMetrics;
opt.palette = option.palette;
opt.rect = rect;
// opt.state = option.state | QStyle::State_KeyboardFocusChange |
// QStyle::State_Item;
auto col = option.state & QStyle::State_Selected ? QPalette::Highlight : QPalette::Base;
opt.backgroundColor = option.palette.color(col);
// Apparently some widget styles expect this hint to not be set
painter->setRenderHint(QPainter::Antialiasing, false);
if (!(option.state & QStyle::State_HasFocus))
return;
QStyleOptionFocusRect opt;
opt.direction = option.direction;
opt.fontMetrics = option.fontMetrics;
opt.palette = option.palette;
opt.rect = rect;
// opt.state = option.state | QStyle::State_KeyboardFocusChange |
// QStyle::State_Item;
auto col = option.state & QStyle::State_Selected ? QPalette::Highlight : QPalette::Base;
opt.backgroundColor = option.palette.color(col);
// Apparently some widget styles expect this hint to not be set
painter->setRenderHint(QPainter::Antialiasing, false);
QStyle *style = option.widget ? option.widget->style() : QApplication::style();
QStyle *style = option.widget ? option.widget->style() : QApplication::style();
style->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, painter, option.widget);
style->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, painter, option.widget);
painter->setRenderHint(QPainter::Antialiasing);
painter->setRenderHint(QPainter::Antialiasing);
}
// TODO this can be made a lot prettier
void drawProgressOverlay(QPainter *painter, const QStyleOptionViewItem &option,
const int value, const int maximum)
const int value, const int maximum)
{
if (maximum == 0 || value == maximum)
{
return;
}
if (maximum == 0 || value == maximum)
{
return;
}
painter->save();
painter->save();
qreal percent = (qreal)value / (qreal)maximum;
QColor color = option.palette.color(QPalette::Dark);
color.setAlphaF(0.70f);
painter->setBrush(color);
painter->setPen(QPen(QBrush(), 0));
painter->drawPie(option.rect, 90 * 16, -percent * 360 * 16);
qreal percent = (qreal)value / (qreal)maximum;
QColor color = option.palette.color(QPalette::Dark);
color.setAlphaF(0.70f);
painter->setBrush(color);
painter->setPen(QPen(QBrush(), 0));
painter->drawPie(option.rect, 90 * 16, -percent * 360 * 16);
painter->restore();
painter->restore();
}
void drawBadges(QPainter *painter, const QStyleOptionViewItem &option, BaseInstance *instance, QIcon::Mode mode, QIcon::State state)
{
QList<QString> pixmaps;
if (instance->isRunning())
{
pixmaps.append("status-running");
}
else if (instance->hasCrashed() || instance->hasVersionBroken())
{
pixmaps.append("status-bad");
}
if (instance->hasUpdateAvailable())
{
pixmaps.append("checkupdate");
}
QList<QString> pixmaps;
if (instance->isRunning())
{
pixmaps.append("status-running");
}
else if (instance->hasCrashed() || instance->hasVersionBroken())
{
pixmaps.append("status-bad");
}
if (instance->hasUpdateAvailable())
{
pixmaps.append("checkupdate");
}
static const int itemSide = 24;
static const int spacing = 1;
const int itemsPerRow = qMax(1, qFloor(double(option.rect.width() + spacing) / double(itemSide + spacing)));
const int rows = qCeil((double)pixmaps.size() / (double)itemsPerRow);
QListIterator<QString> it(pixmaps);
painter->translate(option.rect.topLeft());
for (int y = 0; y < rows; ++y)
{
for (int x = 0; x < itemsPerRow; ++x)
{
if (!it.hasNext())
{
return;
}
// FIXME: inject this.
auto icon = XdgIcon::fromTheme(it.next());
// opt.icon.paint(painter, iconbox, Qt::AlignCenter, mode, state);
const QPixmap pixmap;
// itemSide
QRect badgeRect(
option.rect.width() - x * itemSide + qMax(x - 1, 0) * spacing - itemSide,
y * itemSide + qMax(y - 1, 0) * spacing,
itemSide,
itemSide
);
icon.paint(painter, badgeRect, Qt::AlignCenter, mode, state);
}
}
painter->translate(-option.rect.topLeft());
static const int itemSide = 24;
static const int spacing = 1;
const int itemsPerRow = qMax(1, qFloor(double(option.rect.width() + spacing) / double(itemSide + spacing)));
const int rows = qCeil((double)pixmaps.size() / (double)itemsPerRow);
QListIterator<QString> it(pixmaps);
painter->translate(option.rect.topLeft());
for (int y = 0; y < rows; ++y)
{
for (int x = 0; x < itemsPerRow; ++x)
{
if (!it.hasNext())
{
return;
}
// FIXME: inject this.
auto icon = XdgIcon::fromTheme(it.next());
// opt.icon.paint(painter, iconbox, Qt::AlignCenter, mode, state);
const QPixmap pixmap;
// itemSide
QRect badgeRect(
option.rect.width() - x * itemSide + qMax(x - 1, 0) * spacing - itemSide,
y * itemSide + qMax(y - 1, 0) * spacing,
itemSide,
itemSide
);
icon.paint(painter, badgeRect, Qt::AlignCenter, mode, state);
}
}
painter->translate(-option.rect.topLeft());
}
static QSize viewItemTextSize(const QStyleOptionViewItem *option)
{
QStyle *style = option->widget ? option->widget->style() : QApplication::style();
QTextOption textOption;
textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
QTextLayout textLayout;
textLayout.setTextOption(textOption);
textLayout.setFont(option->font);
textLayout.setText(option->text);
const int textMargin =
style->pixelMetric(QStyle::PM_FocusFrameHMargin, option, option->widget) + 1;
QRect bounds(0, 0, 100 - 2 * textMargin, 600);
qreal height = 0, widthUsed = 0;
viewItemTextLayout(textLayout, bounds.width(), height, widthUsed);
const QSize size(qCeil(widthUsed), qCeil(height));
return QSize(size.width() + 2 * textMargin, size.height());
QStyle *style = option->widget ? option->widget->style() : QApplication::style();
QTextOption textOption;
textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
QTextLayout textLayout;
textLayout.setTextOption(textOption);
textLayout.setFont(option->font);
textLayout.setText(option->text);
const int textMargin =
style->pixelMetric(QStyle::PM_FocusFrameHMargin, option, option->widget) + 1;
QRect bounds(0, 0, 100 - 2 * textMargin, 600);
qreal height = 0, widthUsed = 0;
viewItemTextLayout(textLayout, bounds.width(), height, widthUsed);
const QSize size(qCeil(widthUsed), qCeil(height));
return QSize(size.width() + 2 * textMargin, size.height());
}
void ListViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
const QModelIndex &index) const
{
QStyleOptionViewItem opt = option;
initStyleOption(&opt, index);
painter->save();
painter->setClipRect(opt.rect);
QStyleOptionViewItem opt = option;
initStyleOption(&opt, index);
painter->save();
painter->setClipRect(opt.rect);
opt.features |= QStyleOptionViewItem::WrapText;
opt.text = index.data().toString();
opt.textElideMode = Qt::ElideRight;
opt.displayAlignment = Qt::AlignTop | Qt::AlignHCenter;
opt.features |= QStyleOptionViewItem::WrapText;
opt.text = index.data().toString();
opt.textElideMode = Qt::ElideRight;
opt.displayAlignment = Qt::AlignTop | Qt::AlignHCenter;
QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
// const int iconSize = style->pixelMetric(QStyle::PM_IconViewIconSize);
const int iconSize = 48;
QRect iconbox = opt.rect;
const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, opt.widget) + 1;
QRect textRect = opt.rect;
QRect textHighlightRect = textRect;
// clip the decoration on top, remove width padding
textRect.adjust(textMargin, iconSize + textMargin + 5, -textMargin, 0);
// const int iconSize = style->pixelMetric(QStyle::PM_IconViewIconSize);
const int iconSize = 48;
QRect iconbox = opt.rect;
const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, opt.widget) + 1;
QRect textRect = opt.rect;
QRect textHighlightRect = textRect;
// clip the decoration on top, remove width padding
textRect.adjust(textMargin, iconSize + textMargin + 5, -textMargin, 0);
textHighlightRect.adjust(0, iconSize + 5, 0, 0);
textHighlightRect.adjust(0, iconSize + 5, 0, 0);
// draw background
{
// FIXME: unused
// QSize textSize = viewItemTextSize ( &opt );
QPalette::ColorGroup cg;
QStyleOptionViewItem opt2(opt);
// draw background
{
// FIXME: unused
// QSize textSize = viewItemTextSize ( &opt );
QPalette::ColorGroup cg;
QStyleOptionViewItem opt2(opt);
if ((opt.widget && opt.widget->isEnabled()) || (opt.state & QStyle::State_Enabled))
{
if (!(opt.state & QStyle::State_Active))
cg = QPalette::Inactive;
else
cg = QPalette::Normal;
}
else
{
cg = QPalette::Disabled;
}
opt2.palette.setCurrentColorGroup(cg);
if ((opt.widget && opt.widget->isEnabled()) || (opt.state & QStyle::State_Enabled))
{
if (!(opt.state & QStyle::State_Active))
cg = QPalette::Inactive;
else
cg = QPalette::Normal;
}
else
{
cg = QPalette::Disabled;
}
opt2.palette.setCurrentColorGroup(cg);
// fill in background, if any
// fill in background, if any
if (opt.backgroundBrush.style() != Qt::NoBrush)
{
QPointF oldBO = painter->brushOrigin();
painter->setBrushOrigin(opt.rect.topLeft());
painter->fillRect(opt.rect, opt.backgroundBrush);
painter->setBrushOrigin(oldBO);
}
if (opt.backgroundBrush.style() != Qt::NoBrush)
{
QPointF oldBO = painter->brushOrigin();
painter->setBrushOrigin(opt.rect.topLeft());
painter->fillRect(opt.rect, opt.backgroundBrush);
painter->setBrushOrigin(oldBO);
}
drawSelectionRect(painter, opt2, textHighlightRect);
drawSelectionRect(painter, opt2, textHighlightRect);
/*
if (opt.showDecorationSelected)
{
drawSelectionRect(painter, opt2, opt.rect);
drawFocusRect(painter, opt2, opt.rect);
// painter->fillRect ( opt.rect, opt.palette.brush ( cg, QPalette::Highlight ) );
}
else
{
/*
if (opt.showDecorationSelected)
{
drawSelectionRect(painter, opt2, opt.rect);
drawFocusRect(painter, opt2, opt.rect);
// painter->fillRect ( opt.rect, opt.palette.brush ( cg, QPalette::Highlight ) );
}
else
{
// if ( opt.state & QStyle::State_Selected )
{
// QRect textRect = subElementRect ( QStyle::SE_ItemViewItemText, opt,
// opt.widget );
// painter->fillRect ( textHighlightRect, opt.palette.brush ( cg,
// QPalette::Highlight ) );
drawSelectionRect(painter, opt2, textHighlightRect);
drawFocusRect(painter, opt2, textHighlightRect);
}
}
*/
}
// if ( opt.state & QStyle::State_Selected )
{
// QRect textRect = subElementRect ( QStyle::SE_ItemViewItemText, opt,
// opt.widget );
// painter->fillRect ( textHighlightRect, opt.palette.brush ( cg,
// QPalette::Highlight ) );
drawSelectionRect(painter, opt2, textHighlightRect);
drawFocusRect(painter, opt2, textHighlightRect);
}
}
*/
}
// icon mode and state, also used for badges
QIcon::Mode mode = QIcon::Normal;
if (!(opt.state & QStyle::State_Enabled))
mode = QIcon::Disabled;
else if (opt.state & QStyle::State_Selected)
mode = QIcon::Selected;
QIcon::State state = opt.state & QStyle::State_Open ? QIcon::On : QIcon::Off;
// icon mode and state, also used for badges
QIcon::Mode mode = QIcon::Normal;
if (!(opt.state & QStyle::State_Enabled))
mode = QIcon::Disabled;
else if (opt.state & QStyle::State_Selected)
mode = QIcon::Selected;
QIcon::State state = opt.state & QStyle::State_Open ? QIcon::On : QIcon::Off;
// draw the icon
{
iconbox.setHeight(iconSize);
opt.icon.paint(painter, iconbox, Qt::AlignCenter, mode, state);
}
// set the text colors
QPalette::ColorGroup cg =
opt.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled;
if (cg == QPalette::Normal && !(opt.state & QStyle::State_Active))
cg = QPalette::Inactive;
if (opt.state & QStyle::State_Selected)
{
painter->setPen(opt.palette.color(cg, QPalette::HighlightedText));
}
else
{
painter->setPen(opt.palette.color(cg, QPalette::Text));
}
// draw the icon
{
iconbox.setHeight(iconSize);
opt.icon.paint(painter, iconbox, Qt::AlignCenter, mode, state);
}
// set the text colors
QPalette::ColorGroup cg =
opt.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled;
if (cg == QPalette::Normal && !(opt.state & QStyle::State_Active))
cg = QPalette::Inactive;
if (opt.state & QStyle::State_Selected)
{
painter->setPen(opt.palette.color(cg, QPalette::HighlightedText));
}
else
{
painter->setPen(opt.palette.color(cg, QPalette::Text));
}
// draw the text
QTextOption textOption;
textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
textOption.setTextDirection(opt.direction);
textOption.setAlignment(QStyle::visualAlignment(opt.direction, opt.displayAlignment));
QTextLayout textLayout;
textLayout.setTextOption(textOption);
textLayout.setFont(opt.font);
textLayout.setText(opt.text);
// draw the text
QTextOption textOption;
textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
textOption.setTextDirection(opt.direction);
textOption.setAlignment(QStyle::visualAlignment(opt.direction, opt.displayAlignment));
QTextLayout textLayout;
textLayout.setTextOption(textOption);
textLayout.setFont(opt.font);
textLayout.setText(opt.text);
qreal width, height;
viewItemTextLayout(textLayout, textRect.width(), height, width);
qreal width, height;
viewItemTextLayout(textLayout, textRect.width(), height, width);
const int lineCount = textLayout.lineCount();
const int lineCount = textLayout.lineCount();
const QRect layoutRect = QStyle::alignedRect(
opt.direction, opt.displayAlignment, QSize(textRect.width(), int(height)), textRect);
const QPointF position = layoutRect.topLeft();
for (int i = 0; i < lineCount; ++i)
{
const QTextLine line = textLayout.lineAt(i);
line.draw(painter, position);
}
const QRect layoutRect = QStyle::alignedRect(
opt.direction, opt.displayAlignment, QSize(textRect.width(), int(height)), textRect);
const QPointF position = layoutRect.topLeft();
for (int i = 0; i < lineCount; ++i)
{
const QTextLine line = textLayout.lineAt(i);
line.draw(painter, position);
}
// FIXME: this really has no business of being here. Make generic.
auto instance = (BaseInstance*)index.data(InstanceList::InstancePointerRole)
.value<void *>();
if (instance)
{
drawBadges(painter, opt, instance, mode, state);
}
// FIXME: this really has no business of being here. Make generic.
auto instance = (BaseInstance*)index.data(InstanceList::InstancePointerRole)
.value<void *>();
if (instance)
{
drawBadges(painter, opt, instance, mode, state);
}
drawProgressOverlay(painter, opt, index.data(GroupViewRoles::ProgressValueRole).toInt(),
index.data(GroupViewRoles::ProgressMaximumRole).toInt());
drawProgressOverlay(painter, opt, index.data(GroupViewRoles::ProgressValueRole).toInt(),
index.data(GroupViewRoles::ProgressMaximumRole).toInt());
painter->restore();
painter->restore();
}
QSize ListViewDelegate::sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const
const QModelIndex &index) const
{
QStyleOptionViewItem opt = option;
initStyleOption(&opt, index);
opt.features |= QStyleOptionViewItem::WrapText;
opt.text = index.data().toString();
opt.textElideMode = Qt::ElideRight;
opt.displayAlignment = Qt::AlignTop | Qt::AlignHCenter;
QStyleOptionViewItem opt = option;
initStyleOption(&opt, index);
opt.features |= QStyleOptionViewItem::WrapText;
opt.text = index.data().toString();
opt.textElideMode = Qt::ElideRight;
opt.displayAlignment = Qt::AlignTop | Qt::AlignHCenter;
QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
const int textMargin =
style->pixelMetric(QStyle::PM_FocusFrameHMargin, &option, opt.widget) + 1;
int height = 48 + textMargin * 2 + 5; // TODO: turn constants into variables
QSize szz = viewItemTextSize(&opt);
height += szz.height();
// FIXME: maybe the icon items could scale and keep proportions?
QSize sz(100, height);
return sz;
QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
const int textMargin =
style->pixelMetric(QStyle::PM_FocusFrameHMargin, &option, opt.widget) + 1;
int height = 48 + textMargin * 2 + 5; // TODO: turn constants into variables
QSize szz = viewItemTextSize(&opt);
height += szz.height();
// FIXME: maybe the icon items could scale and keep proportions?
QSize sz(100, height);
return sz;
}

View File

@ -21,10 +21,10 @@
class ListViewDelegate : public QStyledItemDelegate
{
public:
explicit ListViewDelegate(QObject *parent = 0);
explicit ListViewDelegate(QObject *parent = 0);
protected:
void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const;
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const;
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
};

View File

@ -28,290 +28,290 @@ VisualGroup::VisualGroup(const QString &text, GroupView *view) : view(view), tex
}
VisualGroup::VisualGroup(const VisualGroup *other)
: view(other->view), text(other->text), collapsed(other->collapsed)
: view(other->view), text(other->text), collapsed(other->collapsed)
{
}
void VisualGroup::update()
{
auto temp_items = items();
auto itemsPerRow = view->itemsPerRow();
auto temp_items = items();
auto itemsPerRow = view->itemsPerRow();
int numRows = qMax(1, qCeil((qreal)temp_items.size() / (qreal)itemsPerRow));
rows = QVector<VisualRow>(numRows);
int numRows = qMax(1, qCeil((qreal)temp_items.size() / (qreal)itemsPerRow));
rows = QVector<VisualRow>(numRows);
int maxRowHeight = 0;
int positionInRow = 0;
int currentRow = 0;
int offsetFromTop = 0;
for (auto item: temp_items)
{
if(positionInRow == itemsPerRow)
{
rows[currentRow].height = maxRowHeight;
rows[currentRow].top = offsetFromTop;
currentRow ++;
offsetFromTop += maxRowHeight + 5;
positionInRow = 0;
maxRowHeight = 0;
}
auto itemHeight = view->itemDelegate()->sizeHint(view->viewOptions(), item).height();
if(itemHeight > maxRowHeight)
{
maxRowHeight = itemHeight;
}
rows[currentRow].items.append(item);
positionInRow++;
}
rows[currentRow].height = maxRowHeight;
rows[currentRow].top = offsetFromTop;
int maxRowHeight = 0;
int positionInRow = 0;
int currentRow = 0;
int offsetFromTop = 0;
for (auto item: temp_items)
{
if(positionInRow == itemsPerRow)
{
rows[currentRow].height = maxRowHeight;
rows[currentRow].top = offsetFromTop;
currentRow ++;
offsetFromTop += maxRowHeight + 5;
positionInRow = 0;
maxRowHeight = 0;
}
auto itemHeight = view->itemDelegate()->sizeHint(view->viewOptions(), item).height();
if(itemHeight > maxRowHeight)
{
maxRowHeight = itemHeight;
}
rows[currentRow].items.append(item);
positionInRow++;
}
rows[currentRow].height = maxRowHeight;
rows[currentRow].top = offsetFromTop;
}
QPair<int, int> VisualGroup::positionOf(const QModelIndex &index) const
{
int y = 0;
for (auto & row: rows)
{
for(auto x = 0; x < row.items.size(); x++)
{
if(row.items[x] == index)
{
return qMakePair(x,y);
}
}
y++;
}
qWarning() << "Item" << index.row() << index.data(Qt::DisplayRole).toString() << "not found in visual group" << text;
return qMakePair(0, 0);
int y = 0;
for (auto & row: rows)
{
for(auto x = 0; x < row.items.size(); x++)
{
if(row.items[x] == index)
{
return qMakePair(x,y);
}
}
y++;
}
qWarning() << "Item" << index.row() << index.data(Qt::DisplayRole).toString() << "not found in visual group" << text;
return qMakePair(0, 0);
}
int VisualGroup::rowTopOf(const QModelIndex &index) const
{
auto position = positionOf(index);
return rows[position.second].top;
auto position = positionOf(index);
return rows[position.second].top;
}
int VisualGroup::rowHeightOf(const QModelIndex &index) const
{
auto position = positionOf(index);
return rows[position.second].height;
auto position = positionOf(index);
return rows[position.second].height;
}
VisualGroup::HitResults VisualGroup::hitScan(const QPoint &pos) const
{
VisualGroup::HitResults results = VisualGroup::NoHit;
int y_start = verticalPosition();
int body_start = y_start + headerHeight();
int body_end = body_start + contentHeight() + 5; // FIXME: wtf is this 5?
int y = pos.y();
// int x = pos.x();
if (y < y_start)
{
results = VisualGroup::NoHit;
}
else if (y < body_start)
{
results = VisualGroup::HeaderHit;
int collapseSize = headerHeight() - 4;
VisualGroup::HitResults results = VisualGroup::NoHit;
int y_start = verticalPosition();
int body_start = y_start + headerHeight();
int body_end = body_start + contentHeight() + 5; // FIXME: wtf is this 5?
int y = pos.y();
// int x = pos.x();
if (y < y_start)
{
results = VisualGroup::NoHit;
}
else if (y < body_start)
{
results = VisualGroup::HeaderHit;
int collapseSize = headerHeight() - 4;
// the icon
QRect iconRect = QRect(view->m_leftMargin + 2, 2 + y_start, collapseSize, collapseSize);
if (iconRect.contains(pos))
{
results |= VisualGroup::CheckboxHit;
}
}
else if (y < body_end)
{
results |= VisualGroup::BodyHit;
}
return results;
// the icon
QRect iconRect = QRect(view->m_leftMargin + 2, 2 + y_start, collapseSize, collapseSize);
if (iconRect.contains(pos))
{
results |= VisualGroup::CheckboxHit;
}
}
else if (y < body_end)
{
results |= VisualGroup::BodyHit;
}
return results;
}
void VisualGroup::drawHeader(QPainter *painter, const QStyleOptionViewItem &option)
{
painter->setRenderHint(QPainter::Antialiasing);
painter->setRenderHint(QPainter::Antialiasing);
const QRect optRect = option.rect;
QFont font(QApplication::font());
font.setBold(true);
const QFontMetrics fontMetrics = QFontMetrics(font);
const QRect optRect = option.rect;
QFont font(QApplication::font());
font.setBold(true);
const QFontMetrics fontMetrics = QFontMetrics(font);
QColor outlineColor = option.palette.text().color();
outlineColor.setAlphaF(0.35);
QColor outlineColor = option.palette.text().color();
outlineColor.setAlphaF(0.35);
//BEGIN: top left corner
{
painter->save();
painter->setPen(outlineColor);
const QPointF topLeft(optRect.topLeft());
QRectF arc(topLeft, QSizeF(4, 4));
arc.translate(0.5, 0.5);
painter->drawArc(arc, 1440, 1440);
painter->restore();
}
//END: top left corner
//BEGIN: top left corner
{
painter->save();
painter->setPen(outlineColor);
const QPointF topLeft(optRect.topLeft());
QRectF arc(topLeft, QSizeF(4, 4));
arc.translate(0.5, 0.5);
painter->drawArc(arc, 1440, 1440);
painter->restore();
}
//END: top left corner
//BEGIN: left vertical line
{
QPoint start(optRect.topLeft());
start.ry() += 3;
QPoint verticalGradBottom(optRect.topLeft());
verticalGradBottom.ry() += fontMetrics.height() + 5;
QLinearGradient gradient(start, verticalGradBottom);
gradient.setColorAt(0, outlineColor);
gradient.setColorAt(1, Qt::transparent);
painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient);
}
//END: left vertical line
//BEGIN: left vertical line
{
QPoint start(optRect.topLeft());
start.ry() += 3;
QPoint verticalGradBottom(optRect.topLeft());
verticalGradBottom.ry() += fontMetrics.height() + 5;
QLinearGradient gradient(start, verticalGradBottom);
gradient.setColorAt(0, outlineColor);
gradient.setColorAt(1, Qt::transparent);
painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient);
}
//END: left vertical line
//BEGIN: horizontal line
{
QPoint start(optRect.topLeft());
start.rx() += 3;
QPoint horizontalGradTop(optRect.topLeft());
horizontalGradTop.rx() += optRect.width() - 6;
painter->fillRect(QRect(start, QSize(optRect.width() - 6, 1)), outlineColor);
}
//END: horizontal line
//BEGIN: horizontal line
{
QPoint start(optRect.topLeft());
start.rx() += 3;
QPoint horizontalGradTop(optRect.topLeft());
horizontalGradTop.rx() += optRect.width() - 6;
painter->fillRect(QRect(start, QSize(optRect.width() - 6, 1)), outlineColor);
}
//END: horizontal line
//BEGIN: top right corner
{
painter->save();
painter->setPen(outlineColor);
QPointF topRight(optRect.topRight());
topRight.rx() -= 4;
QRectF arc(topRight, QSizeF(4, 4));
arc.translate(0.5, 0.5);
painter->drawArc(arc, 0, 1440);
painter->restore();
}
//END: top right corner
//BEGIN: top right corner
{
painter->save();
painter->setPen(outlineColor);
QPointF topRight(optRect.topRight());
topRight.rx() -= 4;
QRectF arc(topRight, QSizeF(4, 4));
arc.translate(0.5, 0.5);
painter->drawArc(arc, 0, 1440);
painter->restore();
}
//END: top right corner
//BEGIN: right vertical line
{
QPoint start(optRect.topRight());
start.ry() += 3;
QPoint verticalGradBottom(optRect.topRight());
verticalGradBottom.ry() += fontMetrics.height() + 5;
QLinearGradient gradient(start, verticalGradBottom);
gradient.setColorAt(0, outlineColor);
gradient.setColorAt(1, Qt::transparent);
painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient);
}
//END: right vertical line
//BEGIN: right vertical line
{
QPoint start(optRect.topRight());
start.ry() += 3;
QPoint verticalGradBottom(optRect.topRight());
verticalGradBottom.ry() += fontMetrics.height() + 5;
QLinearGradient gradient(start, verticalGradBottom);
gradient.setColorAt(0, outlineColor);
gradient.setColorAt(1, Qt::transparent);
painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient);
}
//END: right vertical line
//BEGIN: checkboxy thing
{
painter->save();
painter->setRenderHint(QPainter::Antialiasing, false);
painter->setFont(font);
QColor penColor(option.palette.text().color());
penColor.setAlphaF(0.6);
painter->setPen(penColor);
QRect iconSubRect(option.rect);
iconSubRect.setTop(iconSubRect.top() + 7);
iconSubRect.setLeft(iconSubRect.left() + 7);
//BEGIN: checkboxy thing
{
painter->save();
painter->setRenderHint(QPainter::Antialiasing, false);
painter->setFont(font);
QColor penColor(option.palette.text().color());
penColor.setAlphaF(0.6);
painter->setPen(penColor);
QRect iconSubRect(option.rect);
iconSubRect.setTop(iconSubRect.top() + 7);
iconSubRect.setLeft(iconSubRect.left() + 7);
int sizing = fontMetrics.height();
int even = ( (sizing - 1) % 2 );
int sizing = fontMetrics.height();
int even = ( (sizing - 1) % 2 );
iconSubRect.setHeight(sizing - even);
iconSubRect.setWidth(sizing - even);
painter->drawRect(iconSubRect);
iconSubRect.setHeight(sizing - even);
iconSubRect.setWidth(sizing - even);
painter->drawRect(iconSubRect);
/*
if(collapsed)
painter->drawText(iconSubRect, Qt::AlignHCenter | Qt::AlignVCenter, "+");
else
painter->drawText(iconSubRect, Qt::AlignHCenter | Qt::AlignVCenter, "-");
*/
painter->setBrush(option.palette.text());
painter->fillRect(iconSubRect.x(), iconSubRect.y() + iconSubRect.height() / 2,
iconSubRect.width(), 2, penColor);
if (collapsed)
{
painter->fillRect(iconSubRect.x() + iconSubRect.width() / 2, iconSubRect.y(), 2,
iconSubRect.height(), penColor);
}
/*
if(collapsed)
painter->drawText(iconSubRect, Qt::AlignHCenter | Qt::AlignVCenter, "+");
else
painter->drawText(iconSubRect, Qt::AlignHCenter | Qt::AlignVCenter, "-");
*/
painter->setBrush(option.palette.text());
painter->fillRect(iconSubRect.x(), iconSubRect.y() + iconSubRect.height() / 2,
iconSubRect.width(), 2, penColor);
if (collapsed)
{
painter->fillRect(iconSubRect.x() + iconSubRect.width() / 2, iconSubRect.y(), 2,
iconSubRect.height(), penColor);
}
painter->restore();
}
//END: checkboxy thing
painter->restore();
}
//END: checkboxy thing
//BEGIN: text
{
QRect textRect(option.rect);
textRect.setTop(textRect.top() + 7);
textRect.setLeft(textRect.left() + 7 + fontMetrics.height() + 7);
textRect.setHeight(fontMetrics.height());
textRect.setRight(textRect.right() - 7);
//BEGIN: text
{
QRect textRect(option.rect);
textRect.setTop(textRect.top() + 7);
textRect.setLeft(textRect.left() + 7 + fontMetrics.height() + 7);
textRect.setHeight(fontMetrics.height());
textRect.setRight(textRect.right() - 7);
painter->save();
painter->setFont(font);
QColor penColor(option.palette.text().color());
penColor.setAlphaF(0.6);
painter->setPen(penColor);
painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text);
painter->restore();
}
//END: text
painter->save();
painter->setFont(font);
QColor penColor(option.palette.text().color());
penColor.setAlphaF(0.6);
painter->setPen(penColor);
painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text);
painter->restore();
}
//END: text
}
int VisualGroup::totalHeight() const
{
return headerHeight() + 5 + contentHeight(); // FIXME: wtf is that '5'?
return headerHeight() + 5 + contentHeight(); // FIXME: wtf is that '5'?
}
int VisualGroup::headerHeight() const
{
QFont font(QApplication::font());
QFont font(QApplication::font());
font.setBold(true);
QFontMetrics fontMetrics(font);
const int height = fontMetrics.height() + 1 /* 1 pixel-width gradient */
+ 11 /* top and bottom separation */;
return height;
/*
int raw = view->viewport()->fontMetrics().height() + 4;
// add english. maybe. depends on font height.
if (raw % 2 == 0)
raw++;
return std::min(raw, 25);
*/
/*
int raw = view->viewport()->fontMetrics().height() + 4;
// add english. maybe. depends on font height.
if (raw % 2 == 0)
raw++;
return std::min(raw, 25);
*/
}
int VisualGroup::contentHeight() const
{
if (collapsed)
{
return 0;
}
auto last = rows[numRows() - 1];
return last.top + last.height;
if (collapsed)
{
return 0;
}
auto last = rows[numRows() - 1];
return last.top + last.height;
}
int VisualGroup::numRows() const
{
return rows.size();
return rows.size();
}
int VisualGroup::verticalPosition() const
{
return m_verticalPosition;
return m_verticalPosition;
}
QList<QModelIndex> VisualGroup::items() const
{
QList<QModelIndex> indices;
for (int i = 0; i < view->model()->rowCount(); ++i)
{
const QModelIndex index = view->model()->index(i, 0);
if (index.data(GroupViewRoles::GroupRole).toString() == text)
{
indices.append(index);
}
}
return indices;
QList<QModelIndex> indices;
for (int i = 0; i < view->model()->rowCount(); ++i)
{
const QModelIndex index = view->model()->index(i, 0);
if (index.data(GroupViewRoles::GroupRole).toString() == text)
{
indices.append(index);
}
}
return indices;
}

View File

@ -26,81 +26,81 @@ class QModelIndex;
struct VisualRow
{
QList<QModelIndex> items;
int height = 0;
int top = 0;
inline int size() const
{
return items.size();
}
inline QModelIndex &operator[](int i)
{
return items[i];
}
QList<QModelIndex> items;
int height = 0;
int top = 0;
inline int size() const
{
return items.size();
}
inline QModelIndex &operator[](int i)
{
return items[i];
}
};
struct VisualGroup
{
/* constructors */
VisualGroup(const QString &text, GroupView *view);
VisualGroup(const VisualGroup *other);
VisualGroup(const QString &text, GroupView *view);
VisualGroup(const VisualGroup *other);
/* data */
GroupView *view = nullptr;
QString text;
bool collapsed = false;
QVector<VisualRow> rows;
int firstItemIndex = 0;
int m_verticalPosition = 0;
GroupView *view = nullptr;
QString text;
bool collapsed = false;
QVector<VisualRow> rows;
int firstItemIndex = 0;
int m_verticalPosition = 0;
/* logic */
/// update the internal list of items and flow them into the rows.
void update();
/// update the internal list of items and flow them into the rows.
void update();
/// draw the header at y-position.
void drawHeader(QPainter *painter, const QStyleOptionViewItem &option);
/// draw the header at y-position.
void drawHeader(QPainter *painter, const QStyleOptionViewItem &option);
/// height of the group, in total. includes a small bit of padding.
int totalHeight() const;
/// height of the group, in total. includes a small bit of padding.
int totalHeight() const;
/// height of the group header, in pixels
int headerHeight() const;
/// height of the group header, in pixels
int headerHeight() const;
/// height of the group content, in pixels
int contentHeight() const;
/// height of the group content, in pixels
int contentHeight() const;
/// the number of visual rows this group has
int numRows() const;
/// the number of visual rows this group has
int numRows() const;
/// actually calculate the above value
int calculateNumRows() const;
/// actually calculate the above value
int calculateNumRows() const;
/// the height at which this group starts, in pixels
int verticalPosition() const;
/// the height at which this group starts, in pixels
int verticalPosition() const;
/// relative geometry - top of the row of the given item
int rowTopOf(const QModelIndex &index) const;
/// relative geometry - top of the row of the given item
int rowTopOf(const QModelIndex &index) const;
/// height of the row of the given item
int rowHeightOf(const QModelIndex &index) const;
/// height of the row of the given item
int rowHeightOf(const QModelIndex &index) const;
/// x/y position of the given item inside the group (in items!)
QPair<int, int> positionOf(const QModelIndex &index) const;
/// x/y position of the given item inside the group (in items!)
QPair<int, int> positionOf(const QModelIndex &index) const;
enum HitResult
{
NoHit = 0x0,
TextHit = 0x1,
CheckboxHit = 0x2,
HeaderHit = 0x4,
BodyHit = 0x8
};
Q_DECLARE_FLAGS(HitResults, HitResult)
enum HitResult
{
NoHit = 0x0,
TextHit = 0x1,
CheckboxHit = 0x2,
HeaderHit = 0x4,
BodyHit = 0x8
};
Q_DECLARE_FLAGS(HitResults, HitResult)
/// shoot! BANG! what did we hit?
HitResults hitScan (const QPoint &pos) const;
/// shoot! BANG! what did we hit?
HitResults hitScan (const QPoint &pos) const;
QList<QModelIndex> items() const;
QList<QModelIndex> items() const;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(VisualGroup::HitResults)

View File

@ -1,20 +1,20 @@
set(CMAKE_MODULE_PATH "@CMAKE_MODULE_PATH@")
file(GLOB_RECURSE QTPLUGINS "${CMAKE_INSTALL_PREFIX}/@PLUGIN_DEST_DIR@/*@CMAKE_SHARED_LIBRARY_SUFFIX@")
file(GLOB_RECURSE QTPLUGINS "${CMAKE_INSTALL_PREFIX}/@PLUGIN_DEST_DIR@/*@CMAKE_SHARED_LIBRARY_SUFFIX@")
function(gp_resolved_file_type_override resolved_file type_var)
if(resolved_file MATCHES "^/(usr/)?lib/libQt")
set(${type_var} other PARENT_SCOPE)
elseif(resolved_file MATCHES "^/(usr/)?lib(.+)?/libxcb-")
set(${type_var} other PARENT_SCOPE)
elseif(resolved_file MATCHES "^/(usr/)?lib(.+)?/libicu")
set(${type_var} other PARENT_SCOPE)
elseif(resolved_file MATCHES "^/(usr/)?lib(.+)?/libpng")
set(${type_var} other PARENT_SCOPE)
elseif(resolved_file MATCHES "^/(usr/)?lib(.+)?/libproxy")
set(${type_var} other PARENT_SCOPE)
elseif((resolved_file MATCHES "^/(usr/)?lib(.+)?/libstdc\\+\\+") AND (UNIX AND NOT APPLE))
set(${type_var} other PARENT_SCOPE)
endif()
if(resolved_file MATCHES "^/(usr/)?lib/libQt")
set(${type_var} other PARENT_SCOPE)
elseif(resolved_file MATCHES "^/(usr/)?lib(.+)?/libxcb-")
set(${type_var} other PARENT_SCOPE)
elseif(resolved_file MATCHES "^/(usr/)?lib(.+)?/libicu")
set(${type_var} other PARENT_SCOPE)
elseif(resolved_file MATCHES "^/(usr/)?lib(.+)?/libpng")
set(${type_var} other PARENT_SCOPE)
elseif(resolved_file MATCHES "^/(usr/)?lib(.+)?/libproxy")
set(${type_var} other PARENT_SCOPE)
elseif((resolved_file MATCHES "^/(usr/)?lib(.+)?/libstdc\\+\\+") AND (UNIX AND NOT APPLE))
set(${type_var} other PARENT_SCOPE)
endif()
endfunction()
set(gp_tool "@CMAKE_GP_TOOL@")

View File

@ -16,46 +16,46 @@
int main(int argc, char *argv[])
{
#ifdef BREAK_INFINITE_LOOP
while(true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(250));
}
while(true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(250));
}
#endif
#ifdef BREAK_EXCEPTION
throw 42;
throw 42;
#endif
#ifdef BREAK_RETURN
return 42;
return 42;
#endif
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
// initialize Qt
MultiMC app(argc, argv);
// initialize Qt
MultiMC app(argc, argv);
switch (app.status())
{
case MultiMC::StartingUp:
case MultiMC::Initialized:
{
Q_INIT_RESOURCE(multimc);
Q_INIT_RESOURCE(backgrounds);
Q_INIT_RESOURCE(assets);
switch (app.status())
{
case MultiMC::StartingUp:
case MultiMC::Initialized:
{
Q_INIT_RESOURCE(multimc);
Q_INIT_RESOURCE(backgrounds);
Q_INIT_RESOURCE(assets);
Q_INIT_RESOURCE(pe_dark);
Q_INIT_RESOURCE(pe_light);
Q_INIT_RESOURCE(pe_blue);
Q_INIT_RESOURCE(pe_colored);
Q_INIT_RESOURCE(OSX);
Q_INIT_RESOURCE(iOS);
Q_INIT_RESOURCE(flat);
return app.exec();
}
case MultiMC::Failed:
return 1;
case MultiMC::Succeeded:
return 0;
}
Q_INIT_RESOURCE(pe_dark);
Q_INIT_RESOURCE(pe_light);
Q_INIT_RESOURCE(pe_blue);
Q_INIT_RESOURCE(pe_colored);
Q_INIT_RESOURCE(OSX);
Q_INIT_RESOURCE(iOS);
Q_INIT_RESOURCE(flat);
return app.exec();
}
case MultiMC::Failed:
return 1;
case MultiMC::Succeeded:
return 0;
}
}

View File

@ -2,10 +2,10 @@
# Basic start script for running MultiMC with the libs packaged with it.
function printerror {
printf "$1"
if which zenity >/dev/null; then zenity --error --text="$1" &>/dev/null;
elif which kdialog >/dev/null; then kdialog --error "$1" &>/dev/null;
fi
printf "$1"
if which zenity >/dev/null; then zenity --error --text="$1" &>/dev/null;
elif which kdialog >/dev/null; then kdialog --error "$1" &>/dev/null;
fi
}
if [[ $EUID -eq 0 ]]; then
@ -28,66 +28,66 @@ export QT_FONTPATH="${MMC_DIR}/fonts"
# Detect missing dependencies...
DEPS_LIST=`ldd "${MMC_DIR}"/plugins/*/*.so 2>/dev/null | grep "not found" | sort -u | awk -vORS=", " '{ print $1 }'`
if [ "x$DEPS_LIST" = "x" ]; then
# We have all our dependencies. Run MultiMC.
echo "No missing dependencies found."
# We have all our dependencies. Run MultiMC.
echo "No missing dependencies found."
# Just to be sure...
chmod +x "${MMC_DIR}/bin/MultiMC"
# Just to be sure...
chmod +x "${MMC_DIR}/bin/MultiMC"
# Run MultiMC
"${MMC_DIR}/bin/MultiMC" -d "${MMC_DIR}" "$@"
# Run MultiMC
"${MMC_DIR}/bin/MultiMC" -d "${MMC_DIR}" "$@"
# Run MultiMC in valgrind
# valgrind --log-file="valgrind.log" --leak-check=full --track-origins=yes "${MMC_DIR}/bin/MultiMC" -d "${MMC_DIR}" "$@"
# Run MultiMC in valgrind
# valgrind --log-file="valgrind.log" --leak-check=full --track-origins=yes "${MMC_DIR}/bin/MultiMC" -d "${MMC_DIR}" "$@"
# Run MultiMC with callgrind, delay instrumentation
# valgrind --log-file="valgrind.log" --tool=callgrind --instr-atstart=no "${MMC_DIR}/bin/MultiMC" -d "${MMC_DIR}" "$@"
# use callgrind_control -i on/off to profile actions
# Run MultiMC with callgrind, delay instrumentation
# valgrind --log-file="valgrind.log" --tool=callgrind --instr-atstart=no "${MMC_DIR}/bin/MultiMC" -d "${MMC_DIR}" "$@"
# use callgrind_control -i on/off to profile actions
# Exit with MultiMC's exit code.
exit $?
# Exit with MultiMC's exit code.
exit $?
else
# apt
if which apt-file &>/dev/null; then
LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do apt-file -l search $LIBRARY; done`
COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
INSTALL_CMD="sudo apt-get install $COMMAND_LIBS"
# pacman
elif which pkgfile &>/dev/null; then
LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do pkgfile $LIBRARY; done`
COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
INSTALL_CMD="sudo pacman -S $COMMAND_LIBS"
# dnf
elif which dnf &>/dev/null; then
LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do dnf whatprovides -q $LIBRARY; done`
COMMAND_LIBS=`echo "$COMMAND_LIBS" | grep -v 'Repo' | sort -u | awk -vORS=" " '{ print $1 }'`
INSTALL_CMD="sudo dnf install $COMMAND_LIBS"
# yum
elif which yum &>/dev/null; then
LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do yum whatprovides $LIBRARY; done`
COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
INSTALL_CMD="sudo yum install $COMMAND_LIBS"
# zypper
elif which zypper &>/dev/null; then
LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do zypper wp $LIBRARY; done`
COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
INSTALL_CMD="sudo zypper install $COMMAND_LIBS"
# emerge
elif which pfl &>/dev/null; then
LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do pfl $LIBRARY; done`
COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
INSTALL_CMD="sudo emerge $COMMAND_LIBS"
fi
# apt
if which apt-file &>/dev/null; then
LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do apt-file -l search $LIBRARY; done`
COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
INSTALL_CMD="sudo apt-get install $COMMAND_LIBS"
# pacman
elif which pkgfile &>/dev/null; then
LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do pkgfile $LIBRARY; done`
COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
INSTALL_CMD="sudo pacman -S $COMMAND_LIBS"
# dnf
elif which dnf &>/dev/null; then
LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do dnf whatprovides -q $LIBRARY; done`
COMMAND_LIBS=`echo "$COMMAND_LIBS" | grep -v 'Repo' | sort -u | awk -vORS=" " '{ print $1 }'`
INSTALL_CMD="sudo dnf install $COMMAND_LIBS"
# yum
elif which yum &>/dev/null; then
LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do yum whatprovides $LIBRARY; done`
COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
INSTALL_CMD="sudo yum install $COMMAND_LIBS"
# zypper
elif which zypper &>/dev/null; then
LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do zypper wp $LIBRARY; done`
COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
INSTALL_CMD="sudo zypper install $COMMAND_LIBS"
# emerge
elif which pfl &>/dev/null; then
LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do pfl $LIBRARY; done`
COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
INSTALL_CMD="sudo emerge $COMMAND_LIBS"
fi
MESSAGE="Error: MultiMC is missing the following libraries that it needs to work correctly:\n\t${DEPS_LIST}\nPlease install them from your distribution's package manager."
MESSAGE="$MESSAGE\n\nHint (please apply common sense): $INSTALL_CMD\n"
MESSAGE="Error: MultiMC is missing the following libraries that it needs to work correctly:\n\t${DEPS_LIST}\nPlease install them from your distribution's package manager."
MESSAGE="$MESSAGE\n\nHint (please apply common sense): $INSTALL_CMD\n"
printerror "$MESSAGE"
exit 1
printerror "$MESSAGE"
exit 1
fi

View File

@ -26,35 +26,35 @@
#include "widgets/PageContainer.h"
PageDialog::PageDialog(BasePageProvider *pageProvider, QString defaultId, QWidget *parent)
: QDialog(parent)
: QDialog(parent)
{
setWindowTitle(pageProvider->dialogTitle());
m_container = new PageContainer(pageProvider, defaultId, this);
setWindowTitle(pageProvider->dialogTitle());
m_container = new PageContainer(pageProvider, defaultId, this);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(m_container);
mainLayout->setSpacing(0);
mainLayout->setContentsMargins(0, 0, 0, 0);
setLayout(mainLayout);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(m_container);
mainLayout->setSpacing(0);
mainLayout->setContentsMargins(0, 0, 0, 0);
setLayout(mainLayout);
QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Close);
buttons->button(QDialogButtonBox::Close)->setDefault(true);
m_container->addButtons(buttons);
QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Close);
buttons->button(QDialogButtonBox::Close)->setDefault(true);
m_container->addButtons(buttons);
connect(buttons->button(QDialogButtonBox::Close), SIGNAL(clicked()), this, SLOT(close()));
connect(buttons->button(QDialogButtonBox::Help), SIGNAL(clicked()), m_container, SLOT(help()));
connect(buttons->button(QDialogButtonBox::Close), SIGNAL(clicked()), this, SLOT(close()));
connect(buttons->button(QDialogButtonBox::Help), SIGNAL(clicked()), m_container, SLOT(help()));
restoreGeometry(QByteArray::fromBase64(MMC->settings()->get("PagedGeometry").toByteArray()));
restoreGeometry(QByteArray::fromBase64(MMC->settings()->get("PagedGeometry").toByteArray()));
}
void PageDialog::closeEvent(QCloseEvent *event)
{
qDebug() << "Paged dialog close requested";
if (m_container->prepareToClose())
{
qDebug() << "Paged dialog close approved";
MMC->settings()->set("PagedGeometry", saveGeometry().toBase64());
qDebug() << "Paged dialog geometry saved";
QDialog::closeEvent(event);
}
qDebug() << "Paged dialog close requested";
if (m_container->prepareToClose())
{
qDebug() << "Paged dialog close approved";
MMC->settings()->set("PagedGeometry", saveGeometry().toBase64());
qDebug() << "Paged dialog geometry saved";
QDialog::closeEvent(event);
}
}

View File

@ -21,15 +21,15 @@
class PageContainer;
class PageDialog : public QDialog
{
Q_OBJECT
Q_OBJECT
public:
explicit PageDialog(BasePageProvider *pageProvider, QString defaultId = QString(), QWidget *parent = 0);
virtual ~PageDialog() {}
explicit PageDialog(BasePageProvider *pageProvider, QString defaultId = QString(), QWidget *parent = 0);
virtual ~PageDialog() {}
private
slots:
virtual void closeEvent(QCloseEvent *event);
virtual void closeEvent(QCloseEvent *event);
private:
PageContainer * m_container;
PageContainer * m_container;
};

View File

@ -24,35 +24,35 @@
class BasePage
{
public:
virtual ~BasePage() {}
virtual QString id() const = 0;
virtual QString displayName() const = 0;
virtual QIcon icon() const = 0;
virtual bool apply() { return true; }
virtual bool shouldDisplay() const { return true; }
virtual QString helpPage() const { return QString(); }
void opened()
{
isOpened = true;
openedImpl();
}
void closed()
{
isOpened = false;
closedImpl();
}
virtual void openedImpl() {}
virtual void closedImpl() {}
virtual void setParentContainer(BasePageContainer * container)
{
m_container = container;
};
virtual ~BasePage() {}
virtual QString id() const = 0;
virtual QString displayName() const = 0;
virtual QIcon icon() const = 0;
virtual bool apply() { return true; }
virtual bool shouldDisplay() const { return true; }
virtual QString helpPage() const { return QString(); }
void opened()
{
isOpened = true;
openedImpl();
}
void closed()
{
isOpened = false;
closedImpl();
}
virtual void openedImpl() {}
virtual void closedImpl() {}
virtual void setParentContainer(BasePageContainer * container)
{
m_container = container;
};
public:
int stackIndex = -1;
int listIndex = -1;
int stackIndex = -1;
int listIndex = -1;
protected:
BasePageContainer * m_container = nullptr;
bool isOpened = false;
BasePageContainer * m_container = nullptr;
bool isOpened = false;
};
typedef std::shared_ptr<BasePage> BasePagePtr;

View File

@ -3,8 +3,8 @@
class BasePageContainer
{
public:
virtual ~BasePageContainer(){};
virtual bool selectPage(QString pageId) = 0;
virtual void refreshContainer() = 0;
virtual bool requestClose() = 0;
virtual ~BasePageContainer(){};
virtual bool selectPage(QString pageId) = 0;
virtual void refreshContainer() = 0;
virtual bool requestClose() = 0;
};

View File

@ -22,47 +22,47 @@
class BasePageProvider
{
public:
virtual QList<BasePage *> getPages() = 0;
virtual QString dialogTitle() = 0;
virtual QList<BasePage *> getPages() = 0;
virtual QString dialogTitle() = 0;
};
class GenericPageProvider : public BasePageProvider
{
typedef std::function<BasePage *()> PageCreator;
typedef std::function<BasePage *()> PageCreator;
public:
explicit GenericPageProvider(const QString &dialogTitle)
: m_dialogTitle(dialogTitle)
{
}
virtual ~GenericPageProvider() {}
explicit GenericPageProvider(const QString &dialogTitle)
: m_dialogTitle(dialogTitle)
{
}
virtual ~GenericPageProvider() {}
QList<BasePage *> getPages() override
{
QList<BasePage *> pages;
for (PageCreator creator : m_creators)
{
pages.append(creator());
}
return pages;
}
QString dialogTitle() override { return m_dialogTitle; }
QList<BasePage *> getPages() override
{
QList<BasePage *> pages;
for (PageCreator creator : m_creators)
{
pages.append(creator());
}
return pages;
}
QString dialogTitle() override { return m_dialogTitle; }
void setDialogTitle(const QString &title)
{
m_dialogTitle = title;
}
void addPageCreator(PageCreator page)
{
m_creators.append(page);
}
void setDialogTitle(const QString &title)
{
m_dialogTitle = title;
}
void addPageCreator(PageCreator page)
{
m_creators.append(page);
}
template<typename PageClass>
void addPage()
{
addPageCreator([](){return new PageClass();});
}
template<typename PageClass>
void addPage()
{
addPageCreator([](){return new PageClass();});
}
private:
QList<PageCreator> m_creators;
QString m_dialogTitle;
QList<PageCreator> m_creators;
QString m_dialogTitle;
};

View File

@ -34,120 +34,120 @@
#include "MultiMC.h"
AccountListPage::AccountListPage(QWidget *parent)
: QWidget(parent), ui(new Ui::AccountListPage)
: QWidget(parent), ui(new Ui::AccountListPage)
{
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();
m_accounts = MMC->accounts();
m_accounts = MMC->accounts();
ui->listView->setModel(m_accounts.get());
ui->listView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
ui->listView->setModel(m_accounts.get());
ui->listView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
// Expand the account column
ui->listView->header()->setSectionResizeMode(1, QHeaderView::Stretch);
// Expand the account column
ui->listView->header()->setSectionResizeMode(1, QHeaderView::Stretch);
QItemSelectionModel *selectionModel = ui->listView->selectionModel();
QItemSelectionModel *selectionModel = ui->listView->selectionModel();
connect(selectionModel, &QItemSelectionModel::selectionChanged,
[this](const QItemSelection &sel, const QItemSelection &dsel)
{ updateButtonStates(); });
connect(selectionModel, &QItemSelectionModel::selectionChanged,
[this](const QItemSelection &sel, const QItemSelection &dsel)
{ updateButtonStates(); });
connect(m_accounts.get(), SIGNAL(listChanged()), SLOT(listChanged()));
connect(m_accounts.get(), SIGNAL(activeAccountChanged()), SLOT(listChanged()));
connect(m_accounts.get(), SIGNAL(listChanged()), SLOT(listChanged()));
connect(m_accounts.get(), SIGNAL(activeAccountChanged()), SLOT(listChanged()));
updateButtonStates();
updateButtonStates();
}
AccountListPage::~AccountListPage()
{
delete ui;
delete ui;
}
void AccountListPage::listChanged()
{
updateButtonStates();
updateButtonStates();
}
void AccountListPage::on_addAccountBtn_clicked()
{
addAccount(tr("Please enter your Mojang or Minecraft account username and password to add "
"your account."));
addAccount(tr("Please enter your Mojang or Minecraft account username and password to add "
"your account."));
}
void AccountListPage::on_rmAccountBtn_clicked()
{
QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
if (selection.size() > 0)
{
QModelIndex selected = selection.first();
m_accounts->removeAccount(selected);
}
QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
if (selection.size() > 0)
{
QModelIndex selected = selection.first();
m_accounts->removeAccount(selected);
}
}
void AccountListPage::on_setDefaultBtn_clicked()
{
QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
if (selection.size() > 0)
{
QModelIndex selected = selection.first();
MojangAccountPtr account =
selected.data(MojangAccountList::PointerRole).value<MojangAccountPtr>();
m_accounts->setActiveAccount(account->username());
}
QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
if (selection.size() > 0)
{
QModelIndex selected = selection.first();
MojangAccountPtr account =
selected.data(MojangAccountList::PointerRole).value<MojangAccountPtr>();
m_accounts->setActiveAccount(account->username());
}
}
void AccountListPage::on_noDefaultBtn_clicked()
{
m_accounts->setActiveAccount("");
m_accounts->setActiveAccount("");
}
void AccountListPage::updateButtonStates()
{
// If there is no selection, disable buttons that require something selected.
QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
// If there is no selection, disable buttons that require something selected.
QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
ui->rmAccountBtn->setEnabled(selection.size() > 0);
ui->setDefaultBtn->setEnabled(selection.size() > 0);
ui->uploadSkinBtn->setEnabled(selection.size() > 0);
ui->rmAccountBtn->setEnabled(selection.size() > 0);
ui->setDefaultBtn->setEnabled(selection.size() > 0);
ui->uploadSkinBtn->setEnabled(selection.size() > 0);
ui->noDefaultBtn->setDown(m_accounts->activeAccount().get() == nullptr);
ui->noDefaultBtn->setDown(m_accounts->activeAccount().get() == nullptr);
}
void AccountListPage::addAccount(const QString &errMsg)
{
// TODO: The login dialog isn't quite done yet
MojangAccountPtr account = LoginDialog::newAccount(this, errMsg);
// TODO: The login dialog isn't quite done yet
MojangAccountPtr account = LoginDialog::newAccount(this, errMsg);
if (account != nullptr)
{
m_accounts->addAccount(account);
if (m_accounts->count() == 1)
m_accounts->setActiveAccount(account->username());
if (account != nullptr)
{
m_accounts->addAccount(account);
if (m_accounts->count() == 1)
m_accounts->setActiveAccount(account->username());
// Grab associated player skins
auto job = new NetJob("Player skins: " + account->username());
// Grab associated player skins
auto job = new NetJob("Player skins: " + account->username());
for (AccountProfile profile : account->profiles())
{
auto meta = Env::getInstance().metacache()->resolveEntry("skins", profile.id + ".png");
auto action = Net::Download::makeCached(QUrl("https://" + URLConstants::SKINS_BASE + profile.id + ".png"), meta);
job->addNetAction(action);
meta->setStale(true);
}
for (AccountProfile profile : account->profiles())
{
auto meta = Env::getInstance().metacache()->resolveEntry("skins", profile.id + ".png");
auto action = Net::Download::makeCached(QUrl("https://" + URLConstants::SKINS_BASE + profile.id + ".png"), meta);
job->addNetAction(action);
meta->setStale(true);
}
job->start();
}
job->start();
}
}
void AccountListPage::on_uploadSkinBtn_clicked()
{
QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
if (selection.size() > 0)
{
QModelIndex selected = selection.first();
MojangAccountPtr account = selected.data(MojangAccountList::PointerRole).value<MojangAccountPtr>();
SkinUploadDialog dialog(account, this);
dialog.exec();
}
QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
if (selection.size() > 0)
{
QModelIndex selected = selection.first();
MojangAccountPtr account = selected.data(MojangAccountList::PointerRole).value<MojangAccountPtr>();
SkinUploadDialog dialog(account, this);
dialog.exec();
}
}

View File

@ -32,57 +32,57 @@ class AuthenticateTask;
class AccountListPage : public QWidget, public BasePage
{
Q_OBJECT
Q_OBJECT
public:
explicit AccountListPage(QWidget *parent = 0);
~AccountListPage();
explicit AccountListPage(QWidget *parent = 0);
~AccountListPage();
QString displayName() const override
{
return tr("Accounts");
}
QIcon icon() const override
{
auto icon = MMC->getThemedIcon("accounts");
if(icon.isNull())
{
icon = MMC->getThemedIcon("noaccount");
}
return icon;
}
QString id() const override
{
return "accounts";
}
QString helpPage() const override
{
return "Getting-Started#adding-an-account";
}
QString displayName() const override
{
return tr("Accounts");
}
QIcon icon() const override
{
auto icon = MMC->getThemedIcon("accounts");
if(icon.isNull())
{
icon = MMC->getThemedIcon("noaccount");
}
return icon;
}
QString id() const override
{
return "accounts";
}
QString helpPage() const override
{
return "Getting-Started#adding-an-account";
}
public
slots:
void on_addAccountBtn_clicked();
void on_addAccountBtn_clicked();
void on_rmAccountBtn_clicked();
void on_rmAccountBtn_clicked();
void on_setDefaultBtn_clicked();
void on_setDefaultBtn_clicked();
void on_noDefaultBtn_clicked();
void on_noDefaultBtn_clicked();
void on_uploadSkinBtn_clicked();
void on_uploadSkinBtn_clicked();
void listChanged();
void listChanged();
//! Updates the states of the dialog's buttons.
void updateButtonStates();
//! Updates the states of the dialog's buttons.
void updateButtonStates();
protected:
std::shared_ptr<MojangAccountList> m_accounts;
std::shared_ptr<MojangAccountList> m_accounts;
protected
slots:
void addAccount(const QString& errMsg="");
void addAccount(const QString& errMsg="");
private:
Ui::AccountListPage *ui;
Ui::AccountListPage *ui;
};

View File

@ -6,17 +6,17 @@
CustomCommandsPage::CustomCommandsPage(QWidget* parent): QWidget(parent)
{
auto verticalLayout = new QVBoxLayout(this);
verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
verticalLayout->setContentsMargins(0, 0, 0, 0);
auto verticalLayout = new QVBoxLayout(this);
verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
verticalLayout->setContentsMargins(0, 0, 0, 0);
auto tabWidget = new QTabWidget(this);
tabWidget->setObjectName(QStringLiteral("tabWidget"));
commands = new CustomCommands(this);
tabWidget->addTab(commands, "Foo");
tabWidget->tabBar()->hide();
verticalLayout->addWidget(tabWidget);
loadSettings();
auto tabWidget = new QTabWidget(this);
tabWidget->setObjectName(QStringLiteral("tabWidget"));
commands = new CustomCommands(this);
tabWidget->addTab(commands, "Foo");
tabWidget->tabBar()->hide();
verticalLayout->addWidget(tabWidget);
loadSettings();
}
CustomCommandsPage::~CustomCommandsPage()
@ -25,26 +25,26 @@ CustomCommandsPage::~CustomCommandsPage()
bool CustomCommandsPage::apply()
{
applySettings();
return true;
applySettings();
return true;
}
void CustomCommandsPage::applySettings()
{
auto s = MMC->settings();
s->set("PreLaunchCommand", commands->prelaunchCommand());
s->set("WrapperCommand", commands->wrapperCommand());
s->set("PostExitCommand", commands->postexitCommand());
auto s = MMC->settings();
s->set("PreLaunchCommand", commands->prelaunchCommand());
s->set("WrapperCommand", commands->wrapperCommand());
s->set("PostExitCommand", commands->postexitCommand());
}
void CustomCommandsPage::loadSettings()
{
auto s = MMC->settings();
commands->initialize(
false,
true,
s->get("PreLaunchCommand").toString(),
s->get("WrapperCommand").toString(),
s->get("PostExitCommand").toString()
);
auto s = MMC->settings();
commands->initialize(
false,
true,
s->get("PreLaunchCommand").toString(),
s->get("WrapperCommand").toString(),
s->get("PostExitCommand").toString()
);
}

View File

@ -24,32 +24,32 @@
class CustomCommandsPage : public QWidget, public BasePage
{
Q_OBJECT
Q_OBJECT
public:
explicit CustomCommandsPage(QWidget *parent = 0);
~CustomCommandsPage();
explicit CustomCommandsPage(QWidget *parent = 0);
~CustomCommandsPage();
QString displayName() const override
{
return tr("Custom Commands");
}
QIcon icon() const override
{
return MMC->getThemedIcon("custom-commands");
}
QString id() const override
{
return "custom-commands";
}
QString helpPage() const override
{
return "Custom-commands";
}
bool apply() override;
QString displayName() const override
{
return tr("Custom Commands");
}
QIcon icon() const override
{
return MMC->getThemedIcon("custom-commands");
}
QString id() const override
{
return "custom-commands";
}
QString helpPage() const override
{
return "Custom-commands";
}
bool apply() override;
private:
void applySettings();
void loadSettings();
CustomCommands * commands;
void applySettings();
void loadSettings();
CustomCommands * commands;
};

View File

@ -28,206 +28,206 @@
#include <tools/MCEditTool.h>
ExternalToolsPage::ExternalToolsPage(QWidget *parent) :
QWidget(parent),
ui(new Ui::ExternalToolsPage)
QWidget(parent),
ui(new Ui::ExternalToolsPage)
{
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();
#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
ui->jsonEditorTextBox->setClearButtonEnabled(true);
#endif
#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
ui->jsonEditorTextBox->setClearButtonEnabled(true);
#endif
ui->mceditLink->setOpenExternalLinks(true);
ui->jvisualvmLink->setOpenExternalLinks(true);
ui->jprofilerLink->setOpenExternalLinks(true);
loadSettings();
ui->mceditLink->setOpenExternalLinks(true);
ui->jvisualvmLink->setOpenExternalLinks(true);
ui->jprofilerLink->setOpenExternalLinks(true);
loadSettings();
}
ExternalToolsPage::~ExternalToolsPage()
{
delete ui;
delete ui;
}
void ExternalToolsPage::loadSettings()
{
auto s = MMC->settings();
ui->jprofilerPathEdit->setText(s->get("JProfilerPath").toString());
ui->jvisualvmPathEdit->setText(s->get("JVisualVMPath").toString());
ui->mceditPathEdit->setText(s->get("MCEditPath").toString());
auto s = MMC->settings();
ui->jprofilerPathEdit->setText(s->get("JProfilerPath").toString());
ui->jvisualvmPathEdit->setText(s->get("JVisualVMPath").toString());
ui->mceditPathEdit->setText(s->get("MCEditPath").toString());
// Editors
ui->jsonEditorTextBox->setText(s->get("JsonEditor").toString());
// Editors
ui->jsonEditorTextBox->setText(s->get("JsonEditor").toString());
}
void ExternalToolsPage::applySettings()
{
auto s = MMC->settings();
auto s = MMC->settings();
s->set("JProfilerPath", ui->jprofilerPathEdit->text());
s->set("JVisualVMPath", ui->jvisualvmPathEdit->text());
s->set("MCEditPath", ui->mceditPathEdit->text());
s->set("JProfilerPath", ui->jprofilerPathEdit->text());
s->set("JVisualVMPath", ui->jvisualvmPathEdit->text());
s->set("MCEditPath", ui->mceditPathEdit->text());
// Editors
QString jsonEditor = ui->jsonEditorTextBox->text();
if (!jsonEditor.isEmpty() &&
(!QFileInfo(jsonEditor).exists() || !QFileInfo(jsonEditor).isExecutable()))
{
QString found = QStandardPaths::findExecutable(jsonEditor);
if (!found.isEmpty())
{
jsonEditor = found;
}
}
s->set("JsonEditor", jsonEditor);
// Editors
QString jsonEditor = ui->jsonEditorTextBox->text();
if (!jsonEditor.isEmpty() &&
(!QFileInfo(jsonEditor).exists() || !QFileInfo(jsonEditor).isExecutable()))
{
QString found = QStandardPaths::findExecutable(jsonEditor);
if (!found.isEmpty())
{
jsonEditor = found;
}
}
s->set("JsonEditor", jsonEditor);
}
void ExternalToolsPage::on_jprofilerPathBtn_clicked()
{
QString raw_dir = ui->jprofilerPathEdit->text();
QString error;
do
{
raw_dir = QFileDialog::getExistingDirectory(this, tr("JProfiler Folder"), raw_dir);
if (raw_dir.isEmpty())
{
break;
}
QString cooked_dir = FS::NormalizePath(raw_dir);
if (!MMC->profilers()["jprofiler"]->check(cooked_dir, &error))
{
QMessageBox::critical(this, tr("Error"), tr("Error while checking JProfiler install:\n%1").arg(error));
continue;
}
else
{
ui->jprofilerPathEdit->setText(cooked_dir);
break;
}
} while (1);
QString raw_dir = ui->jprofilerPathEdit->text();
QString error;
do
{
raw_dir = QFileDialog::getExistingDirectory(this, tr("JProfiler Folder"), raw_dir);
if (raw_dir.isEmpty())
{
break;
}
QString cooked_dir = FS::NormalizePath(raw_dir);
if (!MMC->profilers()["jprofiler"]->check(cooked_dir, &error))
{
QMessageBox::critical(this, tr("Error"), tr("Error while checking JProfiler install:\n%1").arg(error));
continue;
}
else
{
ui->jprofilerPathEdit->setText(cooked_dir);
break;
}
} while (1);
}
void ExternalToolsPage::on_jprofilerCheckBtn_clicked()
{
QString error;
if (!MMC->profilers()["jprofiler"]->check(ui->jprofilerPathEdit->text(), &error))
{
QMessageBox::critical(this, tr("Error"), tr("Error while checking JProfiler install:\n%1").arg(error));
}
else
{
QMessageBox::information(this, tr("OK"), tr("JProfiler setup seems to be OK"));
}
QString error;
if (!MMC->profilers()["jprofiler"]->check(ui->jprofilerPathEdit->text(), &error))
{
QMessageBox::critical(this, tr("Error"), tr("Error while checking JProfiler install:\n%1").arg(error));
}
else
{
QMessageBox::information(this, tr("OK"), tr("JProfiler setup seems to be OK"));
}
}
void ExternalToolsPage::on_jvisualvmPathBtn_clicked()
{
QString raw_dir = ui->jvisualvmPathEdit->text();
QString error;
do
{
raw_dir = QFileDialog::getOpenFileName(this, tr("JVisualVM Executable"), raw_dir);
if (raw_dir.isEmpty())
{
break;
}
QString cooked_dir = FS::NormalizePath(raw_dir);
if (!MMC->profilers()["jvisualvm"]->check(cooked_dir, &error))
{
QMessageBox::critical(this, tr("Error"), tr("Error while checking JVisualVM install:\n%1").arg(error));
continue;
}
else
{
ui->jvisualvmPathEdit->setText(cooked_dir);
break;
}
} while (1);
QString raw_dir = ui->jvisualvmPathEdit->text();
QString error;
do
{
raw_dir = QFileDialog::getOpenFileName(this, tr("JVisualVM Executable"), raw_dir);
if (raw_dir.isEmpty())
{
break;
}
QString cooked_dir = FS::NormalizePath(raw_dir);
if (!MMC->profilers()["jvisualvm"]->check(cooked_dir, &error))
{
QMessageBox::critical(this, tr("Error"), tr("Error while checking JVisualVM install:\n%1").arg(error));
continue;
}
else
{
ui->jvisualvmPathEdit->setText(cooked_dir);
break;
}
} while (1);
}
void ExternalToolsPage::on_jvisualvmCheckBtn_clicked()
{
QString error;
if (!MMC->profilers()["jvisualvm"]->check(ui->jvisualvmPathEdit->text(), &error))
{
QMessageBox::critical(this, tr("Error"), tr("Error while checking JVisualVM install:\n%1").arg(error));
}
else
{
QMessageBox::information(this, tr("OK"), tr("JVisualVM setup seems to be OK"));
}
QString error;
if (!MMC->profilers()["jvisualvm"]->check(ui->jvisualvmPathEdit->text(), &error))
{
QMessageBox::critical(this, tr("Error"), tr("Error while checking JVisualVM install:\n%1").arg(error));
}
else
{
QMessageBox::information(this, tr("OK"), tr("JVisualVM setup seems to be OK"));
}
}
void ExternalToolsPage::on_mceditPathBtn_clicked()
{
QString raw_dir = ui->mceditPathEdit->text();
QString error;
do
{
QString raw_dir = ui->mceditPathEdit->text();
QString error;
do
{
#ifdef Q_OS_OSX
raw_dir = QFileDialog::getOpenFileName(this, tr("MCEdit Application"), raw_dir);
raw_dir = QFileDialog::getOpenFileName(this, tr("MCEdit Application"), raw_dir);
#else
raw_dir = QFileDialog::getExistingDirectory(this, tr("MCEdit Folder"), raw_dir);
raw_dir = QFileDialog::getExistingDirectory(this, tr("MCEdit Folder"), raw_dir);
#endif
if (raw_dir.isEmpty())
{
break;
}
QString cooked_dir = FS::NormalizePath(raw_dir);
if (!MMC->mcedit()->check(cooked_dir, error))
{
QMessageBox::critical(this, tr("Error"), tr("Error while checking MCEdit install:\n%1").arg(error));
continue;
}
else
{
ui->mceditPathEdit->setText(cooked_dir);
break;
}
} while (1);
if (raw_dir.isEmpty())
{
break;
}
QString cooked_dir = FS::NormalizePath(raw_dir);
if (!MMC->mcedit()->check(cooked_dir, error))
{
QMessageBox::critical(this, tr("Error"), tr("Error while checking MCEdit install:\n%1").arg(error));
continue;
}
else
{
ui->mceditPathEdit->setText(cooked_dir);
break;
}
} while (1);
}
void ExternalToolsPage::on_mceditCheckBtn_clicked()
{
QString error;
if (!MMC->mcedit()->check(ui->mceditPathEdit->text(), error))
{
QMessageBox::critical(this, tr("Error"), tr("Error while checking MCEdit install:\n%1").arg(error));
}
else
{
QMessageBox::information(this, tr("OK"), tr("MCEdit setup seems to be OK"));
}
QString error;
if (!MMC->mcedit()->check(ui->mceditPathEdit->text(), error))
{
QMessageBox::critical(this, tr("Error"), tr("Error while checking MCEdit install:\n%1").arg(error));
}
else
{
QMessageBox::information(this, tr("OK"), tr("MCEdit setup seems to be OK"));
}
}
void ExternalToolsPage::on_jsonEditorBrowseBtn_clicked()
{
QString raw_file = QFileDialog::getOpenFileName(
this, tr("JSON Editor"),
ui->jsonEditorTextBox->text().isEmpty()
QString raw_file = QFileDialog::getOpenFileName(
this, tr("JSON Editor"),
ui->jsonEditorTextBox->text().isEmpty()
#if defined(Q_OS_LINUX)
? QString("/usr/bin")
? QString("/usr/bin")
#else
? QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation).first()
? QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation).first()
#endif
: ui->jsonEditorTextBox->text());
: ui->jsonEditorTextBox->text());
if (raw_file.isEmpty())
{
return;
}
QString cooked_file = FS::NormalizePath(raw_file);
if (raw_file.isEmpty())
{
return;
}
QString cooked_file = FS::NormalizePath(raw_file);
// it has to exist and be an executable
if (QFileInfo(cooked_file).exists() && QFileInfo(cooked_file).isExecutable())
{
ui->jsonEditorTextBox->setText(cooked_file);
}
else
{
QMessageBox::warning(this, tr("Invalid"),
tr("The file chosen does not seem to be an executable"));
}
// it has to exist and be an executable
if (QFileInfo(cooked_file).exists() && QFileInfo(cooked_file).isExecutable())
{
ui->jsonEditorTextBox->setText(cooked_file);
}
else
{
QMessageBox::warning(this, tr("Invalid"),
tr("The file chosen does not seem to be an executable"));
}
}
bool ExternalToolsPage::apply()
{
applySettings();
return true;
applySettings();
return true;
}

View File

@ -26,49 +26,49 @@ class ExternalToolsPage;
class ExternalToolsPage : public QWidget, public BasePage
{
Q_OBJECT
Q_OBJECT
public:
explicit ExternalToolsPage(QWidget *parent = 0);
~ExternalToolsPage();
explicit ExternalToolsPage(QWidget *parent = 0);
~ExternalToolsPage();
QString displayName() const override
{
return tr("External Tools");
}
QIcon icon() const override
{
auto icon = MMC->getThemedIcon("externaltools");
if(icon.isNull())
{
icon = MMC->getThemedIcon("loadermods");
}
return icon;
}
QString id() const override
{
return "external-tools";
}
QString helpPage() const override
{
return "Tools";
}
virtual bool apply() override;
QString displayName() const override
{
return tr("External Tools");
}
QIcon icon() const override
{
auto icon = MMC->getThemedIcon("externaltools");
if(icon.isNull())
{
icon = MMC->getThemedIcon("loadermods");
}
return icon;
}
QString id() const override
{
return "external-tools";
}
QString helpPage() const override
{
return "Tools";
}
virtual bool apply() override;
private:
void loadSettings();
void applySettings();
void loadSettings();
void applySettings();
private:
Ui::ExternalToolsPage *ui;
Ui::ExternalToolsPage *ui;
private
slots:
void on_jprofilerPathBtn_clicked();
void on_jprofilerCheckBtn_clicked();
void on_jvisualvmPathBtn_clicked();
void on_jvisualvmCheckBtn_clicked();
void on_mceditPathBtn_clicked();
void on_mceditCheckBtn_clicked();
void on_jsonEditorBrowseBtn_clicked();
void on_jprofilerPathBtn_clicked();
void on_jprofilerCheckBtn_clicked();
void on_jvisualvmPathBtn_clicked();
void on_jvisualvmCheckBtn_clicked();
void on_mceditPathBtn_clicked();
void on_mceditCheckBtn_clicked();
void on_jsonEditorBrowseBtn_clicked();
};

View File

@ -34,120 +34,120 @@
JavaPage::JavaPage(QWidget *parent) : QWidget(parent), ui(new Ui::JavaPage)
{
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();
auto sysMB = Sys::getSystemRam() / Sys::megabyte;
ui->maxMemSpinBox->setMaximum(sysMB);
loadSettings();
auto sysMB = Sys::getSystemRam() / Sys::megabyte;
ui->maxMemSpinBox->setMaximum(sysMB);
loadSettings();
}
JavaPage::~JavaPage()
{
delete ui;
delete ui;
}
bool JavaPage::apply()
{
applySettings();
return true;
applySettings();
return true;
}
void JavaPage::applySettings()
{
auto s = MMC->settings();
auto s = MMC->settings();
// Memory
int min = ui->minMemSpinBox->value();
int max = ui->maxMemSpinBox->value();
if(min < max)
{
s->set("MinMemAlloc", min);
s->set("MaxMemAlloc", max);
}
else
{
s->set("MinMemAlloc", max);
s->set("MaxMemAlloc", min);
}
s->set("PermGen", ui->permGenSpinBox->value());
// Memory
int min = ui->minMemSpinBox->value();
int max = ui->maxMemSpinBox->value();
if(min < max)
{
s->set("MinMemAlloc", min);
s->set("MaxMemAlloc", max);
}
else
{
s->set("MinMemAlloc", max);
s->set("MaxMemAlloc", min);
}
s->set("PermGen", ui->permGenSpinBox->value());
// Java Settings
s->set("JavaPath", ui->javaPathTextBox->text());
s->set("JvmArgs", ui->jvmArgsTextBox->text());
JavaCommon::checkJVMArgs(s->get("JvmArgs").toString(), this->parentWidget());
// Java Settings
s->set("JavaPath", ui->javaPathTextBox->text());
s->set("JvmArgs", ui->jvmArgsTextBox->text());
JavaCommon::checkJVMArgs(s->get("JvmArgs").toString(), this->parentWidget());
}
void JavaPage::loadSettings()
{
auto s = MMC->settings();
// Memory
int min = s->get("MinMemAlloc").toInt();
int max = s->get("MaxMemAlloc").toInt();
if(min < max)
{
ui->minMemSpinBox->setValue(min);
ui->maxMemSpinBox->setValue(max);
}
else
{
ui->minMemSpinBox->setValue(max);
ui->maxMemSpinBox->setValue(min);
}
ui->permGenSpinBox->setValue(s->get("PermGen").toInt());
auto s = MMC->settings();
// Memory
int min = s->get("MinMemAlloc").toInt();
int max = s->get("MaxMemAlloc").toInt();
if(min < max)
{
ui->minMemSpinBox->setValue(min);
ui->maxMemSpinBox->setValue(max);
}
else
{
ui->minMemSpinBox->setValue(max);
ui->maxMemSpinBox->setValue(min);
}
ui->permGenSpinBox->setValue(s->get("PermGen").toInt());
// Java Settings
ui->javaPathTextBox->setText(s->get("JavaPath").toString());
ui->jvmArgsTextBox->setText(s->get("JvmArgs").toString());
// Java Settings
ui->javaPathTextBox->setText(s->get("JavaPath").toString());
ui->jvmArgsTextBox->setText(s->get("JvmArgs").toString());
}
void JavaPage::on_javaDetectBtn_clicked()
{
JavaInstallPtr java;
JavaInstallPtr java;
VersionSelectDialog vselect(MMC->javalist().get(), tr("Select a Java version"), this, true);
vselect.setResizeOn(2);
vselect.exec();
VersionSelectDialog vselect(MMC->javalist().get(), tr("Select a Java version"), this, true);
vselect.setResizeOn(2);
vselect.exec();
if (vselect.result() == QDialog::Accepted && vselect.selectedVersion())
{
java = std::dynamic_pointer_cast<JavaInstall>(vselect.selectedVersion());
ui->javaPathTextBox->setText(java->path);
}
if (vselect.result() == QDialog::Accepted && vselect.selectedVersion())
{
java = std::dynamic_pointer_cast<JavaInstall>(vselect.selectedVersion());
ui->javaPathTextBox->setText(java->path);
}
}
void JavaPage::on_javaBrowseBtn_clicked()
{
QString raw_path = QFileDialog::getOpenFileName(this, tr("Find Java executable"));
QString raw_path = QFileDialog::getOpenFileName(this, tr("Find Java executable"));
// do not allow current dir - it's dirty. Do not allow dirs that don't exist
if(raw_path.isEmpty())
{
return;
}
// do not allow current dir - it's dirty. Do not allow dirs that don't exist
if(raw_path.isEmpty())
{
return;
}
QString cooked_path = FS::NormalizePath(raw_path);
QFileInfo javaInfo(cooked_path);;
if(!javaInfo.exists() || !javaInfo.isExecutable())
{
return;
}
ui->javaPathTextBox->setText(cooked_path);
QString cooked_path = FS::NormalizePath(raw_path);
QFileInfo javaInfo(cooked_path);;
if(!javaInfo.exists() || !javaInfo.isExecutable())
{
return;
}
ui->javaPathTextBox->setText(cooked_path);
}
void JavaPage::on_javaTestBtn_clicked()
{
if(checker)
{
return;
}
checker.reset(new JavaCommon::TestCheck(
this, ui->javaPathTextBox->text(), ui->jvmArgsTextBox->text(),
ui->minMemSpinBox->value(), ui->maxMemSpinBox->value(), ui->permGenSpinBox->value()));
connect(checker.get(), SIGNAL(finished()), SLOT(checkerFinished()));
checker->run();
if(checker)
{
return;
}
checker.reset(new JavaCommon::TestCheck(
this, ui->javaPathTextBox->text(), ui->jvmArgsTextBox->text(),
ui->minMemSpinBox->value(), ui->maxMemSpinBox->value(), ui->permGenSpinBox->value()));
connect(checker.get(), SIGNAL(finished()), SLOT(checkerFinished()));
checker->run();
}
void JavaPage::checkerFinished()
{
checker.reset();
checker.reset();
}

View File

@ -31,42 +31,42 @@ class JavaPage;
class JavaPage : public QWidget, public BasePage
{
Q_OBJECT
Q_OBJECT
public:
explicit JavaPage(QWidget *parent = 0);
~JavaPage();
explicit JavaPage(QWidget *parent = 0);
~JavaPage();
QString displayName() const override
{
return tr("Java");
}
QIcon icon() const override
{
return MMC->getThemedIcon("java");
}
QString id() const override
{
return "java-settings";
}
QString helpPage() const override
{
return "Java-settings";
}
bool apply() override;
QString displayName() const override
{
return tr("Java");
}
QIcon icon() const override
{
return MMC->getThemedIcon("java");
}
QString id() const override
{
return "java-settings";
}
QString helpPage() const override
{
return "Java-settings";
}
bool apply() override;
private:
void applySettings();
void loadSettings();
void applySettings();
void loadSettings();
private
slots:
void on_javaDetectBtn_clicked();
void on_javaTestBtn_clicked();
void on_javaBrowseBtn_clicked();
void checkerFinished();
void on_javaDetectBtn_clicked();
void on_javaTestBtn_clicked();
void on_javaBrowseBtn_clicked();
void checkerFinished();
private:
Ui::JavaPage *ui;
unique_qobject_ptr<JavaCommon::TestCheck> checker;
Ui::JavaPage *ui;
unique_qobject_ptr<JavaCommon::TestCheck> checker;
};

View File

@ -25,52 +25,52 @@
MinecraftPage::MinecraftPage(QWidget *parent) : QWidget(parent), ui(new Ui::MinecraftPage)
{
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();
loadSettings();
updateCheckboxStuff();
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();
loadSettings();
updateCheckboxStuff();
}
MinecraftPage::~MinecraftPage()
{
delete ui;
delete ui;
}
bool MinecraftPage::apply()
{
applySettings();
return true;
applySettings();
return true;
}
void MinecraftPage::updateCheckboxStuff()
{
ui->windowWidthSpinBox->setEnabled(!ui->maximizedCheckBox->isChecked());
ui->windowHeightSpinBox->setEnabled(!ui->maximizedCheckBox->isChecked());
ui->windowWidthSpinBox->setEnabled(!ui->maximizedCheckBox->isChecked());
ui->windowHeightSpinBox->setEnabled(!ui->maximizedCheckBox->isChecked());
}
void MinecraftPage::on_maximizedCheckBox_clicked(bool checked)
{
Q_UNUSED(checked);
updateCheckboxStuff();
Q_UNUSED(checked);
updateCheckboxStuff();
}
void MinecraftPage::applySettings()
{
auto s = MMC->settings();
auto s = MMC->settings();
// Window Size
s->set("LaunchMaximized", ui->maximizedCheckBox->isChecked());
s->set("MinecraftWinWidth", ui->windowWidthSpinBox->value());
s->set("MinecraftWinHeight", ui->windowHeightSpinBox->value());
// Window Size
s->set("LaunchMaximized", ui->maximizedCheckBox->isChecked());
s->set("MinecraftWinWidth", ui->windowWidthSpinBox->value());
s->set("MinecraftWinHeight", ui->windowHeightSpinBox->value());
}
void MinecraftPage::loadSettings()
{
auto s = MMC->settings();
auto s = MMC->settings();
// Window Size
ui->maximizedCheckBox->setChecked(s->get("LaunchMaximized").toBool());
ui->windowWidthSpinBox->setValue(s->get("MinecraftWinWidth").toInt());
ui->windowHeightSpinBox->setValue(s->get("MinecraftWinHeight").toInt());
// Window Size
ui->maximizedCheckBox->setChecked(s->get("LaunchMaximized").toBool());
ui->windowWidthSpinBox->setValue(s->get("MinecraftWinWidth").toInt());
ui->windowHeightSpinBox->setValue(s->get("MinecraftWinHeight").toInt());
}

View File

@ -31,40 +31,40 @@ class MinecraftPage;
class MinecraftPage : public QWidget, public BasePage
{
Q_OBJECT
Q_OBJECT
public:
explicit MinecraftPage(QWidget *parent = 0);
~MinecraftPage();
explicit MinecraftPage(QWidget *parent = 0);
~MinecraftPage();
QString displayName() const override
{
return tr("Minecraft");
}
QIcon icon() const override
{
return MMC->getThemedIcon("minecraft");
}
QString id() const override
{
return "minecraft-settings";
}
QString helpPage() const override
{
return "Minecraft-settings";
}
bool apply() override;
QString displayName() const override
{
return tr("Minecraft");
}
QIcon icon() const override
{
return MMC->getThemedIcon("minecraft");
}
QString id() const override
{
return "minecraft-settings";
}
QString helpPage() const override
{
return "Minecraft-settings";
}
bool apply() override;
private:
void updateCheckboxStuff();
void applySettings();
void loadSettings();
void updateCheckboxStuff();
void applySettings();
void loadSettings();
private
slots:
void on_maximizedCheckBox_clicked(bool checked);
void on_maximizedCheckBox_clicked(bool checked);
private:
Ui::MinecraftPage *ui;
Ui::MinecraftPage *ui;
};

View File

@ -32,441 +32,441 @@
// FIXME: possibly move elsewhere
enum InstSortMode
{
// Sort alphabetically by name.
Sort_Name,
// Sort by which instance was launched most recently.
Sort_LastLaunch
// Sort alphabetically by name.
Sort_Name,
// Sort by which instance was launched most recently.
Sort_LastLaunch
};
MultiMCPage::MultiMCPage(QWidget *parent) : QWidget(parent), ui(new Ui::MultiMCPage)
{
ui->setupUi(this);
auto origForeground = ui->fontPreview->palette().color(ui->fontPreview->foregroundRole());
auto origBackground = ui->fontPreview->palette().color(ui->fontPreview->backgroundRole());
m_colors.reset(new LogColorCache(origForeground, origBackground));
ui->setupUi(this);
auto origForeground = ui->fontPreview->palette().color(ui->fontPreview->foregroundRole());
auto origBackground = ui->fontPreview->palette().color(ui->fontPreview->backgroundRole());
m_colors.reset(new LogColorCache(origForeground, origBackground));
ui->sortingModeGroup->setId(ui->sortByNameBtn, Sort_Name);
ui->sortingModeGroup->setId(ui->sortLastLaunchedBtn, Sort_LastLaunch);
ui->sortingModeGroup->setId(ui->sortByNameBtn, Sort_Name);
ui->sortingModeGroup->setId(ui->sortLastLaunchedBtn, Sort_LastLaunch);
defaultFormat = new QTextCharFormat(ui->fontPreview->currentCharFormat());
defaultFormat = new QTextCharFormat(ui->fontPreview->currentCharFormat());
m_languageModel = MMC->translations();
loadSettings();
m_languageModel = MMC->translations();
loadSettings();
if(BuildConfig.UPDATER_ENABLED)
{
QObject::connect(MMC->updateChecker().get(), &UpdateChecker::channelListLoaded, this,
&MultiMCPage::refreshUpdateChannelList);
if(BuildConfig.UPDATER_ENABLED)
{
QObject::connect(MMC->updateChecker().get(), &UpdateChecker::channelListLoaded, this,
&MultiMCPage::refreshUpdateChannelList);
if (MMC->updateChecker()->hasChannels())
{
refreshUpdateChannelList();
}
else
{
MMC->updateChecker()->updateChanList(false);
}
}
else
{
ui->updateSettingsBox->setHidden(true);
}
// Analytics
if(BuildConfig.ANALYTICS_ID.isEmpty())
{
ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->analyticsTab));
}
connect(ui->fontSizeBox, SIGNAL(valueChanged(int)), SLOT(refreshFontPreview()));
connect(ui->consoleFont, SIGNAL(currentFontChanged(QFont)), SLOT(refreshFontPreview()));
connect(ui->languageBox, SIGNAL(currentIndexChanged(int)), SLOT(languageIndexChanged(int)));
if (MMC->updateChecker()->hasChannels())
{
refreshUpdateChannelList();
}
else
{
MMC->updateChecker()->updateChanList(false);
}
}
else
{
ui->updateSettingsBox->setHidden(true);
}
// Analytics
if(BuildConfig.ANALYTICS_ID.isEmpty())
{
ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->analyticsTab));
}
connect(ui->fontSizeBox, SIGNAL(valueChanged(int)), SLOT(refreshFontPreview()));
connect(ui->consoleFont, SIGNAL(currentFontChanged(QFont)), SLOT(refreshFontPreview()));
connect(ui->languageBox, SIGNAL(currentIndexChanged(int)), SLOT(languageIndexChanged(int)));
}
MultiMCPage::~MultiMCPage()
{
delete ui;
delete ui;
}
bool MultiMCPage::apply()
{
applySettings();
return true;
applySettings();
return true;
}
void MultiMCPage::on_instDirBrowseBtn_clicked()
{
QString raw_dir = QFileDialog::getExistingDirectory(this, tr("Instance Folder"), ui->instDirTextBox->text());
QString raw_dir = QFileDialog::getExistingDirectory(this, tr("Instance Folder"), ui->instDirTextBox->text());
// do not allow current dir - it's dirty. Do not allow dirs that don't exist
if (!raw_dir.isEmpty() && QDir(raw_dir).exists())
{
QString cooked_dir = FS::NormalizePath(raw_dir);
if (FS::checkProblemticPathJava(QDir(cooked_dir)))
{
QMessageBox warning;
warning.setText(tr("You're trying to specify an instance folder which\'s path "
"contains at least one \'!\'. "
"Java is known to cause problems if that is the case, your "
"instances (probably) won't start!"));
warning.setInformativeText(
tr("Do you really want to use this path? "
"Selecting \"No\" will close this and not alter your instance path."));
warning.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
int result = warning.exec();
if (result == QMessageBox::Yes)
{
ui->instDirTextBox->setText(cooked_dir);
}
}
else
{
ui->instDirTextBox->setText(cooked_dir);
}
}
// do not allow current dir - it's dirty. Do not allow dirs that don't exist
if (!raw_dir.isEmpty() && QDir(raw_dir).exists())
{
QString cooked_dir = FS::NormalizePath(raw_dir);
if (FS::checkProblemticPathJava(QDir(cooked_dir)))
{
QMessageBox warning;
warning.setText(tr("You're trying to specify an instance folder which\'s path "
"contains at least one \'!\'. "
"Java is known to cause problems if that is the case, your "
"instances (probably) won't start!"));
warning.setInformativeText(
tr("Do you really want to use this path? "
"Selecting \"No\" will close this and not alter your instance path."));
warning.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
int result = warning.exec();
if (result == QMessageBox::Yes)
{
ui->instDirTextBox->setText(cooked_dir);
}
}
else
{
ui->instDirTextBox->setText(cooked_dir);
}
}
}
void MultiMCPage::on_iconsDirBrowseBtn_clicked()
{
QString raw_dir = QFileDialog::getExistingDirectory(this, tr("Icons Folder"), ui->iconsDirTextBox->text());
QString raw_dir = QFileDialog::getExistingDirectory(this, tr("Icons Folder"), ui->iconsDirTextBox->text());
// do not allow current dir - it's dirty. Do not allow dirs that don't exist
if (!raw_dir.isEmpty() && QDir(raw_dir).exists())
{
QString cooked_dir = FS::NormalizePath(raw_dir);
ui->iconsDirTextBox->setText(cooked_dir);
}
// do not allow current dir - it's dirty. Do not allow dirs that don't exist
if (!raw_dir.isEmpty() && QDir(raw_dir).exists())
{
QString cooked_dir = FS::NormalizePath(raw_dir);
ui->iconsDirTextBox->setText(cooked_dir);
}
}
void MultiMCPage::on_modsDirBrowseBtn_clicked()
{
QString raw_dir = QFileDialog::getExistingDirectory(this, tr("Mods Folder"), ui->modsDirTextBox->text());
QString raw_dir = QFileDialog::getExistingDirectory(this, tr("Mods Folder"), ui->modsDirTextBox->text());
// do not allow current dir - it's dirty. Do not allow dirs that don't exist
if (!raw_dir.isEmpty() && QDir(raw_dir).exists())
{
QString cooked_dir = FS::NormalizePath(raw_dir);
ui->modsDirTextBox->setText(cooked_dir);
}
// do not allow current dir - it's dirty. Do not allow dirs that don't exist
if (!raw_dir.isEmpty() && QDir(raw_dir).exists())
{
QString cooked_dir = FS::NormalizePath(raw_dir);
ui->modsDirTextBox->setText(cooked_dir);
}
}
void MultiMCPage::languageIndexChanged(int index)
{
auto languageCode = ui->languageBox->itemData(ui->languageBox->currentIndex()).toString();
if(languageCode.isEmpty())
{
qWarning() << "Unknown language at index" << index;
return;
}
auto translations = MMC->translations();
translations->selectLanguage(languageCode);
translations->updateLanguage(languageCode);
auto languageCode = ui->languageBox->itemData(ui->languageBox->currentIndex()).toString();
if(languageCode.isEmpty())
{
qWarning() << "Unknown language at index" << index;
return;
}
auto translations = MMC->translations();
translations->selectLanguage(languageCode);
translations->updateLanguage(languageCode);
}
void MultiMCPage::refreshUpdateChannelList()
{
// Stop listening for selection changes. It's going to change a lot while we update it and
// we don't need to update the
// description label constantly.
QObject::disconnect(ui->updateChannelComboBox, SIGNAL(currentIndexChanged(int)), this,
SLOT(updateChannelSelectionChanged(int)));
// Stop listening for selection changes. It's going to change a lot while we update it and
// we don't need to update the
// description label constantly.
QObject::disconnect(ui->updateChannelComboBox, SIGNAL(currentIndexChanged(int)), this,
SLOT(updateChannelSelectionChanged(int)));
QList<UpdateChecker::ChannelListEntry> channelList = MMC->updateChecker()->getChannelList();
ui->updateChannelComboBox->clear();
int selection = -1;
for (int i = 0; i < channelList.count(); i++)
{
UpdateChecker::ChannelListEntry entry = channelList.at(i);
QList<UpdateChecker::ChannelListEntry> channelList = MMC->updateChecker()->getChannelList();
ui->updateChannelComboBox->clear();
int selection = -1;
for (int i = 0; i < channelList.count(); i++)
{
UpdateChecker::ChannelListEntry entry = channelList.at(i);
// When it comes to selection, we'll rely on the indexes of a channel entry being the
// same in the
// combo box as it is in the update checker's channel list.
// This probably isn't very safe, but the channel list doesn't change often enough (or
// at all) for
// this to be a big deal. Hope it doesn't break...
ui->updateChannelComboBox->addItem(entry.name);
// When it comes to selection, we'll rely on the indexes of a channel entry being the
// same in the
// combo box as it is in the update checker's channel list.
// This probably isn't very safe, but the channel list doesn't change often enough (or
// at all) for
// this to be a big deal. Hope it doesn't break...
ui->updateChannelComboBox->addItem(entry.name);
// If the update channel we just added was the selected one, set the current index in
// the combo box to it.
if (entry.id == m_currentUpdateChannel)
{
qDebug() << "Selected index" << i << "channel id" << m_currentUpdateChannel;
selection = i;
}
}
// If the update channel we just added was the selected one, set the current index in
// the combo box to it.
if (entry.id == m_currentUpdateChannel)
{
qDebug() << "Selected index" << i << "channel id" << m_currentUpdateChannel;
selection = i;
}
}
ui->updateChannelComboBox->setCurrentIndex(selection);
ui->updateChannelComboBox->setCurrentIndex(selection);
// Start listening for selection changes again and update the description label.
QObject::connect(ui->updateChannelComboBox, SIGNAL(currentIndexChanged(int)), this,
SLOT(updateChannelSelectionChanged(int)));
refreshUpdateChannelDesc();
// Start listening for selection changes again and update the description label.
QObject::connect(ui->updateChannelComboBox, SIGNAL(currentIndexChanged(int)), this,
SLOT(updateChannelSelectionChanged(int)));
refreshUpdateChannelDesc();
// Now that we've updated the channel list, we can enable the combo box.
// It starts off disabled so that if the channel list hasn't been loaded, it will be
// disabled.
ui->updateChannelComboBox->setEnabled(true);
// Now that we've updated the channel list, we can enable the combo box.
// It starts off disabled so that if the channel list hasn't been loaded, it will be
// disabled.
ui->updateChannelComboBox->setEnabled(true);
}
void MultiMCPage::updateChannelSelectionChanged(int index)
{
refreshUpdateChannelDesc();
refreshUpdateChannelDesc();
}
void MultiMCPage::refreshUpdateChannelDesc()
{
// Get the channel list.
QList<UpdateChecker::ChannelListEntry> channelList = MMC->updateChecker()->getChannelList();
int selectedIndex = ui->updateChannelComboBox->currentIndex();
if (selectedIndex < 0)
{
return;
}
if (selectedIndex < channelList.count())
{
// Find the channel list entry with the given index.
UpdateChecker::ChannelListEntry selected = channelList.at(selectedIndex);
// Get the channel list.
QList<UpdateChecker::ChannelListEntry> channelList = MMC->updateChecker()->getChannelList();
int selectedIndex = ui->updateChannelComboBox->currentIndex();
if (selectedIndex < 0)
{
return;
}
if (selectedIndex < channelList.count())
{
// Find the channel list entry with the given index.
UpdateChecker::ChannelListEntry selected = channelList.at(selectedIndex);
// Set the description text.
ui->updateChannelDescLabel->setText(selected.description);
// Set the description text.
ui->updateChannelDescLabel->setText(selected.description);
// Set the currently selected channel ID.
m_currentUpdateChannel = selected.id;
}
// Set the currently selected channel ID.
m_currentUpdateChannel = selected.id;
}
}
void MultiMCPage::applySettings()
{
auto s = MMC->settings();
auto s = MMC->settings();
// Language
s->set("Language", ui->languageBox->itemData(ui->languageBox->currentIndex()).toString());
// Language
s->set("Language", ui->languageBox->itemData(ui->languageBox->currentIndex()).toString());
if (ui->resetNotificationsBtn->isChecked())
{
s->set("ShownNotifications", QString());
}
if (ui->resetNotificationsBtn->isChecked())
{
s->set("ShownNotifications", QString());
}
// Updates
s->set("AutoUpdate", ui->autoUpdateCheckBox->isChecked());
s->set("UpdateChannel", m_currentUpdateChannel);
auto original = s->get("IconTheme").toString();
//FIXME: make generic
switch (ui->themeComboBox->currentIndex())
{
case 1:
s->set("IconTheme", "pe_dark");
break;
case 2:
s->set("IconTheme", "pe_light");
break;
case 3:
s->set("IconTheme", "pe_blue");
break;
case 4:
s->set("IconTheme", "pe_colored");
break;
case 5:
s->set("IconTheme", "OSX");
break;
case 6:
s->set("IconTheme", "iOS");
break;
case 7:
s->set("IconTheme", "flat");
break;
case 8:
s->set("IconTheme", "custom");
break;
case 0:
default:
s->set("IconTheme", "multimc");
break;
}
// Updates
s->set("AutoUpdate", ui->autoUpdateCheckBox->isChecked());
s->set("UpdateChannel", m_currentUpdateChannel);
auto original = s->get("IconTheme").toString();
//FIXME: make generic
switch (ui->themeComboBox->currentIndex())
{
case 1:
s->set("IconTheme", "pe_dark");
break;
case 2:
s->set("IconTheme", "pe_light");
break;
case 3:
s->set("IconTheme", "pe_blue");
break;
case 4:
s->set("IconTheme", "pe_colored");
break;
case 5:
s->set("IconTheme", "OSX");
break;
case 6:
s->set("IconTheme", "iOS");
break;
case 7:
s->set("IconTheme", "flat");
break;
case 8:
s->set("IconTheme", "custom");
break;
case 0:
default:
s->set("IconTheme", "multimc");
break;
}
if(original != s->get("IconTheme"))
{
MMC->setIconTheme(s->get("IconTheme").toString());
}
if(original != s->get("IconTheme"))
{
MMC->setIconTheme(s->get("IconTheme").toString());
}
auto originalAppTheme = s->get("ApplicationTheme").toString();
auto newAppTheme = ui->themeComboBoxColors->currentData().toString();
if(originalAppTheme != newAppTheme)
{
s->set("ApplicationTheme", newAppTheme);
MMC->setApplicationTheme(newAppTheme, false);
}
auto originalAppTheme = s->get("ApplicationTheme").toString();
auto newAppTheme = ui->themeComboBoxColors->currentData().toString();
if(originalAppTheme != newAppTheme)
{
s->set("ApplicationTheme", newAppTheme);
MMC->setApplicationTheme(newAppTheme, false);
}
// Console settings
s->set("ShowConsole", ui->showConsoleCheck->isChecked());
s->set("AutoCloseConsole", ui->autoCloseConsoleCheck->isChecked());
s->set("ShowConsoleOnError", ui->showConsoleErrorCheck->isChecked());
QString consoleFontFamily = ui->consoleFont->currentFont().family();
s->set("ConsoleFont", consoleFontFamily);
s->set("ConsoleFontSize", ui->fontSizeBox->value());
s->set("ConsoleMaxLines", ui->lineLimitSpinBox->value());
s->set("ConsoleOverflowStop", ui->checkStopLogging->checkState() != Qt::Unchecked);
// Console settings
s->set("ShowConsole", ui->showConsoleCheck->isChecked());
s->set("AutoCloseConsole", ui->autoCloseConsoleCheck->isChecked());
s->set("ShowConsoleOnError", ui->showConsoleErrorCheck->isChecked());
QString consoleFontFamily = ui->consoleFont->currentFont().family();
s->set("ConsoleFont", consoleFontFamily);
s->set("ConsoleFontSize", ui->fontSizeBox->value());
s->set("ConsoleMaxLines", ui->lineLimitSpinBox->value());
s->set("ConsoleOverflowStop", ui->checkStopLogging->checkState() != Qt::Unchecked);
// Folders
// TODO: Offer to move instances to new instance folder.
s->set("InstanceDir", ui->instDirTextBox->text());
s->set("CentralModsDir", ui->modsDirTextBox->text());
s->set("IconsDir", ui->iconsDirTextBox->text());
// Folders
// TODO: Offer to move instances to new instance folder.
s->set("InstanceDir", ui->instDirTextBox->text());
s->set("CentralModsDir", ui->modsDirTextBox->text());
s->set("IconsDir", ui->iconsDirTextBox->text());
auto sortMode = (InstSortMode)ui->sortingModeGroup->checkedId();
switch (sortMode)
{
case Sort_LastLaunch:
s->set("InstSortMode", "LastLaunch");
break;
case Sort_Name:
default:
s->set("InstSortMode", "Name");
break;
}
auto sortMode = (InstSortMode)ui->sortingModeGroup->checkedId();
switch (sortMode)
{
case Sort_LastLaunch:
s->set("InstSortMode", "LastLaunch");
break;
case Sort_Name:
default:
s->set("InstSortMode", "Name");
break;
}
// Analytics
if(!BuildConfig.ANALYTICS_ID.isEmpty())
{
s->set("Analytics", ui->analyticsCheck->isChecked());
}
// Analytics
if(!BuildConfig.ANALYTICS_ID.isEmpty())
{
s->set("Analytics", ui->analyticsCheck->isChecked());
}
}
void MultiMCPage::loadSettings()
{
auto s = MMC->settings();
// Language
{
ui->languageBox->setModel(m_languageModel.get());
ui->languageBox->setCurrentIndex(ui->languageBox->findData(s->get("Language").toString()));
}
auto s = MMC->settings();
// Language
{
ui->languageBox->setModel(m_languageModel.get());
ui->languageBox->setCurrentIndex(ui->languageBox->findData(s->get("Language").toString()));
}
// Updates
ui->autoUpdateCheckBox->setChecked(s->get("AutoUpdate").toBool());
m_currentUpdateChannel = s->get("UpdateChannel").toString();
//FIXME: make generic
auto theme = s->get("IconTheme").toString();
if (theme == "pe_dark")
{
ui->themeComboBox->setCurrentIndex(1);
}
else if (theme == "pe_light")
{
ui->themeComboBox->setCurrentIndex(2);
}
else if (theme == "pe_blue")
{
ui->themeComboBox->setCurrentIndex(3);
}
else if (theme == "pe_colored")
{
ui->themeComboBox->setCurrentIndex(4);
}
else if (theme == "OSX")
{
ui->themeComboBox->setCurrentIndex(5);
}
else if (theme == "iOS")
{
ui->themeComboBox->setCurrentIndex(6);
}
else if (theme == "flat")
{
ui->themeComboBox->setCurrentIndex(7);
}
else if (theme == "custom")
{
ui->themeComboBox->setCurrentIndex(8);
}
else
{
ui->themeComboBox->setCurrentIndex(0);
}
// Updates
ui->autoUpdateCheckBox->setChecked(s->get("AutoUpdate").toBool());
m_currentUpdateChannel = s->get("UpdateChannel").toString();
//FIXME: make generic
auto theme = s->get("IconTheme").toString();
if (theme == "pe_dark")
{
ui->themeComboBox->setCurrentIndex(1);
}
else if (theme == "pe_light")
{
ui->themeComboBox->setCurrentIndex(2);
}
else if (theme == "pe_blue")
{
ui->themeComboBox->setCurrentIndex(3);
}
else if (theme == "pe_colored")
{
ui->themeComboBox->setCurrentIndex(4);
}
else if (theme == "OSX")
{
ui->themeComboBox->setCurrentIndex(5);
}
else if (theme == "iOS")
{
ui->themeComboBox->setCurrentIndex(6);
}
else if (theme == "flat")
{
ui->themeComboBox->setCurrentIndex(7);
}
else if (theme == "custom")
{
ui->themeComboBox->setCurrentIndex(8);
}
else
{
ui->themeComboBox->setCurrentIndex(0);
}
{
auto currentTheme = s->get("ApplicationTheme").toString();
auto themes = MMC->getValidApplicationThemes();
int idx = 0;
for(auto &theme: themes)
{
ui->themeComboBoxColors->addItem(theme->name(), theme->id());
if(currentTheme == theme->id())
{
ui->themeComboBoxColors->setCurrentIndex(idx);
}
idx++;
}
}
{
auto currentTheme = s->get("ApplicationTheme").toString();
auto themes = MMC->getValidApplicationThemes();
int idx = 0;
for(auto &theme: themes)
{
ui->themeComboBoxColors->addItem(theme->name(), theme->id());
if(currentTheme == theme->id())
{
ui->themeComboBoxColors->setCurrentIndex(idx);
}
idx++;
}
}
// Console settings
ui->showConsoleCheck->setChecked(s->get("ShowConsole").toBool());
ui->autoCloseConsoleCheck->setChecked(s->get("AutoCloseConsole").toBool());
ui->showConsoleErrorCheck->setChecked(s->get("ShowConsoleOnError").toBool());
QString fontFamily = MMC->settings()->get("ConsoleFont").toString();
QFont consoleFont(fontFamily);
ui->consoleFont->setCurrentFont(consoleFont);
// Console settings
ui->showConsoleCheck->setChecked(s->get("ShowConsole").toBool());
ui->autoCloseConsoleCheck->setChecked(s->get("AutoCloseConsole").toBool());
ui->showConsoleErrorCheck->setChecked(s->get("ShowConsoleOnError").toBool());
QString fontFamily = MMC->settings()->get("ConsoleFont").toString();
QFont consoleFont(fontFamily);
ui->consoleFont->setCurrentFont(consoleFont);
bool conversionOk = true;
int fontSize = MMC->settings()->get("ConsoleFontSize").toInt(&conversionOk);
if(!conversionOk)
{
fontSize = 11;
}
ui->fontSizeBox->setValue(fontSize);
refreshFontPreview();
ui->lineLimitSpinBox->setValue(s->get("ConsoleMaxLines").toInt());
ui->checkStopLogging->setChecked(s->get("ConsoleOverflowStop").toBool());
bool conversionOk = true;
int fontSize = MMC->settings()->get("ConsoleFontSize").toInt(&conversionOk);
if(!conversionOk)
{
fontSize = 11;
}
ui->fontSizeBox->setValue(fontSize);
refreshFontPreview();
ui->lineLimitSpinBox->setValue(s->get("ConsoleMaxLines").toInt());
ui->checkStopLogging->setChecked(s->get("ConsoleOverflowStop").toBool());
// Folders
ui->instDirTextBox->setText(s->get("InstanceDir").toString());
ui->modsDirTextBox->setText(s->get("CentralModsDir").toString());
ui->iconsDirTextBox->setText(s->get("IconsDir").toString());
// Folders
ui->instDirTextBox->setText(s->get("InstanceDir").toString());
ui->modsDirTextBox->setText(s->get("CentralModsDir").toString());
ui->iconsDirTextBox->setText(s->get("IconsDir").toString());
QString sortMode = s->get("InstSortMode").toString();
QString sortMode = s->get("InstSortMode").toString();
if (sortMode == "LastLaunch")
{
ui->sortLastLaunchedBtn->setChecked(true);
}
else
{
ui->sortByNameBtn->setChecked(true);
}
if (sortMode == "LastLaunch")
{
ui->sortLastLaunchedBtn->setChecked(true);
}
else
{
ui->sortByNameBtn->setChecked(true);
}
// Analytics
if(!BuildConfig.ANALYTICS_ID.isEmpty())
{
ui->analyticsCheck->setChecked(s->get("Analytics").toBool());
}
// Analytics
if(!BuildConfig.ANALYTICS_ID.isEmpty())
{
ui->analyticsCheck->setChecked(s->get("Analytics").toBool());
}
}
void MultiMCPage::refreshFontPreview()
{
int fontSize = ui->fontSizeBox->value();
QString fontFamily = ui->consoleFont->currentFont().family();
ui->fontPreview->clear();
defaultFormat->setFont(QFont(fontFamily, fontSize));
{
QTextCharFormat format(*defaultFormat);
format.setForeground(m_colors->getFront(MessageLevel::Error));
// append a paragraph/line
auto workCursor = ui->fontPreview->textCursor();
workCursor.movePosition(QTextCursor::End);
workCursor.insertText(tr("[Something/ERROR] A spooky error!"), format);
workCursor.insertBlock();
}
{
QTextCharFormat format(*defaultFormat);
format.setForeground(m_colors->getFront(MessageLevel::Message));
// append a paragraph/line
auto workCursor = ui->fontPreview->textCursor();
workCursor.movePosition(QTextCursor::End);
workCursor.insertText(tr("[Test/INFO] A harmless message..."), format);
workCursor.insertBlock();
}
{
QTextCharFormat format(*defaultFormat);
format.setForeground(m_colors->getFront(MessageLevel::Warning));
// append a paragraph/line
auto workCursor = ui->fontPreview->textCursor();
workCursor.movePosition(QTextCursor::End);
workCursor.insertText(tr("[Something/WARN] A not so spooky warning."), format);
workCursor.insertBlock();
}
int fontSize = ui->fontSizeBox->value();
QString fontFamily = ui->consoleFont->currentFont().family();
ui->fontPreview->clear();
defaultFormat->setFont(QFont(fontFamily, fontSize));
{
QTextCharFormat format(*defaultFormat);
format.setForeground(m_colors->getFront(MessageLevel::Error));
// append a paragraph/line
auto workCursor = ui->fontPreview->textCursor();
workCursor.movePosition(QTextCursor::End);
workCursor.insertText(tr("[Something/ERROR] A spooky error!"), format);
workCursor.insertBlock();
}
{
QTextCharFormat format(*defaultFormat);
format.setForeground(m_colors->getFront(MessageLevel::Message));
// append a paragraph/line
auto workCursor = ui->fontPreview->textCursor();
workCursor.movePosition(QTextCursor::End);
workCursor.insertText(tr("[Test/INFO] A harmless message..."), format);
workCursor.insertBlock();
}
{
QTextCharFormat format(*defaultFormat);
format.setForeground(m_colors->getFront(MessageLevel::Warning));
// append a paragraph/line
auto workCursor = ui->fontPreview->textCursor();
workCursor.movePosition(QTextCursor::End);
workCursor.insertText(tr("[Something/WARN] A not so spooky warning."), format);
workCursor.insertBlock();
}
}

View File

@ -34,71 +34,71 @@ class MultiMCPage;
class MultiMCPage : public QWidget, public BasePage
{
Q_OBJECT
Q_OBJECT
public:
explicit MultiMCPage(QWidget *parent = 0);
~MultiMCPage();
explicit MultiMCPage(QWidget *parent = 0);
~MultiMCPage();
QString displayName() const override
{
return "MultiMC";
}
QIcon icon() const override
{
return MMC->getThemedIcon("multimc");
}
QString id() const override
{
return "multimc-settings";
}
QString helpPage() const override
{
return "MultiMC-settings";
}
bool apply() override;
QString displayName() const override
{
return "MultiMC";
}
QIcon icon() const override
{
return MMC->getThemedIcon("multimc");
}
QString id() const override
{
return "multimc-settings";
}
QString helpPage() const override
{
return "MultiMC-settings";
}
bool apply() override;
private:
void applySettings();
void loadSettings();
void applySettings();
void loadSettings();
private
slots:
void on_instDirBrowseBtn_clicked();
void on_modsDirBrowseBtn_clicked();
void on_iconsDirBrowseBtn_clicked();
void on_instDirBrowseBtn_clicked();
void on_modsDirBrowseBtn_clicked();
void on_iconsDirBrowseBtn_clicked();
void languageIndexChanged(int index);
void languageIndexChanged(int index);
/*!
* Updates the list of update channels in the combo box.
*/
void refreshUpdateChannelList();
/*!
* Updates the list of update channels in the combo box.
*/
void refreshUpdateChannelList();
/*!
* Updates the channel description label.
*/
void refreshUpdateChannelDesc();
/*!
* Updates the channel description label.
*/
void refreshUpdateChannelDesc();
/*!
* Updates the font preview
*/
void refreshFontPreview();
/*!
* Updates the font preview
*/
void refreshFontPreview();
void updateChannelSelectionChanged(int index);
void updateChannelSelectionChanged(int index);
private:
Ui::MultiMCPage *ui;
Ui::MultiMCPage *ui;
/*!
* Stores the currently selected update channel.
*/
QString m_currentUpdateChannel;
/*!
* Stores the currently selected update channel.
*/
QString m_currentUpdateChannel;
// default format for the font preview...
QTextCharFormat *defaultFormat;
// default format for the font preview...
QTextCharFormat *defaultFormat;
std::unique_ptr<LogColorCache> m_colors;
std::unique_ptr<LogColorCache> m_colors;
std::shared_ptr<TranslationsModel> m_languageModel;
std::shared_ptr<TranslationsModel> m_languageModel;
};

View File

@ -33,192 +33,192 @@ using namespace Meta;
static QString formatRequires(const VersionPtr &version)
{
QStringList lines;
auto & reqs = version->requires();
auto iter = reqs.begin();
while (iter != reqs.end())
{
auto &uid = iter->uid;
auto &version = iter->equalsVersion;
const QString readable = ENV.metadataIndex()->hasUid(uid) ? ENV.metadataIndex()->get(uid)->humanReadable() : uid;
if(!version.isEmpty())
{
lines.append(QString("%1 (%2)").arg(readable, version));
}
else
{
lines.append(QString("%1").arg(readable));
}
iter++;
}
return lines.join('\n');
QStringList lines;
auto & reqs = version->requires();
auto iter = reqs.begin();
while (iter != reqs.end())
{
auto &uid = iter->uid;
auto &version = iter->equalsVersion;
const QString readable = ENV.metadataIndex()->hasUid(uid) ? ENV.metadataIndex()->get(uid)->humanReadable() : uid;
if(!version.isEmpty())
{
lines.append(QString("%1 (%2)").arg(readable, version));
}
else
{
lines.append(QString("%1").arg(readable));
}
iter++;
}
return lines.join('\n');
}
PackagesPage::PackagesPage(QWidget *parent) :
QWidget(parent),
ui(new Ui::PackagesPage)
QWidget(parent),
ui(new Ui::PackagesPage)
{
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();
m_fileProxy = new QSortFilterProxyModel(this);
m_fileProxy->setSortRole(Qt::DisplayRole);
m_fileProxy->setSortCaseSensitivity(Qt::CaseInsensitive);
m_fileProxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
m_fileProxy->setFilterRole(Qt::DisplayRole);
m_fileProxy->setFilterKeyColumn(0);
m_fileProxy->sort(0);
m_fileProxy->setSourceModel(ENV.metadataIndex().get());
ui->indexView->setModel(m_fileProxy);
m_fileProxy = new QSortFilterProxyModel(this);
m_fileProxy->setSortRole(Qt::DisplayRole);
m_fileProxy->setSortCaseSensitivity(Qt::CaseInsensitive);
m_fileProxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
m_fileProxy->setFilterRole(Qt::DisplayRole);
m_fileProxy->setFilterKeyColumn(0);
m_fileProxy->sort(0);
m_fileProxy->setSourceModel(ENV.metadataIndex().get());
ui->indexView->setModel(m_fileProxy);
m_filterProxy = new QSortFilterProxyModel(this);
m_filterProxy->setSortRole(VersionList::SortRole);
m_filterProxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
m_filterProxy->setFilterRole(Qt::DisplayRole);
m_filterProxy->setFilterKeyColumn(0);
m_filterProxy->sort(0, Qt::DescendingOrder);
ui->versionsView->setModel(m_filterProxy);
m_filterProxy = new QSortFilterProxyModel(this);
m_filterProxy->setSortRole(VersionList::SortRole);
m_filterProxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
m_filterProxy->setFilterRole(Qt::DisplayRole);
m_filterProxy->setFilterKeyColumn(0);
m_filterProxy->sort(0, Qt::DescendingOrder);
ui->versionsView->setModel(m_filterProxy);
m_versionProxy = new VersionProxyModel(this);
m_filterProxy->setSourceModel(m_versionProxy);
m_versionProxy = new VersionProxyModel(this);
m_filterProxy->setSourceModel(m_versionProxy);
connect(ui->indexView->selectionModel(), &QItemSelectionModel::currentChanged, this, &PackagesPage::updateCurrentVersionList);
connect(ui->versionsView->selectionModel(), &QItemSelectionModel::currentChanged, this, &PackagesPage::updateVersion);
connect(m_filterProxy, &QSortFilterProxyModel::dataChanged, this, &PackagesPage::versionListDataChanged);
connect(ui->indexView->selectionModel(), &QItemSelectionModel::currentChanged, this, &PackagesPage::updateCurrentVersionList);
connect(ui->versionsView->selectionModel(), &QItemSelectionModel::currentChanged, this, &PackagesPage::updateVersion);
connect(m_filterProxy, &QSortFilterProxyModel::dataChanged, this, &PackagesPage::versionListDataChanged);
updateCurrentVersionList(QModelIndex());
updateVersion();
updateCurrentVersionList(QModelIndex());
updateVersion();
}
PackagesPage::~PackagesPage()
{
delete ui;
delete ui;
}
QIcon PackagesPage::icon() const
{
return MMC->getThemedIcon("packages");
return MMC->getThemedIcon("packages");
}
void PackagesPage::on_refreshIndexBtn_clicked()
{
ENV.metadataIndex()->load(Net::Mode::Online);
ENV.metadataIndex()->load(Net::Mode::Online);
}
void PackagesPage::on_refreshFileBtn_clicked()
{
VersionListPtr list = ui->indexView->currentIndex().data(Index::ListPtrRole).value<VersionListPtr>();
if (!list)
{
return;
}
list->load(Net::Mode::Online);
VersionListPtr list = ui->indexView->currentIndex().data(Index::ListPtrRole).value<VersionListPtr>();
if (!list)
{
return;
}
list->load(Net::Mode::Online);
}
void PackagesPage::on_refreshVersionBtn_clicked()
{
VersionPtr version = ui->versionsView->currentIndex().data(VersionList::VersionPtrRole).value<VersionPtr>();
if (!version)
{
return;
}
version->load(Net::Mode::Online);
VersionPtr version = ui->versionsView->currentIndex().data(VersionList::VersionPtrRole).value<VersionPtr>();
if (!version)
{
return;
}
version->load(Net::Mode::Online);
}
void PackagesPage::on_fileSearchEdit_textChanged(const QString &search)
{
if (search.isEmpty())
{
m_fileProxy->setFilterFixedString(QString());
}
else
{
QStringList parts = search.split(' ');
std::transform(parts.begin(), parts.end(), parts.begin(), &QRegularExpression::escape);
m_fileProxy->setFilterRegExp(".*" + parts.join(".*") + ".*");
}
if (search.isEmpty())
{
m_fileProxy->setFilterFixedString(QString());
}
else
{
QStringList parts = search.split(' ');
std::transform(parts.begin(), parts.end(), parts.begin(), &QRegularExpression::escape);
m_fileProxy->setFilterRegExp(".*" + parts.join(".*") + ".*");
}
}
void PackagesPage::on_versionSearchEdit_textChanged(const QString &search)
{
if (search.isEmpty())
{
m_filterProxy->setFilterFixedString(QString());
}
else
{
QStringList parts = search.split(' ');
std::transform(parts.begin(), parts.end(), parts.begin(), &QRegularExpression::escape);
m_filterProxy->setFilterRegExp(".*" + parts.join(".*") + ".*");
}
if (search.isEmpty())
{
m_filterProxy->setFilterFixedString(QString());
}
else
{
QStringList parts = search.split(' ');
std::transform(parts.begin(), parts.end(), parts.begin(), &QRegularExpression::escape);
m_filterProxy->setFilterRegExp(".*" + parts.join(".*") + ".*");
}
}
void PackagesPage::updateCurrentVersionList(const QModelIndex &index)
{
if (index.isValid())
{
VersionListPtr list = index.data(Index::ListPtrRole).value<VersionListPtr>();
ui->versionsBox->setEnabled(true);
ui->refreshFileBtn->setEnabled(true);
ui->fileUidLabel->setEnabled(true);
ui->fileUid->setText(list->uid());
ui->fileNameLabel->setEnabled(true);
ui->fileName->setText(list->name());
m_versionProxy->setSourceModel(list.get());
ui->refreshFileBtn->setText(tr("Refresh %1").arg(list->humanReadable()));
list->load(Net::Mode::Offline);
}
else
{
ui->versionsBox->setEnabled(false);
ui->refreshFileBtn->setEnabled(false);
ui->fileUidLabel->setEnabled(false);
ui->fileUid->clear();
ui->fileNameLabel->setEnabled(false);
ui->fileName->clear();
m_versionProxy->setSourceModel(nullptr);
ui->refreshFileBtn->setText(tr("Refresh"));
}
if (index.isValid())
{
VersionListPtr list = index.data(Index::ListPtrRole).value<VersionListPtr>();
ui->versionsBox->setEnabled(true);
ui->refreshFileBtn->setEnabled(true);
ui->fileUidLabel->setEnabled(true);
ui->fileUid->setText(list->uid());
ui->fileNameLabel->setEnabled(true);
ui->fileName->setText(list->name());
m_versionProxy->setSourceModel(list.get());
ui->refreshFileBtn->setText(tr("Refresh %1").arg(list->humanReadable()));
list->load(Net::Mode::Offline);
}
else
{
ui->versionsBox->setEnabled(false);
ui->refreshFileBtn->setEnabled(false);
ui->fileUidLabel->setEnabled(false);
ui->fileUid->clear();
ui->fileNameLabel->setEnabled(false);
ui->fileName->clear();
m_versionProxy->setSourceModel(nullptr);
ui->refreshFileBtn->setText(tr("Refresh"));
}
}
void PackagesPage::versionListDataChanged(const QModelIndex &tl, const QModelIndex &br)
{
if (QItemSelection(tl, br).contains(ui->versionsView->currentIndex()))
{
updateVersion();
}
if (QItemSelection(tl, br).contains(ui->versionsView->currentIndex()))
{
updateVersion();
}
}
void PackagesPage::updateVersion()
{
VersionPtr version = std::dynamic_pointer_cast<Version>(
ui->versionsView->currentIndex().data(VersionList::VersionPointerRole).value<BaseVersionPtr>());
if (version)
{
ui->refreshVersionBtn->setEnabled(true);
ui->versionVersionLabel->setEnabled(true);
ui->versionVersion->setText(version->version());
ui->versionTimeLabel->setEnabled(true);
ui->versionTime->setText(version->time().toString("yyyy-MM-dd HH:mm"));
ui->versionTypeLabel->setEnabled(true);
ui->versionType->setText(version->type());
ui->versionRequiresLabel->setEnabled(true);
ui->versionRequires->setText(formatRequires(version));
ui->refreshVersionBtn->setText(tr("Refresh %1").arg(version->version()));
}
else
{
ui->refreshVersionBtn->setEnabled(false);
ui->versionVersionLabel->setEnabled(false);
ui->versionVersion->clear();
ui->versionTimeLabel->setEnabled(false);
ui->versionTime->clear();
ui->versionTypeLabel->setEnabled(false);
ui->versionType->clear();
ui->versionRequiresLabel->setEnabled(false);
ui->versionRequires->clear();
ui->refreshVersionBtn->setText(tr("Refresh"));
}
VersionPtr version = std::dynamic_pointer_cast<Version>(
ui->versionsView->currentIndex().data(VersionList::VersionPointerRole).value<BaseVersionPtr>());
if (version)
{
ui->refreshVersionBtn->setEnabled(true);
ui->versionVersionLabel->setEnabled(true);
ui->versionVersion->setText(version->version());
ui->versionTimeLabel->setEnabled(true);
ui->versionTime->setText(version->time().toString("yyyy-MM-dd HH:mm"));
ui->versionTypeLabel->setEnabled(true);
ui->versionType->setText(version->type());
ui->versionRequiresLabel->setEnabled(true);
ui->versionRequires->setText(formatRequires(version));
ui->refreshVersionBtn->setText(tr("Refresh %1").arg(version->version()));
}
else
{
ui->refreshVersionBtn->setEnabled(false);
ui->versionVersionLabel->setEnabled(false);
ui->versionVersion->clear();
ui->versionTimeLabel->setEnabled(false);
ui->versionTime->clear();
ui->versionTypeLabel->setEnabled(false);
ui->versionType->clear();
ui->versionRequiresLabel->setEnabled(false);
ui->versionRequires->clear();
ui->refreshVersionBtn->setText(tr("Refresh"));
}
}
void PackagesPage::openedImpl()
{
ENV.metadataIndex()->load(Net::Mode::Offline);
ENV.metadataIndex()->load(Net::Mode::Offline);
}

View File

@ -28,30 +28,30 @@ class VersionProxyModel;
class PackagesPage : public QWidget, public BasePage
{
Q_OBJECT
Q_OBJECT
public:
explicit PackagesPage(QWidget *parent = 0);
~PackagesPage();
explicit PackagesPage(QWidget *parent = 0);
~PackagesPage();
QString id() const override { return "packages-global"; }
QString displayName() const override { return tr("Packages"); }
QIcon icon() const override;
void openedImpl() override;
QString id() const override { return "packages-global"; }
QString displayName() const override { return tr("Packages"); }
QIcon icon() const override;
void openedImpl() override;
private slots:
void on_refreshIndexBtn_clicked();
void on_refreshFileBtn_clicked();
void on_refreshVersionBtn_clicked();
void on_fileSearchEdit_textChanged(const QString &search);
void on_versionSearchEdit_textChanged(const QString &search);
void updateCurrentVersionList(const QModelIndex &index);
void versionListDataChanged(const QModelIndex &tl, const QModelIndex &br);
void on_refreshIndexBtn_clicked();
void on_refreshFileBtn_clicked();
void on_refreshVersionBtn_clicked();
void on_fileSearchEdit_textChanged(const QString &search);
void on_versionSearchEdit_textChanged(const QString &search);
void updateCurrentVersionList(const QModelIndex &index);
void versionListDataChanged(const QModelIndex &tl, const QModelIndex &br);
private:
Ui::PackagesPage *ui;
QSortFilterProxyModel *m_fileProxy;
QSortFilterProxyModel *m_filterProxy;
VersionProxyModel *m_versionProxy;
Ui::PackagesPage *ui;
QSortFilterProxyModel *m_fileProxy;
QSortFilterProxyModel *m_filterProxy;
VersionProxyModel *m_versionProxy;
void updateVersion();
void updateVersion();
};

View File

@ -26,56 +26,56 @@
#include "MultiMC.h"
PasteEEPage::PasteEEPage(QWidget *parent) :
QWidget(parent),
ui(new Ui::PasteEEPage)
QWidget(parent),
ui(new Ui::PasteEEPage)
{
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();\
connect(ui->customAPIkeyEdit, &QLineEdit::textEdited, this, &PasteEEPage::textEdited);
loadSettings();
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();\
connect(ui->customAPIkeyEdit, &QLineEdit::textEdited, this, &PasteEEPage::textEdited);
loadSettings();
}
PasteEEPage::~PasteEEPage()
{
delete ui;
delete ui;
}
void PasteEEPage::loadSettings()
{
auto s = MMC->settings();
QString keyToUse = s->get("PasteEEAPIKey").toString();
if(keyToUse == "multimc")
{
ui->multimcButton->setChecked(true);
}
else
{
ui->customButton->setChecked(true);
ui->customAPIkeyEdit->setText(keyToUse);
}
auto s = MMC->settings();
QString keyToUse = s->get("PasteEEAPIKey").toString();
if(keyToUse == "multimc")
{
ui->multimcButton->setChecked(true);
}
else
{
ui->customButton->setChecked(true);
ui->customAPIkeyEdit->setText(keyToUse);
}
}
void PasteEEPage::applySettings()
{
auto s = MMC->settings();
auto s = MMC->settings();
QString pasteKeyToUse;
if (ui->customButton->isChecked())
pasteKeyToUse = ui->customAPIkeyEdit->text();
else
{
pasteKeyToUse = "multimc";
}
s->set("PasteEEAPIKey", pasteKeyToUse);
QString pasteKeyToUse;
if (ui->customButton->isChecked())
pasteKeyToUse = ui->customAPIkeyEdit->text();
else
{
pasteKeyToUse = "multimc";
}
s->set("PasteEEAPIKey", pasteKeyToUse);
}
bool PasteEEPage::apply()
{
applySettings();
return true;
applySettings();
return true;
}
void PasteEEPage::textEdited(const QString& text)
{
ui->customButton->setChecked(true);
ui->customButton->setChecked(true);
}

View File

@ -26,37 +26,37 @@ class PasteEEPage;
class PasteEEPage : public QWidget, public BasePage
{
Q_OBJECT
Q_OBJECT
public:
explicit PasteEEPage(QWidget *parent = 0);
~PasteEEPage();
explicit PasteEEPage(QWidget *parent = 0);
~PasteEEPage();
QString displayName() const override
{
return tr("Log Upload");
}
QIcon icon() const override
{
return MMC->getThemedIcon("log");
}
QString id() const override
{
return "log-upload";
}
QString helpPage() const override
{
return "Log-Upload";
}
virtual bool apply() override;
QString displayName() const override
{
return tr("Log Upload");
}
QIcon icon() const override
{
return MMC->getThemedIcon("log");
}
QString id() const override
{
return "log-upload";
}
QString helpPage() const override
{
return "Log-Upload";
}
virtual bool apply() override;
private:
void loadSettings();
void applySettings();
void loadSettings();
void applySettings();
private slots:
void textEdited(const QString &text);
void textEdited(const QString &text);
private:
Ui::PasteEEPage *ui;
Ui::PasteEEPage *ui;
};

View File

@ -23,75 +23,75 @@
ProxyPage::ProxyPage(QWidget *parent) : QWidget(parent), ui(new Ui::ProxyPage)
{
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();
loadSettings();
updateCheckboxStuff();
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();
loadSettings();
updateCheckboxStuff();
connect(ui->proxyGroup, SIGNAL(buttonClicked(int)), SLOT(proxyChanged(int)));
connect(ui->proxyGroup, SIGNAL(buttonClicked(int)), SLOT(proxyChanged(int)));
}
ProxyPage::~ProxyPage()
{
delete ui;
delete ui;
}
bool ProxyPage::apply()
{
applySettings();
return true;
applySettings();
return true;
}
void ProxyPage::updateCheckboxStuff()
{
ui->proxyAddrBox->setEnabled(!ui->proxyNoneBtn->isChecked() &&
!ui->proxyDefaultBtn->isChecked());
ui->proxyAuthBox->setEnabled(!ui->proxyNoneBtn->isChecked() &&
!ui->proxyDefaultBtn->isChecked());
ui->proxyAddrBox->setEnabled(!ui->proxyNoneBtn->isChecked() &&
!ui->proxyDefaultBtn->isChecked());
ui->proxyAuthBox->setEnabled(!ui->proxyNoneBtn->isChecked() &&
!ui->proxyDefaultBtn->isChecked());
}
void ProxyPage::proxyChanged(int)
{
updateCheckboxStuff();
updateCheckboxStuff();
}
void ProxyPage::applySettings()
{
auto s = MMC->settings();
auto s = MMC->settings();
// Proxy
QString proxyType = "None";
if (ui->proxyDefaultBtn->isChecked())
proxyType = "Default";
else if (ui->proxyNoneBtn->isChecked())
proxyType = "None";
else if (ui->proxySOCKS5Btn->isChecked())
proxyType = "SOCKS5";
else if (ui->proxyHTTPBtn->isChecked())
proxyType = "HTTP";
// Proxy
QString proxyType = "None";
if (ui->proxyDefaultBtn->isChecked())
proxyType = "Default";
else if (ui->proxyNoneBtn->isChecked())
proxyType = "None";
else if (ui->proxySOCKS5Btn->isChecked())
proxyType = "SOCKS5";
else if (ui->proxyHTTPBtn->isChecked())
proxyType = "HTTP";
s->set("ProxyType", proxyType);
s->set("ProxyAddr", ui->proxyAddrEdit->text());
s->set("ProxyPort", ui->proxyPortEdit->value());
s->set("ProxyUser", ui->proxyUserEdit->text());
s->set("ProxyPass", ui->proxyPassEdit->text());
s->set("ProxyType", proxyType);
s->set("ProxyAddr", ui->proxyAddrEdit->text());
s->set("ProxyPort", ui->proxyPortEdit->value());
s->set("ProxyUser", ui->proxyUserEdit->text());
s->set("ProxyPass", ui->proxyPassEdit->text());
}
void ProxyPage::loadSettings()
{
auto s = MMC->settings();
// Proxy
QString proxyType = s->get("ProxyType").toString();
if (proxyType == "Default")
ui->proxyDefaultBtn->setChecked(true);
else if (proxyType == "None")
ui->proxyNoneBtn->setChecked(true);
else if (proxyType == "SOCKS5")
ui->proxySOCKS5Btn->setChecked(true);
else if (proxyType == "HTTP")
ui->proxyHTTPBtn->setChecked(true);
auto s = MMC->settings();
// Proxy
QString proxyType = s->get("ProxyType").toString();
if (proxyType == "Default")
ui->proxyDefaultBtn->setChecked(true);
else if (proxyType == "None")
ui->proxyNoneBtn->setChecked(true);
else if (proxyType == "SOCKS5")
ui->proxySOCKS5Btn->setChecked(true);
else if (proxyType == "HTTP")
ui->proxyHTTPBtn->setChecked(true);
ui->proxyAddrEdit->setText(s->get("ProxyAddr").toString());
ui->proxyPortEdit->setValue(s->get("ProxyPort").value<qint16>());
ui->proxyUserEdit->setText(s->get("ProxyUser").toString());
ui->proxyPassEdit->setText(s->get("ProxyPass").toString());
ui->proxyAddrEdit->setText(s->get("ProxyAddr").toString());
ui->proxyPortEdit->setValue(s->get("ProxyPort").value<qint16>());
ui->proxyUserEdit->setText(s->get("ProxyUser").toString());
ui->proxyPassEdit->setText(s->get("ProxyPass").toString());
}

View File

@ -28,39 +28,39 @@ class ProxyPage;
class ProxyPage : public QWidget, public BasePage
{
Q_OBJECT
Q_OBJECT
public:
explicit ProxyPage(QWidget *parent = 0);
~ProxyPage();
explicit ProxyPage(QWidget *parent = 0);
~ProxyPage();
QString displayName() const override
{
return tr("Proxy");
}
QIcon icon() const override
{
return MMC->getThemedIcon("proxy");
}
QString id() const override
{
return "proxy-settings";
}
QString helpPage() const override
{
return "Proxy-settings";
}
bool apply() override;
QString displayName() const override
{
return tr("Proxy");
}
QIcon icon() const override
{
return MMC->getThemedIcon("proxy");
}
QString id() const override
{
return "proxy-settings";
}
QString helpPage() const override
{
return "Proxy-settings";
}
bool apply() override;
private:
void updateCheckboxStuff();
void applySettings();
void loadSettings();
void updateCheckboxStuff();
void applySettings();
void loadSettings();
private
slots:
void proxyChanged(int);
void proxyChanged(int);
private:
Ui::ProxyPage *ui;
Ui::ProxyPage *ui;
};

View File

@ -15,237 +15,237 @@
#include <widgets/CustomCommands.h>
InstanceSettingsPage::InstanceSettingsPage(BaseInstance *inst, QWidget *parent)
: QWidget(parent), ui(new Ui::InstanceSettingsPage), m_instance(inst)
: QWidget(parent), ui(new Ui::InstanceSettingsPage), m_instance(inst)
{
m_settings = inst->settings();
ui->setupUi(this);
auto sysMB = Sys::getSystemRam() / Sys::megabyte;
ui->maxMemSpinBox->setMaximum(sysMB);
loadSettings();
m_settings = inst->settings();
ui->setupUi(this);
auto sysMB = Sys::getSystemRam() / Sys::megabyte;
ui->maxMemSpinBox->setMaximum(sysMB);
loadSettings();
}
bool InstanceSettingsPage::shouldDisplay() const
{
return !m_instance->isRunning();
return !m_instance->isRunning();
}
InstanceSettingsPage::~InstanceSettingsPage()
{
delete ui;
delete ui;
}
bool InstanceSettingsPage::apply()
{
applySettings();
return true;
applySettings();
return true;
}
void InstanceSettingsPage::applySettings()
{
SettingsObject::Lock lock(m_settings);
SettingsObject::Lock lock(m_settings);
// Console
bool console = ui->consoleSettingsBox->isChecked();
m_settings->set("OverrideConsole", console);
if (console)
{
m_settings->set("ShowConsole", ui->showConsoleCheck->isChecked());
m_settings->set("AutoCloseConsole", ui->autoCloseConsoleCheck->isChecked());
m_settings->set("ShowConsoleOnError", ui->showConsoleErrorCheck->isChecked());
}
else
{
m_settings->reset("ShowConsole");
m_settings->reset("AutoCloseConsole");
m_settings->reset("ShowConsoleOnError");
}
// Console
bool console = ui->consoleSettingsBox->isChecked();
m_settings->set("OverrideConsole", console);
if (console)
{
m_settings->set("ShowConsole", ui->showConsoleCheck->isChecked());
m_settings->set("AutoCloseConsole", ui->autoCloseConsoleCheck->isChecked());
m_settings->set("ShowConsoleOnError", ui->showConsoleErrorCheck->isChecked());
}
else
{
m_settings->reset("ShowConsole");
m_settings->reset("AutoCloseConsole");
m_settings->reset("ShowConsoleOnError");
}
// Window Size
bool window = ui->windowSizeGroupBox->isChecked();
m_settings->set("OverrideWindow", window);
if (window)
{
m_settings->set("LaunchMaximized", ui->maximizedCheckBox->isChecked());
m_settings->set("MinecraftWinWidth", ui->windowWidthSpinBox->value());
m_settings->set("MinecraftWinHeight", ui->windowHeightSpinBox->value());
}
else
{
m_settings->reset("LaunchMaximized");
m_settings->reset("MinecraftWinWidth");
m_settings->reset("MinecraftWinHeight");
}
// Window Size
bool window = ui->windowSizeGroupBox->isChecked();
m_settings->set("OverrideWindow", window);
if (window)
{
m_settings->set("LaunchMaximized", ui->maximizedCheckBox->isChecked());
m_settings->set("MinecraftWinWidth", ui->windowWidthSpinBox->value());
m_settings->set("MinecraftWinHeight", ui->windowHeightSpinBox->value());
}
else
{
m_settings->reset("LaunchMaximized");
m_settings->reset("MinecraftWinWidth");
m_settings->reset("MinecraftWinHeight");
}
// Memory
bool memory = ui->memoryGroupBox->isChecked();
m_settings->set("OverrideMemory", memory);
if (memory)
{
int min = ui->minMemSpinBox->value();
int max = ui->maxMemSpinBox->value();
if(min < max)
{
m_settings->set("MinMemAlloc", min);
m_settings->set("MaxMemAlloc", max);
}
else
{
m_settings->set("MinMemAlloc", max);
m_settings->set("MaxMemAlloc", min);
}
m_settings->set("PermGen", ui->permGenSpinBox->value());
}
else
{
m_settings->reset("MinMemAlloc");
m_settings->reset("MaxMemAlloc");
m_settings->reset("PermGen");
}
// Memory
bool memory = ui->memoryGroupBox->isChecked();
m_settings->set("OverrideMemory", memory);
if (memory)
{
int min = ui->minMemSpinBox->value();
int max = ui->maxMemSpinBox->value();
if(min < max)
{
m_settings->set("MinMemAlloc", min);
m_settings->set("MaxMemAlloc", max);
}
else
{
m_settings->set("MinMemAlloc", max);
m_settings->set("MaxMemAlloc", min);
}
m_settings->set("PermGen", ui->permGenSpinBox->value());
}
else
{
m_settings->reset("MinMemAlloc");
m_settings->reset("MaxMemAlloc");
m_settings->reset("PermGen");
}
// Java Install Settings
bool javaInstall = ui->javaSettingsGroupBox->isChecked();
m_settings->set("OverrideJavaLocation", javaInstall);
if (javaInstall)
{
m_settings->set("JavaPath", ui->javaPathTextBox->text());
}
else
{
m_settings->reset("JavaPath");
}
// Java Install Settings
bool javaInstall = ui->javaSettingsGroupBox->isChecked();
m_settings->set("OverrideJavaLocation", javaInstall);
if (javaInstall)
{
m_settings->set("JavaPath", ui->javaPathTextBox->text());
}
else
{
m_settings->reset("JavaPath");
}
// Java arguments
bool javaArgs = ui->javaArgumentsGroupBox->isChecked();
m_settings->set("OverrideJavaArgs", javaArgs);
if(javaArgs)
{
m_settings->set("JvmArgs", ui->jvmArgsTextBox->toPlainText().replace("\n", " "));
JavaCommon::checkJVMArgs(m_settings->get("JvmArgs").toString(), this->parentWidget());
}
else
{
m_settings->reset("JvmArgs");
}
// Java arguments
bool javaArgs = ui->javaArgumentsGroupBox->isChecked();
m_settings->set("OverrideJavaArgs", javaArgs);
if(javaArgs)
{
m_settings->set("JvmArgs", ui->jvmArgsTextBox->toPlainText().replace("\n", " "));
JavaCommon::checkJVMArgs(m_settings->get("JvmArgs").toString(), this->parentWidget());
}
else
{
m_settings->reset("JvmArgs");
}
// old generic 'override both' is removed.
m_settings->reset("OverrideJava");
// old generic 'override both' is removed.
m_settings->reset("OverrideJava");
// Custom Commands
bool custcmd = ui->customCommands->checked();
m_settings->set("OverrideCommands", custcmd);
if (custcmd)
{
m_settings->set("PreLaunchCommand", ui->customCommands->prelaunchCommand());
m_settings->set("WrapperCommand", ui->customCommands->wrapperCommand());
m_settings->set("PostExitCommand", ui->customCommands->postexitCommand());
}
else
{
m_settings->reset("PreLaunchCommand");
m_settings->reset("WrapperCommand");
m_settings->reset("PostExitCommand");
}
// Custom Commands
bool custcmd = ui->customCommands->checked();
m_settings->set("OverrideCommands", custcmd);
if (custcmd)
{
m_settings->set("PreLaunchCommand", ui->customCommands->prelaunchCommand());
m_settings->set("WrapperCommand", ui->customCommands->wrapperCommand());
m_settings->set("PostExitCommand", ui->customCommands->postexitCommand());
}
else
{
m_settings->reset("PreLaunchCommand");
m_settings->reset("WrapperCommand");
m_settings->reset("PostExitCommand");
}
}
void InstanceSettingsPage::loadSettings()
{
// Console
ui->consoleSettingsBox->setChecked(m_settings->get("OverrideConsole").toBool());
ui->showConsoleCheck->setChecked(m_settings->get("ShowConsole").toBool());
ui->autoCloseConsoleCheck->setChecked(m_settings->get("AutoCloseConsole").toBool());
ui->showConsoleErrorCheck->setChecked(m_settings->get("ShowConsoleOnError").toBool());
// Console
ui->consoleSettingsBox->setChecked(m_settings->get("OverrideConsole").toBool());
ui->showConsoleCheck->setChecked(m_settings->get("ShowConsole").toBool());
ui->autoCloseConsoleCheck->setChecked(m_settings->get("AutoCloseConsole").toBool());
ui->showConsoleErrorCheck->setChecked(m_settings->get("ShowConsoleOnError").toBool());
// Window Size
ui->windowSizeGroupBox->setChecked(m_settings->get("OverrideWindow").toBool());
ui->maximizedCheckBox->setChecked(m_settings->get("LaunchMaximized").toBool());
ui->windowWidthSpinBox->setValue(m_settings->get("MinecraftWinWidth").toInt());
ui->windowHeightSpinBox->setValue(m_settings->get("MinecraftWinHeight").toInt());
// Window Size
ui->windowSizeGroupBox->setChecked(m_settings->get("OverrideWindow").toBool());
ui->maximizedCheckBox->setChecked(m_settings->get("LaunchMaximized").toBool());
ui->windowWidthSpinBox->setValue(m_settings->get("MinecraftWinWidth").toInt());
ui->windowHeightSpinBox->setValue(m_settings->get("MinecraftWinHeight").toInt());
// Memory
ui->memoryGroupBox->setChecked(m_settings->get("OverrideMemory").toBool());
int min = m_settings->get("MinMemAlloc").toInt();
int max = m_settings->get("MaxMemAlloc").toInt();
if(min < max)
{
ui->minMemSpinBox->setValue(min);
ui->maxMemSpinBox->setValue(max);
}
else
{
ui->minMemSpinBox->setValue(max);
ui->maxMemSpinBox->setValue(min);
}
ui->permGenSpinBox->setValue(m_settings->get("PermGen").toInt());
// Memory
ui->memoryGroupBox->setChecked(m_settings->get("OverrideMemory").toBool());
int min = m_settings->get("MinMemAlloc").toInt();
int max = m_settings->get("MaxMemAlloc").toInt();
if(min < max)
{
ui->minMemSpinBox->setValue(min);
ui->maxMemSpinBox->setValue(max);
}
else
{
ui->minMemSpinBox->setValue(max);
ui->maxMemSpinBox->setValue(min);
}
ui->permGenSpinBox->setValue(m_settings->get("PermGen").toInt());
// Java Settings
bool overrideJava = m_settings->get("OverrideJava").toBool();
bool overrideLocation = m_settings->get("OverrideJavaLocation").toBool() || overrideJava;
bool overrideArgs = m_settings->get("OverrideJavaArgs").toBool() || overrideJava;
// Java Settings
bool overrideJava = m_settings->get("OverrideJava").toBool();
bool overrideLocation = m_settings->get("OverrideJavaLocation").toBool() || overrideJava;
bool overrideArgs = m_settings->get("OverrideJavaArgs").toBool() || overrideJava;
ui->javaSettingsGroupBox->setChecked(overrideLocation);
ui->javaPathTextBox->setText(m_settings->get("JavaPath").toString());
ui->javaSettingsGroupBox->setChecked(overrideLocation);
ui->javaPathTextBox->setText(m_settings->get("JavaPath").toString());
ui->javaArgumentsGroupBox->setChecked(overrideArgs);
ui->jvmArgsTextBox->setPlainText(m_settings->get("JvmArgs").toString());
ui->javaArgumentsGroupBox->setChecked(overrideArgs);
ui->jvmArgsTextBox->setPlainText(m_settings->get("JvmArgs").toString());
// Custom commands
ui->customCommands->initialize(
true,
m_settings->get("OverrideCommands").toBool(),
m_settings->get("PreLaunchCommand").toString(),
m_settings->get("WrapperCommand").toString(),
m_settings->get("PostExitCommand").toString()
);
// Custom commands
ui->customCommands->initialize(
true,
m_settings->get("OverrideCommands").toBool(),
m_settings->get("PreLaunchCommand").toString(),
m_settings->get("WrapperCommand").toString(),
m_settings->get("PostExitCommand").toString()
);
}
void InstanceSettingsPage::on_javaDetectBtn_clicked()
{
JavaInstallPtr java;
JavaInstallPtr java;
VersionSelectDialog vselect(MMC->javalist().get(), tr("Select a Java version"), this, true);
vselect.setResizeOn(2);
vselect.exec();
VersionSelectDialog vselect(MMC->javalist().get(), tr("Select a Java version"), this, true);
vselect.setResizeOn(2);
vselect.exec();
if (vselect.result() == QDialog::Accepted && vselect.selectedVersion())
{
java = std::dynamic_pointer_cast<JavaInstall>(vselect.selectedVersion());
ui->javaPathTextBox->setText(java->path);
}
if (vselect.result() == QDialog::Accepted && vselect.selectedVersion())
{
java = std::dynamic_pointer_cast<JavaInstall>(vselect.selectedVersion());
ui->javaPathTextBox->setText(java->path);
}
}
void InstanceSettingsPage::on_javaBrowseBtn_clicked()
{
QString raw_path = QFileDialog::getOpenFileName(this, tr("Find Java executable"));
QString raw_path = QFileDialog::getOpenFileName(this, tr("Find Java executable"));
// do not allow current dir - it's dirty. Do not allow dirs that don't exist
if(raw_path.isEmpty())
{
return;
}
QString cooked_path = FS::NormalizePath(raw_path);
// do not allow current dir - it's dirty. Do not allow dirs that don't exist
if(raw_path.isEmpty())
{
return;
}
QString cooked_path = FS::NormalizePath(raw_path);
QFileInfo javaInfo(cooked_path);;
if(!javaInfo.exists() || !javaInfo.isExecutable())
{
return;
}
ui->javaPathTextBox->setText(cooked_path);
QFileInfo javaInfo(cooked_path);;
if(!javaInfo.exists() || !javaInfo.isExecutable())
{
return;
}
ui->javaPathTextBox->setText(cooked_path);
}
void InstanceSettingsPage::on_javaTestBtn_clicked()
{
if(checker)
{
return;
}
checker.reset(new JavaCommon::TestCheck(
this, ui->javaPathTextBox->text(), ui->jvmArgsTextBox->toPlainText().replace("\n", " "),
ui->minMemSpinBox->value(), ui->maxMemSpinBox->value(), ui->permGenSpinBox->value()));
connect(checker.get(), SIGNAL(finished()), SLOT(checkerFinished()));
checker->run();
if(checker)
{
return;
}
checker.reset(new JavaCommon::TestCheck(
this, ui->javaPathTextBox->text(), ui->jvmArgsTextBox->toPlainText().replace("\n", " "),
ui->minMemSpinBox->value(), ui->maxMemSpinBox->value(), ui->permGenSpinBox->value()));
connect(checker.get(), SIGNAL(finished()), SLOT(checkerFinished()));
checker->run();
}
void InstanceSettingsPage::checkerFinished()
{
checker.reset();
checker.reset();
}

View File

@ -32,43 +32,43 @@ class InstanceSettingsPage;
class InstanceSettingsPage : public QWidget, public BasePage
{
Q_OBJECT
Q_OBJECT
public:
explicit InstanceSettingsPage(BaseInstance *inst, QWidget *parent = 0);
virtual ~InstanceSettingsPage();
virtual QString displayName() const override
{
return tr("Settings");
}
virtual QIcon icon() const override
{
return MMC->getThemedIcon("instance-settings");
}
virtual QString id() const override
{
return "settings";
}
virtual bool apply() override;
virtual QString helpPage() const override
{
return "Instance-settings";
}
virtual bool shouldDisplay() const override;
explicit InstanceSettingsPage(BaseInstance *inst, QWidget *parent = 0);
virtual ~InstanceSettingsPage();
virtual QString displayName() const override
{
return tr("Settings");
}
virtual QIcon icon() const override
{
return MMC->getThemedIcon("instance-settings");
}
virtual QString id() const override
{
return "settings";
}
virtual bool apply() override;
virtual QString helpPage() const override
{
return "Instance-settings";
}
virtual bool shouldDisplay() const override;
private slots:
void on_javaDetectBtn_clicked();
void on_javaTestBtn_clicked();
void on_javaBrowseBtn_clicked();
void on_javaDetectBtn_clicked();
void on_javaTestBtn_clicked();
void on_javaBrowseBtn_clicked();
void applySettings();
void loadSettings();
void applySettings();
void loadSettings();
void checkerFinished();
void checkerFinished();
private:
Ui::InstanceSettingsPage *ui;
BaseInstance *m_instance;
SettingsObjectPtr m_settings;
unique_qobject_ptr<JavaCommon::TestCheck> checker;
Ui::InstanceSettingsPage *ui;
BaseInstance *m_instance;
SettingsObjectPtr m_settings;
unique_qobject_ptr<JavaCommon::TestCheck> checker;
};

View File

@ -9,42 +9,42 @@
#include "dialogs/ProgressDialog.h"
LegacyUpgradePage::LegacyUpgradePage(InstancePtr inst, QWidget *parent)
: QWidget(parent), ui(new Ui::LegacyUpgradePage), m_inst(inst)
: QWidget(parent), ui(new Ui::LegacyUpgradePage), m_inst(inst)
{
ui->setupUi(this);
ui->setupUi(this);
}
LegacyUpgradePage::~LegacyUpgradePage()
{
delete ui;
delete ui;
}
void LegacyUpgradePage::runModalTask(Task *task)
{
connect(task, &Task::failed, [this](QString reason)
{
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Warning)->show();
});
ProgressDialog loadDialog(this);
loadDialog.setSkipButton(true, tr("Abort"));
if(loadDialog.execWithTask(task) == QDialog::Accepted)
{
m_container->requestClose();
}
connect(task, &Task::failed, [this](QString reason)
{
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Warning)->show();
});
ProgressDialog loadDialog(this);
loadDialog.setSkipButton(true, tr("Abort"));
if(loadDialog.execWithTask(task) == QDialog::Accepted)
{
m_container->requestClose();
}
}
void LegacyUpgradePage::on_upgradeButton_clicked()
{
QString newName = tr("%1 (Migrated)").arg(m_inst->name());
auto upgradeTask = new LegacyUpgradeTask(m_inst);
upgradeTask->setName(newName);
upgradeTask->setGroup(m_inst->group());
upgradeTask->setIcon(m_inst->iconKey());
std::unique_ptr<Task> task(MMC->folderProvider()->wrapInstanceTask(upgradeTask));
runModalTask(task.get());
QString newName = tr("%1 (Migrated)").arg(m_inst->name());
auto upgradeTask = new LegacyUpgradeTask(m_inst);
upgradeTask->setName(newName);
upgradeTask->setGroup(m_inst->group());
upgradeTask->setIcon(m_inst->iconKey());
std::unique_ptr<Task> task(MMC->folderProvider()->wrapInstanceTask(upgradeTask));
runModalTask(task.get());
}
bool LegacyUpgradePage::shouldDisplay() const
{
return !m_inst->isRunning();
return !m_inst->isRunning();
}

View File

@ -29,36 +29,36 @@ class LegacyUpgradePage;
class LegacyUpgradePage : public QWidget, public BasePage
{
Q_OBJECT
Q_OBJECT
public:
explicit LegacyUpgradePage(InstancePtr inst, QWidget *parent = 0);
virtual ~LegacyUpgradePage();
virtual QString displayName() const override
{
return tr("Upgrade");
}
virtual QIcon icon() const override
{
return MMC->getThemedIcon("checkupdate");
}
virtual QString id() const override
{
return "upgrade";
}
virtual QString helpPage() const override
{
return "Legacy-upgrade";
}
virtual bool shouldDisplay() const override;
explicit LegacyUpgradePage(InstancePtr inst, QWidget *parent = 0);
virtual ~LegacyUpgradePage();
virtual QString displayName() const override
{
return tr("Upgrade");
}
virtual QIcon icon() const override
{
return MMC->getThemedIcon("checkupdate");
}
virtual QString id() const override
{
return "upgrade";
}
virtual QString helpPage() const override
{
return "Legacy-upgrade";
}
virtual bool shouldDisplay() const override;
private slots:
void on_upgradeButton_clicked();
void on_upgradeButton_clicked();
private:
void runModalTask(Task *task);
void runModalTask(Task *task);
private:
Ui::LegacyUpgradePage *ui;
InstancePtr m_inst;
Ui::LegacyUpgradePage *ui;
InstancePtr m_inst;
};

View File

@ -15,298 +15,298 @@
class LogFormatProxyModel : public QIdentityProxyModel
{
public:
LogFormatProxyModel(QObject* parent = nullptr) : QIdentityProxyModel(parent)
{
}
QVariant data(const QModelIndex &index, int role) const override
{
switch(role)
{
case Qt::FontRole:
return m_font;
case Qt::TextColorRole:
{
MessageLevel::Enum level = (MessageLevel::Enum) QIdentityProxyModel::data(index, LogModel::LevelRole).toInt();
return m_colors->getFront(level);
}
case Qt::BackgroundRole:
{
MessageLevel::Enum level = (MessageLevel::Enum) QIdentityProxyModel::data(index, LogModel::LevelRole).toInt();
return m_colors->getBack(level);
}
default:
return QIdentityProxyModel::data(index, role);
}
}
LogFormatProxyModel(QObject* parent = nullptr) : QIdentityProxyModel(parent)
{
}
QVariant data(const QModelIndex &index, int role) const override
{
switch(role)
{
case Qt::FontRole:
return m_font;
case Qt::TextColorRole:
{
MessageLevel::Enum level = (MessageLevel::Enum) QIdentityProxyModel::data(index, LogModel::LevelRole).toInt();
return m_colors->getFront(level);
}
case Qt::BackgroundRole:
{
MessageLevel::Enum level = (MessageLevel::Enum) QIdentityProxyModel::data(index, LogModel::LevelRole).toInt();
return m_colors->getBack(level);
}
default:
return QIdentityProxyModel::data(index, role);
}
}
void setFont(QFont font)
{
m_font = font;
}
void setFont(QFont font)
{
m_font = font;
}
void setColors(LogColorCache* colors)
{
m_colors.reset(colors);
}
void setColors(LogColorCache* colors)
{
m_colors.reset(colors);
}
QModelIndex find(const QModelIndex &start, const QString &value, bool reverse) const
{
QModelIndex parentIndex = parent(start);
auto compare = [&](int r) -> QModelIndex
{
QModelIndex idx = index(r, start.column(), parentIndex);
if (!idx.isValid() || idx == start)
{
return QModelIndex();
}
QVariant v = data(idx, Qt::DisplayRole);
QString t = v.toString();
if (t.contains(value, Qt::CaseInsensitive))
return idx;
return QModelIndex();
};
if(reverse)
{
int from = start.row();
int to = 0;
QModelIndex find(const QModelIndex &start, const QString &value, bool reverse) const
{
QModelIndex parentIndex = parent(start);
auto compare = [&](int r) -> QModelIndex
{
QModelIndex idx = index(r, start.column(), parentIndex);
if (!idx.isValid() || idx == start)
{
return QModelIndex();
}
QVariant v = data(idx, Qt::DisplayRole);
QString t = v.toString();
if (t.contains(value, Qt::CaseInsensitive))
return idx;
return QModelIndex();
};
if(reverse)
{
int from = start.row();
int to = 0;
for (int i = 0; i < 2; ++i)
{
for (int r = from; (r >= to); --r)
{
auto idx = compare(r);
if(idx.isValid())
return idx;
}
// prepare for the next iteration
from = rowCount() - 1;
to = start.row();
}
}
else
{
int from = start.row();
int to = rowCount(parentIndex);
for (int i = 0; i < 2; ++i)
{
for (int r = from; (r >= to); --r)
{
auto idx = compare(r);
if(idx.isValid())
return idx;
}
// prepare for the next iteration
from = rowCount() - 1;
to = start.row();
}
}
else
{
int from = start.row();
int to = rowCount(parentIndex);
for (int i = 0; i < 2; ++i)
{
for (int r = from; (r < to); ++r)
{
auto idx = compare(r);
if(idx.isValid())
return idx;
}
// prepare for the next iteration
from = 0;
to = start.row();
}
}
return QModelIndex();
}
for (int i = 0; i < 2; ++i)
{
for (int r = from; (r < to); ++r)
{
auto idx = compare(r);
if(idx.isValid())
return idx;
}
// prepare for the next iteration
from = 0;
to = start.row();
}
}
return QModelIndex();
}
private:
QFont m_font;
std::unique_ptr<LogColorCache> m_colors;
QFont m_font;
std::unique_ptr<LogColorCache> m_colors;
};
LogPage::LogPage(InstancePtr instance, QWidget *parent)
: QWidget(parent), ui(new Ui::LogPage), m_instance(instance)
: QWidget(parent), ui(new Ui::LogPage), m_instance(instance)
{
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();
m_proxy = new LogFormatProxyModel(this);
// set up text colors in the log proxy and adapt them to the current theme foreground and background
{
auto origForeground = ui->text->palette().color(ui->text->foregroundRole());
auto origBackground = ui->text->palette().color(ui->text->backgroundRole());
m_proxy->setColors(new LogColorCache(origForeground, origBackground));
}
m_proxy = new LogFormatProxyModel(this);
// set up text colors in the log proxy and adapt them to the current theme foreground and background
{
auto origForeground = ui->text->palette().color(ui->text->foregroundRole());
auto origBackground = ui->text->palette().color(ui->text->backgroundRole());
m_proxy->setColors(new LogColorCache(origForeground, origBackground));
}
// set up fonts in the log proxy
{
QString fontFamily = MMC->settings()->get("ConsoleFont").toString();
bool conversionOk = false;
int fontSize = MMC->settings()->get("ConsoleFontSize").toInt(&conversionOk);
if(!conversionOk)
{
fontSize = 11;
}
m_proxy->setFont(QFont(fontFamily, fontSize));
}
// set up fonts in the log proxy
{
QString fontFamily = MMC->settings()->get("ConsoleFont").toString();
bool conversionOk = false;
int fontSize = MMC->settings()->get("ConsoleFontSize").toInt(&conversionOk);
if(!conversionOk)
{
fontSize = 11;
}
m_proxy->setFont(QFont(fontFamily, fontSize));
}
ui->text->setModel(m_proxy);
ui->text->setModel(m_proxy);
// set up instance and launch process recognition
{
auto launchTask = m_instance->getLaunchTask();
if(launchTask)
{
setInstanceLaunchTaskChanged(launchTask, true);
}
connect(m_instance.get(), &BaseInstance::launchTaskChanged, this, &LogPage::onInstanceLaunchTaskChanged);
}
// set up instance and launch process recognition
{
auto launchTask = m_instance->getLaunchTask();
if(launchTask)
{
setInstanceLaunchTaskChanged(launchTask, true);
}
connect(m_instance.get(), &BaseInstance::launchTaskChanged, this, &LogPage::onInstanceLaunchTaskChanged);
}
auto findShortcut = new QShortcut(QKeySequence(QKeySequence::Find), this);
connect(findShortcut, SIGNAL(activated()), SLOT(findActivated()));
auto findNextShortcut = new QShortcut(QKeySequence(QKeySequence::FindNext), this);
connect(findNextShortcut, SIGNAL(activated()), SLOT(findNextActivated()));
connect(ui->searchBar, SIGNAL(returnPressed()), SLOT(on_findButton_clicked()));
auto findPreviousShortcut = new QShortcut(QKeySequence(QKeySequence::FindPrevious), this);
connect(findPreviousShortcut, SIGNAL(activated()), SLOT(findPreviousActivated()));
auto findShortcut = new QShortcut(QKeySequence(QKeySequence::Find), this);
connect(findShortcut, SIGNAL(activated()), SLOT(findActivated()));
auto findNextShortcut = new QShortcut(QKeySequence(QKeySequence::FindNext), this);
connect(findNextShortcut, SIGNAL(activated()), SLOT(findNextActivated()));
connect(ui->searchBar, SIGNAL(returnPressed()), SLOT(on_findButton_clicked()));
auto findPreviousShortcut = new QShortcut(QKeySequence(QKeySequence::FindPrevious), this);
connect(findPreviousShortcut, SIGNAL(activated()), SLOT(findPreviousActivated()));
}
LogPage::~LogPage()
{
delete ui;
delete ui;
}
void LogPage::modelStateToUI()
{
if(m_model->wrapLines())
{
ui->text->setWordWrap(true);
ui->wrapCheckbox->setCheckState(Qt::Checked);
}
else
{
ui->text->setWordWrap(false);
ui->wrapCheckbox->setCheckState(Qt::Unchecked);
}
if(m_model->suspended())
{
ui->trackLogCheckbox->setCheckState(Qt::Unchecked);
}
else
{
ui->trackLogCheckbox->setCheckState(Qt::Checked);
}
if(m_model->wrapLines())
{
ui->text->setWordWrap(true);
ui->wrapCheckbox->setCheckState(Qt::Checked);
}
else
{
ui->text->setWordWrap(false);
ui->wrapCheckbox->setCheckState(Qt::Unchecked);
}
if(m_model->suspended())
{
ui->trackLogCheckbox->setCheckState(Qt::Unchecked);
}
else
{
ui->trackLogCheckbox->setCheckState(Qt::Checked);
}
}
void LogPage::UIToModelState()
{
if(!m_model)
{
return;
}
m_model->setLineWrap(ui->wrapCheckbox->checkState() == Qt::Checked);
m_model->suspend(ui->trackLogCheckbox->checkState() != Qt::Checked);
if(!m_model)
{
return;
}
m_model->setLineWrap(ui->wrapCheckbox->checkState() == Qt::Checked);
m_model->suspend(ui->trackLogCheckbox->checkState() != Qt::Checked);
}
void LogPage::setInstanceLaunchTaskChanged(std::shared_ptr<LaunchTask> proc, bool initial)
{
m_process = proc;
if(m_process)
{
m_model = proc->getLogModel();
m_proxy->setSourceModel(m_model.get());
if(initial)
{
modelStateToUI();
}
else
{
UIToModelState();
}
}
else
{
m_proxy->setSourceModel(nullptr);
m_model.reset();
}
m_process = proc;
if(m_process)
{
m_model = proc->getLogModel();
m_proxy->setSourceModel(m_model.get());
if(initial)
{
modelStateToUI();
}
else
{
UIToModelState();
}
}
else
{
m_proxy->setSourceModel(nullptr);
m_model.reset();
}
}
void LogPage::onInstanceLaunchTaskChanged(std::shared_ptr<LaunchTask> proc)
{
setInstanceLaunchTaskChanged(proc, false);
setInstanceLaunchTaskChanged(proc, false);
}
bool LogPage::apply()
{
return true;
return true;
}
bool LogPage::shouldDisplay() const
{
return m_instance->isRunning() || m_proxy->rowCount() > 0;
return m_instance->isRunning() || m_proxy->rowCount() > 0;
}
void LogPage::on_btnPaste_clicked()
{
if(!m_model)
return;
if(!m_model)
return;
//FIXME: turn this into a proper task and move the upload logic out of GuiUtil!
m_model->append(MessageLevel::MultiMC, tr("MultiMC: Log upload triggered at: %1").arg(QDateTime::currentDateTime().toString(Qt::RFC2822Date)));
auto url = GuiUtil::uploadPaste(m_model->toPlainText(), this);
if(!url.isEmpty())
{
m_model->append(MessageLevel::MultiMC, tr("MultiMC: Log uploaded to: %1").arg(url));
}
else
{
m_model->append(MessageLevel::Error, tr("MultiMC: Log upload failed!"));
}
//FIXME: turn this into a proper task and move the upload logic out of GuiUtil!
m_model->append(MessageLevel::MultiMC, tr("MultiMC: Log upload triggered at: %1").arg(QDateTime::currentDateTime().toString(Qt::RFC2822Date)));
auto url = GuiUtil::uploadPaste(m_model->toPlainText(), this);
if(!url.isEmpty())
{
m_model->append(MessageLevel::MultiMC, tr("MultiMC: Log uploaded to: %1").arg(url));
}
else
{
m_model->append(MessageLevel::Error, tr("MultiMC: Log upload failed!"));
}
}
void LogPage::on_btnCopy_clicked()
{
if(!m_model)
return;
m_model->append(MessageLevel::MultiMC, QString("Clipboard copy at: %1").arg(QDateTime::currentDateTime().toString(Qt::RFC2822Date)));
GuiUtil::setClipboardText(m_model->toPlainText());
if(!m_model)
return;
m_model->append(MessageLevel::MultiMC, QString("Clipboard copy at: %1").arg(QDateTime::currentDateTime().toString(Qt::RFC2822Date)));
GuiUtil::setClipboardText(m_model->toPlainText());
}
void LogPage::on_btnClear_clicked()
{
if(!m_model)
return;
m_model->clear();
m_container->refreshContainer();
if(!m_model)
return;
m_model->clear();
m_container->refreshContainer();
}
void LogPage::on_btnBottom_clicked()
{
ui->text->scrollToBottom();
ui->text->scrollToBottom();
}
void LogPage::on_trackLogCheckbox_clicked(bool checked)
{
if(!m_model)
return;
m_model->suspend(!checked);
if(!m_model)
return;
m_model->suspend(!checked);
}
void LogPage::on_wrapCheckbox_clicked(bool checked)
{
ui->text->setWordWrap(checked);
if(!m_model)
return;
m_model->setLineWrap(checked);
ui->text->setWordWrap(checked);
if(!m_model)
return;
m_model->setLineWrap(checked);
}
void LogPage::on_findButton_clicked()
{
auto modifiers = QApplication::keyboardModifiers();
bool reverse = modifiers & Qt::ShiftModifier;
ui->text->findNext(ui->searchBar->text(), reverse);
auto modifiers = QApplication::keyboardModifiers();
bool reverse = modifiers & Qt::ShiftModifier;
ui->text->findNext(ui->searchBar->text(), reverse);
}
void LogPage::findNextActivated()
{
ui->text->findNext(ui->searchBar->text(), false);
ui->text->findNext(ui->searchBar->text(), false);
}
void LogPage::findPreviousActivated()
{
ui->text->findNext(ui->searchBar->text(), true);
ui->text->findNext(ui->searchBar->text(), true);
}
void LogPage::findActivated()
{
// focus the search bar if it doesn't have focus
if (!ui->searchBar->hasFocus())
{
ui->searchBar->setFocus();
ui->searchBar->selectAll();
}
// focus the search bar if it doesn't have focus
if (!ui->searchBar->hasFocus())
{
ui->searchBar->setFocus();
ui->searchBar->selectAll();
}
}

View File

@ -31,56 +31,56 @@ class LogFormatProxyModel;
class LogPage : public QWidget, public BasePage
{
Q_OBJECT
Q_OBJECT
public:
explicit LogPage(InstancePtr instance, QWidget *parent = 0);
virtual ~LogPage();
virtual QString displayName() const override
{
return tr("Minecraft Log");
}
virtual QIcon icon() const override
{
return MMC->getThemedIcon("log");
}
virtual QString id() const override
{
return "console";
}
virtual bool apply() override;
virtual QString helpPage() const override
{
return "Minecraft-Logs";
}
virtual bool shouldDisplay() const override;
explicit LogPage(InstancePtr instance, QWidget *parent = 0);
virtual ~LogPage();
virtual QString displayName() const override
{
return tr("Minecraft Log");
}
virtual QIcon icon() const override
{
return MMC->getThemedIcon("log");
}
virtual QString id() const override
{
return "console";
}
virtual bool apply() override;
virtual QString helpPage() const override
{
return "Minecraft-Logs";
}
virtual bool shouldDisplay() const override;
private slots:
void on_btnPaste_clicked();
void on_btnCopy_clicked();
void on_btnClear_clicked();
void on_btnBottom_clicked();
void on_btnPaste_clicked();
void on_btnCopy_clicked();
void on_btnClear_clicked();
void on_btnBottom_clicked();
void on_trackLogCheckbox_clicked(bool checked);
void on_wrapCheckbox_clicked(bool checked);
void on_trackLogCheckbox_clicked(bool checked);
void on_wrapCheckbox_clicked(bool checked);
void on_findButton_clicked();
void findActivated();
void findNextActivated();
void findPreviousActivated();
void on_findButton_clicked();
void findActivated();
void findNextActivated();
void findPreviousActivated();
void onInstanceLaunchTaskChanged(std::shared_ptr<LaunchTask> proc);
void onInstanceLaunchTaskChanged(std::shared_ptr<LaunchTask> proc);
private:
void modelStateToUI();
void UIToModelState();
void setInstanceLaunchTaskChanged(std::shared_ptr<LaunchTask> proc, bool initial);
void modelStateToUI();
void UIToModelState();
void setInstanceLaunchTaskChanged(std::shared_ptr<LaunchTask> proc, bool initial);
private:
Ui::LogPage *ui;
InstancePtr m_instance;
std::shared_ptr<LaunchTask> m_process;
Ui::LogPage *ui;
InstancePtr m_instance;
std::shared_ptr<LaunchTask> m_process;
LogFormatProxyModel * m_proxy;
shared_qobject_ptr <LogModel> m_model;
LogFormatProxyModel * m_proxy;
shared_qobject_ptr <LogModel> m_model;
};

View File

@ -32,179 +32,179 @@
#include <DesktopServices.h>
ModFolderPage::ModFolderPage(BaseInstance *inst, std::shared_ptr<SimpleModList> mods, QString id,
QString iconName, QString displayName, QString helpPage,
QWidget *parent)
: QWidget(parent), ui(new Ui::ModFolderPage)
QString iconName, QString displayName, QString helpPage,
QWidget *parent)
: QWidget(parent), ui(new Ui::ModFolderPage)
{
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();
m_inst = inst;
m_mods = mods;
m_id = id;
m_displayName = displayName;
m_iconName = iconName;
m_helpName = helpPage;
m_fileSelectionFilter = "%1 (*.zip *.jar)";
m_filterModel = new QSortFilterProxyModel(this);
m_filterModel->setDynamicSortFilter(true);
m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
m_filterModel->setSortCaseSensitivity(Qt::CaseInsensitive);
m_filterModel->setSourceModel(m_mods.get());
m_filterModel->setFilterKeyColumn(-1);
ui->modTreeView->setModel(m_filterModel);
ui->modTreeView->installEventFilter(this);
ui->modTreeView->sortByColumn(1, Qt::AscendingOrder);
auto smodel = ui->modTreeView->selectionModel();
connect(smodel, &QItemSelectionModel::currentChanged, this, &ModFolderPage::modCurrent);
connect(ui->filterEdit, &QLineEdit::textChanged, this, &ModFolderPage::on_filterTextChanged );
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();
m_inst = inst;
m_mods = mods;
m_id = id;
m_displayName = displayName;
m_iconName = iconName;
m_helpName = helpPage;
m_fileSelectionFilter = "%1 (*.zip *.jar)";
m_filterModel = new QSortFilterProxyModel(this);
m_filterModel->setDynamicSortFilter(true);
m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
m_filterModel->setSortCaseSensitivity(Qt::CaseInsensitive);
m_filterModel->setSourceModel(m_mods.get());
m_filterModel->setFilterKeyColumn(-1);
ui->modTreeView->setModel(m_filterModel);
ui->modTreeView->installEventFilter(this);
ui->modTreeView->sortByColumn(1, Qt::AscendingOrder);
auto smodel = ui->modTreeView->selectionModel();
connect(smodel, &QItemSelectionModel::currentChanged, this, &ModFolderPage::modCurrent);
connect(ui->filterEdit, &QLineEdit::textChanged, this, &ModFolderPage::on_filterTextChanged );
}
void ModFolderPage::openedImpl()
{
m_mods->startWatching();
m_mods->startWatching();
}
void ModFolderPage::closedImpl()
{
m_mods->stopWatching();
m_mods->stopWatching();
}
void ModFolderPage::on_filterTextChanged(const QString& newContents)
{
m_viewFilter = newContents;
m_filterModel->setFilterFixedString(m_viewFilter);
m_viewFilter = newContents;
m_filterModel->setFilterFixedString(m_viewFilter);
}
CoreModFolderPage::CoreModFolderPage(BaseInstance *inst, std::shared_ptr<SimpleModList> mods,
QString id, QString iconName, QString displayName,
QString helpPage, QWidget *parent)
: ModFolderPage(inst, mods, id, iconName, displayName, helpPage, parent)
QString id, QString iconName, QString displayName,
QString helpPage, QWidget *parent)
: ModFolderPage(inst, mods, id, iconName, displayName, helpPage, parent)
{
}
ModFolderPage::~ModFolderPage()
{
m_mods->stopWatching();
delete ui;
m_mods->stopWatching();
delete ui;
}
bool ModFolderPage::shouldDisplay() const
{
if (m_inst)
return !m_inst->isRunning();
return true;
if (m_inst)
return !m_inst->isRunning();
return true;
}
bool CoreModFolderPage::shouldDisplay() const
{
if (ModFolderPage::shouldDisplay())
{
auto inst = dynamic_cast<MinecraftInstance *>(m_inst);
if (!inst)
return true;
auto version = inst->getComponentList();
if (!version)
return true;
if(!version->getComponent("net.minecraftforge"))
{
return false;
}
if(!version->getComponent("net.minecraft"))
{
return false;
}
if(version->getComponent("net.minecraft")->getReleaseDateTime() < g_VersionFilterData.legacyCutoffDate)
{
return true;
}
}
return false;
if (ModFolderPage::shouldDisplay())
{
auto inst = dynamic_cast<MinecraftInstance *>(m_inst);
if (!inst)
return true;
auto version = inst->getComponentList();
if (!version)
return true;
if(!version->getComponent("net.minecraftforge"))
{
return false;
}
if(!version->getComponent("net.minecraft"))
{
return false;
}
if(version->getComponent("net.minecraft")->getReleaseDateTime() < g_VersionFilterData.legacyCutoffDate)
{
return true;
}
}
return false;
}
bool ModFolderPage::modListFilter(QKeyEvent *keyEvent)
{
switch (keyEvent->key())
{
case Qt::Key_Delete:
on_rmModBtn_clicked();
return true;
case Qt::Key_Plus:
on_addModBtn_clicked();
return true;
default:
break;
}
return QWidget::eventFilter(ui->modTreeView, keyEvent);
switch (keyEvent->key())
{
case Qt::Key_Delete:
on_rmModBtn_clicked();
return true;
case Qt::Key_Plus:
on_addModBtn_clicked();
return true;
default:
break;
}
return QWidget::eventFilter(ui->modTreeView, keyEvent);
}
bool ModFolderPage::eventFilter(QObject *obj, QEvent *ev)
{
if (ev->type() != QEvent::KeyPress)
{
return QWidget::eventFilter(obj, ev);
}
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
if (obj == ui->modTreeView)
return modListFilter(keyEvent);
return QWidget::eventFilter(obj, ev);
if (ev->type() != QEvent::KeyPress)
{
return QWidget::eventFilter(obj, ev);
}
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
if (obj == ui->modTreeView)
return modListFilter(keyEvent);
return QWidget::eventFilter(obj, ev);
}
void ModFolderPage::on_addModBtn_clicked()
{
auto list = GuiUtil::BrowseForFiles(
m_helpName,
tr("Select %1",
"Select whatever type of files the page contains. Example: 'Loader Mods'")
.arg(m_displayName),
m_fileSelectionFilter.arg(m_displayName), MMC->settings()->get("CentralModsDir").toString(),
this->parentWidget());
if (!list.empty())
{
for (auto filename : list)
{
m_mods->installMod(filename);
}
}
auto list = GuiUtil::BrowseForFiles(
m_helpName,
tr("Select %1",
"Select whatever type of files the page contains. Example: 'Loader Mods'")
.arg(m_displayName),
m_fileSelectionFilter.arg(m_displayName), MMC->settings()->get("CentralModsDir").toString(),
this->parentWidget());
if (!list.empty())
{
for (auto filename : list)
{
m_mods->installMod(filename);
}
}
}
void ModFolderPage::on_enableModBtn_clicked()
{
auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
m_mods->enableMods(selection.indexes(), true);
auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
m_mods->enableMods(selection.indexes(), true);
}
void ModFolderPage::on_disableModBtn_clicked()
{
auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
m_mods->enableMods(selection.indexes(), false);
auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
m_mods->enableMods(selection.indexes(), false);
}
void ModFolderPage::on_rmModBtn_clicked()
{
auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
m_mods->deleteMods(selection.indexes());
auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
m_mods->deleteMods(selection.indexes());
}
void ModFolderPage::on_configFolderBtn_clicked()
{
DesktopServices::openDirectory(m_inst->instanceConfigFolder(), true);
DesktopServices::openDirectory(m_inst->instanceConfigFolder(), true);
}
void ModFolderPage::on_viewModBtn_clicked()
{
DesktopServices::openDirectory(m_mods->dir().absolutePath(), true);
DesktopServices::openDirectory(m_mods->dir().absolutePath(), true);
}
void ModFolderPage::modCurrent(const QModelIndex &current, const QModelIndex &previous)
{
if (!current.isValid())
{
ui->frame->clear();
return;
}
auto sourceCurrent = m_filterModel->mapToSource(current);
int row = sourceCurrent.row();
Mod &m = m_mods->operator[](row);
ui->frame->updateWithMod(m);
if (!current.isValid())
{
ui->frame->clear();
return;
}
auto sourceCurrent = m_filterModel->mapToSource(current);
int row = sourceCurrent.row();
Mod &m = m_mods->operator[](row);
ui->frame->updateWithMod(m);
}

Some files were not shown because too many files have changed in this diff Show More