aboutsummaryrefslogtreecommitdiff
path: root/application/widgets
diff options
context:
space:
mode:
Diffstat (limited to 'application/widgets')
-rw-r--r--application/widgets/Common.cpp27
-rw-r--r--application/widgets/Common.h6
-rw-r--r--application/widgets/IconLabel.cpp43
-rw-r--r--application/widgets/IconLabel.h26
-rw-r--r--application/widgets/LabeledToolButton.cpp86
-rw-r--r--application/widgets/LabeledToolButton.h37
-rw-r--r--application/widgets/LineSeparator.cpp37
-rw-r--r--application/widgets/LineSeparator.h18
-rw-r--r--application/widgets/MCModInfoFrame.cpp111
-rw-r--r--application/widgets/MCModInfoFrame.h46
-rw-r--r--application/widgets/MCModInfoFrame.ui68
-rw-r--r--application/widgets/ModListView.cpp62
-rw-r--r--application/widgets/ModListView.h27
-rw-r--r--application/widgets/PageContainer.cpp210
-rw-r--r--application/widgets/PageContainer.h63
-rw-r--r--application/widgets/PageContainer_p.h123
-rw-r--r--application/widgets/ServerStatus.cpp129
-rw-r--r--application/widgets/ServerStatus.h37
-rw-r--r--application/widgets/VersionListView.cpp147
-rw-r--r--application/widgets/VersionListView.h43
20 files changed, 1346 insertions, 0 deletions
diff --git a/application/widgets/Common.cpp b/application/widgets/Common.cpp
new file mode 100644
index 00000000..9b730d6c
--- /dev/null
+++ b/application/widgets/Common.cpp
@@ -0,0 +1,27 @@
+#include "Common.h"
+
+// Origin: Qt
+QStringList viewItemTextLayout(QTextLayout &textLayout, int lineWidth, qreal &height,
+ qreal &widthUsed)
+{
+ QStringList lines;
+ 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();
+ lines.append(str.mid(line.textStart(), line.textLength()));
+ widthUsed = qMax(widthUsed, line.naturalTextWidth());
+ }
+ textLayout.endLayout();
+ return lines;
+}
diff --git a/application/widgets/Common.h b/application/widgets/Common.h
new file mode 100644
index 00000000..fc46e08f
--- /dev/null
+++ b/application/widgets/Common.h
@@ -0,0 +1,6 @@
+#pragma once
+#include <QStringList>
+#include <QTextLayout>
+
+QStringList viewItemTextLayout(QTextLayout &textLayout, int lineWidth, qreal &height,
+ qreal &widthUsed); \ No newline at end of file
diff --git a/application/widgets/IconLabel.cpp b/application/widgets/IconLabel.cpp
new file mode 100644
index 00000000..86c8a431
--- /dev/null
+++ b/application/widgets/IconLabel.cpp
@@ -0,0 +1,43 @@
+#include "IconLabel.h"
+
+#include <QStyle>
+#include <QStyleOption>
+#include <QLayout>
+#include <QPainter>
+#include <QRect>
+
+IconLabel::IconLabel(QWidget *parent, QIcon icon, QSize size)
+ : QWidget(parent), m_size(size), m_icon(icon)
+{
+ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+}
+
+QSize IconLabel::sizeHint() const
+{
+ return m_size;
+}
+
+void IconLabel::setIcon(QIcon icon)
+{
+ m_icon = icon;
+ update();
+}
+
+void IconLabel::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+ QRect rect = contentsRect();
+ int width = rect.width();
+ int height = rect.height();
+ if(width < height)
+ {
+ rect.setHeight(width);
+ rect.translate(0, (height - width) / 2);
+ }
+ else if (width > height)
+ {
+ rect.setWidth(height);
+ rect.translate((width - height) / 2, 0);
+ }
+ m_icon.paint(&p, rect);
+}
diff --git a/application/widgets/IconLabel.h b/application/widgets/IconLabel.h
new file mode 100644
index 00000000..a2f1eef3
--- /dev/null
+++ b/application/widgets/IconLabel.h
@@ -0,0 +1,26 @@
+#pragma once
+#include <QWidget>
+#include <QIcon>
+
+class QStyleOption;
+
+/**
+ * This is a trivial widget that paints a QIcon of the specified size.
+ */
+class IconLabel : public QWidget
+{
+ Q_OBJECT
+
+public:
+ /// Create a line separator. orientation is the orientation of the line.
+ explicit IconLabel(QWidget *parent, QIcon icon, QSize size);
+
+ virtual QSize sizeHint() const;
+ virtual void paintEvent(QPaintEvent *);
+
+ void setIcon(QIcon icon);
+
+private:
+ QSize m_size;
+ QIcon m_icon;
+};
diff --git a/application/widgets/LabeledToolButton.cpp b/application/widgets/LabeledToolButton.cpp
new file mode 100644
index 00000000..dfdde1bc
--- /dev/null
+++ b/application/widgets/LabeledToolButton.cpp
@@ -0,0 +1,86 @@
+/* Copyright 2013-2015 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <QLabel>
+#include <QVBoxLayout>
+#include <QResizeEvent>
+#include <QStyleOption>
+#include "LabeledToolButton.h"
+#include <QApplication>
+
+/*
+ *
+ * Tool Button with a label on it, instead of the normal text rendering
+ *
+ */
+
+LabeledToolButton::LabeledToolButton(QWidget * parent)
+ : QToolButton(parent)
+ , m_label(new QLabel(this))
+{
+ //QToolButton::setText(" ");
+ m_label->setWordWrap(true);
+ m_label->setMouseTracking(false);
+ m_label->setAlignment(Qt::AlignCenter);
+ m_label->setTextInteractionFlags(Qt::NoTextInteraction);
+ // somehow, this makes word wrap work in the QLabel. yay.
+ m_label->setMinimumWidth(100);
+}
+
+QString LabeledToolButton::text() const
+{
+ return m_label->text();
+}
+
+void LabeledToolButton::setText(const QString & text)
+{
+ m_label->setText(text);
+}
+
+/*!
+ \reimp
+*/
+QSize LabeledToolButton::sizeHint() const
+{
+ /*
+ Q_D(const QToolButton);
+ if (d->sizeHint.isValid())
+ return d->sizeHint;
+ */
+ ensurePolished();
+
+ int w = 0, h = 0;
+ QStyleOptionToolButton opt;
+ initStyleOption(&opt);
+ QSize sz =m_label->sizeHint();
+ w = sz.width();
+ h = sz.height();
+
+ opt.rect.setSize(QSize(w, h)); // PM_MenuButtonIndicator depends on the height
+ if (popupMode() == MenuButtonPopup)
+ w += style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt, this);
+
+ QSize rawSize = style()->sizeFromContents(QStyle::CT_ToolButton, &opt, QSize(w, h), this);
+ QSize sizeHint = rawSize.expandedTo(QApplication::globalStrut());
+ return sizeHint;
+}
+
+
+
+void LabeledToolButton::resizeEvent(QResizeEvent * event)
+{
+ m_label->setGeometry(QRect(4, 4, width()-8, height()-8));
+ QWidget::resizeEvent(event);
+}
diff --git a/application/widgets/LabeledToolButton.h b/application/widgets/LabeledToolButton.h
new file mode 100644
index 00000000..1b74c4ee
--- /dev/null
+++ b/application/widgets/LabeledToolButton.h
@@ -0,0 +1,37 @@
+/* Copyright 2013-2015 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <QPushButton>
+#include <QToolButton>
+
+class QLabel;
+
+class LabeledToolButton : public QToolButton
+{
+ Q_OBJECT
+
+ QLabel * m_label;
+
+public:
+ LabeledToolButton(QWidget * parent = 0);
+
+ QString text() const;
+ void setText(const QString & text);
+ virtual QSize sizeHint() const;
+protected:
+ void resizeEvent(QResizeEvent * event);
+};
diff --git a/application/widgets/LineSeparator.cpp b/application/widgets/LineSeparator.cpp
new file mode 100644
index 00000000..f4ee173d
--- /dev/null
+++ b/application/widgets/LineSeparator.cpp
@@ -0,0 +1,37 @@
+#include "LineSeparator.h"
+
+#include <QStyle>
+#include <QStyleOption>
+#include <QLayout>
+#include <QPainter>
+
+void LineSeparator::initStyleOption(QStyleOption *option) const
+{
+ option->initFrom(this);
+ // in a horizontal layout, the line is vertical (and vice versa)
+ if (m_orientation == Qt::Vertical)
+ option->state |= QStyle::State_Horizontal;
+}
+
+LineSeparator::LineSeparator(QWidget *parent, Qt::Orientation orientation)
+ : QWidget(parent), m_orientation(orientation)
+{
+ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+}
+
+QSize LineSeparator::sizeHint() const
+{
+ QStyleOption opt;
+ initStyleOption(&opt);
+ const int extent =
+ style()->pixelMetric(QStyle::PM_ToolBarSeparatorExtent, &opt, parentWidget());
+ return QSize(extent, extent);
+}
+
+void LineSeparator::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+ QStyleOption opt;
+ initStyleOption(&opt);
+ style()->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator, &opt, &p, parentWidget());
+}
diff --git a/application/widgets/LineSeparator.h b/application/widgets/LineSeparator.h
new file mode 100644
index 00000000..9546e747
--- /dev/null
+++ b/application/widgets/LineSeparator.h
@@ -0,0 +1,18 @@
+#pragma once
+#include <QWidget>
+
+class QStyleOption;
+
+class LineSeparator : public QWidget
+{
+ Q_OBJECT
+
+public:
+ /// Create a line separator. orientation is the orientation of the line.
+ explicit LineSeparator(QWidget *parent, Qt::Orientation orientation = Qt::Horizontal);
+ QSize sizeHint() const;
+ void paintEvent(QPaintEvent *);
+ void initStyleOption(QStyleOption *option) const;
+private:
+ Qt::Orientation m_orientation = Qt::Horizontal;
+};
diff --git a/application/widgets/MCModInfoFrame.cpp b/application/widgets/MCModInfoFrame.cpp
new file mode 100644
index 00000000..2f859ed3
--- /dev/null
+++ b/application/widgets/MCModInfoFrame.cpp
@@ -0,0 +1,111 @@
+/* Copyright 2013-2015 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <QMessageBox>
+#include <QtGui>
+
+#include "MCModInfoFrame.h"
+#include "ui_MCModInfoFrame.h"
+#include "dialogs/CustomMessageBox.h"
+
+void MCModInfoFrame::updateWithMod(Mod &m)
+{
+ if(m.type() == m.MOD_FOLDER)
+ {
+ clear();
+ return;
+ }
+
+ QString text = "";
+ QString name = "";
+ if(m.name().isEmpty()) name = m.mmc_id();
+ else name = m.name();
+
+ if(m.homeurl().isEmpty()) text = name;
+ else text = "<a href=\"" + m.homeurl() + "\">" + name + "</a>";
+ if(!m.authors().isEmpty()) text += " by " + m.authors();
+
+ setModText(text);
+
+ if(m.description().isEmpty())
+ {
+ setModDescription(tr("No description provided in mcmod.info"));
+ }
+ else
+ {
+ setModDescription(m.description());
+ }
+}
+
+void MCModInfoFrame::clear()
+{
+ setModText(tr("Select a mod to view title and authors..."));
+ setModDescription(tr("Select a mod to view description..."));
+}
+
+MCModInfoFrame::MCModInfoFrame(QWidget *parent) :
+ QFrame(parent),
+ ui(new Ui::MCModInfoFrame)
+{
+ ui->setupUi(this);
+}
+
+MCModInfoFrame::~MCModInfoFrame()
+{
+ delete ui;
+}
+
+void MCModInfoFrame::setModText(QString text)
+{
+ ui->label_ModText->setText(text);
+}
+
+void MCModInfoFrame::setModDescription(QString text)
+{
+ ui->label_ModDescription->setToolTip("");
+ QString intermediatetext = text.trimmed();
+ bool prev(false);
+ QChar rem('\n');
+ QString finaltext;
+ finaltext.reserve(intermediatetext.size());
+ foreach(const QChar& c, intermediatetext)
+ {
+ if(c == rem && prev){
+ continue;
+ }
+ prev = c == rem;
+ finaltext += c;
+ }
+ QString labeltext;
+ labeltext.reserve(300);
+ if(finaltext.length() > 290)
+ {
+ ui->label_ModDescription->setOpenExternalLinks(false);
+ ui->label_ModDescription->setTextFormat(Qt::TextFormat::RichText);
+ desc = text;
+ labeltext.append("<html><body>" + finaltext.left(287) + "<a href=\"#mod_desc\">...</a></body></html>");
+ QObject::connect(ui->label_ModDescription, &QLabel::linkActivated, this, &MCModInfoFrame::modDescEllipsisHandler);
+ }
+ else
+ {
+ ui->label_ModDescription->setTextFormat(Qt::TextFormat::PlainText);
+ labeltext.append(finaltext);
+ }
+ ui->label_ModDescription->setText(labeltext);
+}
+void MCModInfoFrame::modDescEllipsisHandler(const QString &link)
+{
+ CustomMessageBox::selectable(this, tr(""), desc)->show();
+}
diff --git a/application/widgets/MCModInfoFrame.h b/application/widgets/MCModInfoFrame.h
new file mode 100644
index 00000000..3f75279c
--- /dev/null
+++ b/application/widgets/MCModInfoFrame.h
@@ -0,0 +1,46 @@
+/* Copyright 2013-2015 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <QFrame>
+#include "minecraft/Mod.h"
+
+namespace Ui
+{
+class MCModInfoFrame;
+}
+
+class MCModInfoFrame : public QFrame
+{
+ Q_OBJECT
+
+public:
+ explicit MCModInfoFrame(QWidget *parent = 0);
+ ~MCModInfoFrame();
+
+ void setModText(QString text);
+ void setModDescription(QString text);
+
+ void updateWithMod(Mod &m);
+ void clear();
+
+public slots:
+ void modDescEllipsisHandler(const QString& link );
+
+private:
+ Ui::MCModInfoFrame *ui;
+ QString desc;
+};
diff --git a/application/widgets/MCModInfoFrame.ui b/application/widgets/MCModInfoFrame.ui
new file mode 100644
index 00000000..60e0a65c
--- /dev/null
+++ b/application/widgets/MCModInfoFrame.ui
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MCModInfoFrame</class>
+ <widget class="QFrame" name="MCModInfoFrame">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>527</width>
+ <height>113</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>120</height>
+ </size>
+ </property>
+ <property name="windowTitle">
+ <string>Frame</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QLabel" name="label_ModText">
+ <property name="text">
+ <string>Select a mod to view title and authors...</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::RichText</enum>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_ModDescription">
+ <property name="text">
+ <string>Select a mod to view description...</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/application/widgets/ModListView.cpp b/application/widgets/ModListView.cpp
new file mode 100644
index 00000000..aa16ad05
--- /dev/null
+++ b/application/widgets/ModListView.cpp
@@ -0,0 +1,62 @@
+/* Copyright 2013-2015 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ModListView.h"
+#include <QHeaderView>
+#include <QMouseEvent>
+#include <QPainter>
+#include <QDrag>
+#include <QRect>
+
+ModListView::ModListView ( QWidget* parent )
+ :QTreeView ( parent )
+{
+ setAllColumnsShowFocus ( true );
+ setExpandsOnDoubleClick ( false );
+ setRootIsDecorated ( false );
+ setSortingEnabled ( false );
+ setAlternatingRowColors ( true );
+ setSelectionMode ( QAbstractItemView::ContiguousSelection );
+ setHeaderHidden ( false );
+ setSelectionBehavior(QAbstractItemView::SelectRows);
+ setVerticalScrollBarPolicy ( Qt::ScrollBarAlwaysOn );
+ setHorizontalScrollBarPolicy ( Qt::ScrollBarAsNeeded );
+ setDropIndicatorShown(true);
+ setDragEnabled(true);
+ setDragDropMode(QAbstractItemView::DropOnly);
+ viewport()->setAcceptDrops(true);
+}
+
+void ModListView::setModel ( QAbstractItemModel* model )
+{
+ QTreeView::setModel ( model );
+ auto head = header();
+ head->setStretchLastSection(false);
+ // HACK: this is true for the checkbox column of mod lists
+ auto string = model->headerData(0,head->orientation()).toString();
+ if(!string.size())
+ {
+ head->setSectionResizeMode(0, QHeaderView::ResizeToContents);
+ head->setSectionResizeMode(1, QHeaderView::Stretch);
+ for(int i = 2; i < head->count(); i++)
+ head->setSectionResizeMode(i, QHeaderView::ResizeToContents);
+ }
+ else
+ {
+ head->setSectionResizeMode(0, QHeaderView::Stretch);
+ for(int i = 1; i < head->count(); i++)
+ head->setSectionResizeMode(i, QHeaderView::ResizeToContents);
+ }
+}
diff --git a/application/widgets/ModListView.h b/application/widgets/ModListView.h
new file mode 100644
index 00000000..43de9811
--- /dev/null
+++ b/application/widgets/ModListView.h
@@ -0,0 +1,27 @@
+/* Copyright 2013-2015 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <QTreeView>
+
+class Mod;
+
+class ModListView: public QTreeView
+{
+ Q_OBJECT
+public:
+ explicit ModListView ( QWidget* parent = 0 );
+ virtual void setModel ( QAbstractItemModel* model );
+};
diff --git a/application/widgets/PageContainer.cpp b/application/widgets/PageContainer.cpp
new file mode 100644
index 00000000..679039a7
--- /dev/null
+++ b/application/widgets/PageContainer.cpp
@@ -0,0 +1,210 @@
+/* Copyright 2013-2015 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PageContainer.h"
+
+#include <QStackedLayout>
+#include <QPushButton>
+#include <QSortFilterProxyModel>
+#include <QUrl>
+#include <QStyledItemDelegate>
+#include <QListView>
+#include <QLineEdit>
+#include <QLabel>
+#include <QDialogButtonBox>
+#include <QGridLayout>
+#include <QDesktopServices>
+
+#include "MultiMC.h"
+#include "settings/SettingsObject.h"
+#include "widgets/IconLabel.h"
+#include "Platform.h"
+#include "PageContainer_p.h"
+#include <MultiMC.h>
+
+class PageEntryFilterModel : public QSortFilterProxyModel
+{
+public:
+ explicit PageEntryFilterModel(QObject *parent = 0) : QSortFilterProxyModel(parent)
+ {
+ }
+
+protected:
+ bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
+ {
+ const QString pattern = filterRegExp().pattern();
+ const auto model = static_cast<PageModel *>(sourceModel());
+ const auto page = model->pages().at(sourceRow);
+ if (!page->shouldDisplay())
+ return false;
+ // Regular contents check, then check page-filter.
+ return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
+ }
+};
+
+PageContainer::PageContainer(BasePageProviderPtr pageProvider, QString defaultId,
+ QWidget *parent)
+ : QWidget(parent)
+{
+ createUI();
+ m_model = new PageModel(this);
+ m_proxyModel = new PageEntryFilterModel(this);
+ int firstIndex = -1;
+ int counter = 0;
+ auto pages = pageProvider->getPages();
+ for (auto page : pages)
+ {
+ page->stackIndex = m_pageStack->addWidget(dynamic_cast<QWidget *>(page));
+ page->listIndex = counter;
+ counter++;
+ if (firstIndex == -1)
+ {
+ firstIndex = page->stackIndex;
+ }
+ }
+ m_model->setPages(pages);
+
+ m_proxyModel->setSourceModel(m_model);
+ m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
+
+ m_pageList->setIconSize(QSize(pageIconSize, pageIconSize));
+ m_pageList->setSelectionMode(QAbstractItemView::SingleSelection);
+ m_pageList->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
+ m_pageList->setModel(m_proxyModel);
+ connect(m_pageList->selectionModel(), SIGNAL(currentRowChanged(QModelIndex, QModelIndex)),
+ this, SLOT(currentChanged(QModelIndex)));
+ m_pageStack->setStackingMode(QStackedLayout::StackOne);
+ m_pageList->setFocus();
+ // now find what we want to have selected...
+ auto page = m_model->findPageEntryById(defaultId);
+ QModelIndex index;
+ if (page)
+ {
+ index = m_proxyModel->mapFromSource(m_model->index(page->listIndex));
+ }
+ else
+ {
+ index = m_proxyModel->index(0, 0);
+ }
+ if (index.isValid())
+ m_pageList->setCurrentIndex(index);
+}
+
+void PageContainer::createUI()
+{
+ m_pageStack = new QStackedLayout;
+ m_filter = new QLineEdit;
+ m_pageList = new PageView;
+ m_header = new QLabel();
+ m_iconHeader = new IconLabel(this, QIcon(), QSize(24, 24));
+
+ QFont headerLabelFont = m_header->font();
+ headerLabelFont.setBold(true);
+ const int pointSize = headerLabelFont.pointSize();
+ if (pointSize > 0)
+ headerLabelFont.setPointSize(pointSize + 2);
+ m_header->setFont(headerLabelFont);
+
+ QHBoxLayout *headerHLayout = new QHBoxLayout;
+ const int leftMargin = MMC->style()->pixelMetric(QStyle::PM_LayoutLeftMargin);
+ headerHLayout->addSpacerItem(
+ new QSpacerItem(leftMargin, 0, QSizePolicy::Fixed, QSizePolicy::Ignored));
+ headerHLayout->addWidget(m_header);
+ headerHLayout->addSpacerItem(
+ new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored));
+ headerHLayout->addWidget(m_iconHeader);
+ const int rightMargin = MMC->style()->pixelMetric(QStyle::PM_LayoutRightMargin);
+ headerHLayout->addSpacerItem(
+ new QSpacerItem(rightMargin, 0, QSizePolicy::Fixed, QSizePolicy::Ignored));
+
+ m_pageStack->setMargin(0);
+ m_pageStack->addWidget(new QWidget(this));
+
+ m_layout = new QGridLayout;
+ m_layout->addLayout(headerHLayout, 0, 1, 1, 1);
+ m_layout->addWidget(m_pageList, 0, 0, 2, 1);
+ m_layout->addLayout(m_pageStack, 1, 1, 1, 1);
+ m_layout->setColumnStretch(1, 4);
+ setLayout(m_layout);
+}
+
+void PageContainer::addButtons(QWidget *buttons)
+{
+ m_layout->addWidget(buttons, 2, 0, 1, 2);
+}
+
+void PageContainer::addButtons(QLayout *buttons)
+{
+ m_layout->addLayout(buttons, 2, 0, 1, 2);
+}
+
+void PageContainer::showPage(int row)
+{
+ if (m_currentPage)
+ {
+ m_currentPage->closed();
+ }
+ if (row != -1)
+ {
+ m_currentPage = m_model->pages().at(row);
+ }
+ else
+ {
+ m_currentPage = nullptr;
+ }
+ if (m_currentPage)
+ {
+ m_pageStack->setCurrentIndex(m_currentPage->stackIndex);
+ m_header->setText(m_currentPage->displayName());
+ m_iconHeader->setIcon(m_currentPage->icon());
+ m_currentPage->opened();
+ }
+ else
+ {
+ m_pageStack->setCurrentIndex(0);
+ m_header->setText(QString());
+ m_iconHeader->setIcon(MMC->getThemedIcon("bug"));
+ }
+}
+
+void PageContainer::help()
+{
+ if (m_currentPage)
+ {
+ QString pageId = m_currentPage->helpPage();
+ if (pageId.isEmpty())
+ return;
+ QDesktopServices::openUrl(QUrl("https://github.com/MultiMC/MultiMC5/wiki/" + pageId));
+ }
+}
+
+void PageContainer::currentChanged(const QModelIndex &current)
+{
+ showPage(current.isValid() ? m_proxyModel->mapToSource(current).row() : -1);
+}
+
+bool PageContainer::requestClose(QCloseEvent *event)
+{
+ for (auto page : m_model->pages())
+ {
+ if (!page->apply())
+ return false;
+ }
+ if (m_currentPage)
+ {
+ m_currentPage->closed();
+ }
+ return true;
+}
diff --git a/application/widgets/PageContainer.h b/application/widgets/PageContainer.h
new file mode 100644
index 00000000..3027af36
--- /dev/null
+++ b/application/widgets/PageContainer.h
@@ -0,0 +1,63 @@
+/* Copyright 2013-2015 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <QWidget>
+#include <QModelIndex>
+
+#include "pages/BasePageProvider.h"
+
+class QLayout;
+class IconLabel;
+class QSortFilterProxyModel;
+class PageModel;
+class QLabel;
+class QListView;
+class QLineEdit;
+class QStackedLayout;
+class QGridLayout;
+
+class PageContainer : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit PageContainer(BasePageProviderPtr pageProvider, QString defaultId = QString(),
+ QWidget *parent = 0);
+ virtual ~PageContainer() {}
+
+ void addButtons(QWidget * buttons);
+ void addButtons(QLayout * buttons);
+ bool requestClose(QCloseEvent *event);
+
+private:
+ void createUI();
+private
+slots:
+ void currentChanged(const QModelIndex &current);
+ void showPage(int row);
+ void help();
+
+private:
+ BasePage * m_currentPage = 0;
+ QSortFilterProxyModel *m_proxyModel;
+ PageModel *m_model;
+ QStackedLayout *m_pageStack;
+ QLineEdit *m_filter;
+ QListView *m_pageList;
+ QLabel *m_header;
+ IconLabel *m_iconHeader;
+ QGridLayout *m_layout;
+};
diff --git a/application/widgets/PageContainer_p.h b/application/widgets/PageContainer_p.h
new file mode 100644
index 00000000..4c720e4c
--- /dev/null
+++ b/application/widgets/PageContainer_p.h
@@ -0,0 +1,123 @@
+/* Copyright 2013-2015 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <QListView>
+#include <QStyledItemDelegate>
+#include <QEvent>
+#include <QScrollBar>
+
+class BasePage;
+const int pageIconSize = 24;
+
+class PageViewDelegate : public QStyledItemDelegate
+{
+public:
+ PageViewDelegate(QObject *parent) : QStyledItemDelegate(parent)
+ {
+ }
+ QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) con