Separate page dialog into a page container and a dialog.
This commit is contained in:
		
							
								
								
									
										190
									
								
								gui/widgets/PageContainer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								gui/widgets/PageContainer.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,190 @@ | ||||
| /* Copyright 2014 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 "gui/Platform.h" | ||||
| #include <QStackedLayout> | ||||
| #include <QPushButton> | ||||
| #include <QSortFilterProxyModel> | ||||
| #include <QUrl> | ||||
| #include "MultiMC.h" | ||||
| #include <QStyledItemDelegate> | ||||
| #include <QListView> | ||||
| #include <QLineEdit> | ||||
| #include <QLabel> | ||||
| #include <QDialogButtonBox> | ||||
| #include <QGridLayout> | ||||
| #include <QDesktopServices> | ||||
| #include <settingsobject.h> | ||||
|  | ||||
| #include "PageContainer_p.h" | ||||
| #include <gui/widgets/IconLabel.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); | ||||
|  | ||||
| 	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::showPage(int row) | ||||
| { | ||||
| 	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(QIcon::fromTheme("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 ¤t) | ||||
| { | ||||
| 	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; | ||||
| 	} | ||||
| 	return true; | ||||
| } | ||||
							
								
								
									
										59
									
								
								gui/widgets/PageContainer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								gui/widgets/PageContainer.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | ||||
| /* Copyright 2014 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 <gui/pages/BasePageProvider.h> | ||||
|  | ||||
| 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); | ||||
| 	bool requestClose(QCloseEvent *event); | ||||
|  | ||||
| private: | ||||
| 	void createUI(); | ||||
| private | ||||
| slots: | ||||
| 	void currentChanged(const QModelIndex ¤t); | ||||
| 	void showPage(int row); | ||||
| 	void help(); | ||||
|  | ||||
| private: | ||||
| 	BasePage * m_currentPage; | ||||
| 	QSortFilterProxyModel *m_proxyModel; | ||||
| 	PageModel *m_model; | ||||
| 	QStackedLayout *m_pageStack; | ||||
| 	QLineEdit *m_filter; | ||||
| 	QListView *m_pageList; | ||||
| 	QLabel *m_header; | ||||
| 	IconLabel *m_iconHeader; | ||||
| 	QGridLayout *m_layout; | ||||
| }; | ||||
							
								
								
									
										106
									
								
								gui/widgets/PageContainer_p.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								gui/widgets/PageContainer_p.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,106 @@ | ||||
| #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) const | ||||
| 	{ | ||||
| 		QSize size = QStyledItemDelegate::sizeHint(option, index); | ||||
| 		size.setHeight(qMax(size.height(), 32)); | ||||
| 		return size; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| class PageModel : public QAbstractListModel | ||||
| { | ||||
| public: | ||||
| 	PageModel(QObject *parent = 0) : QAbstractListModel(parent) | ||||
| 	{ | ||||
| 		QPixmap empty(pageIconSize, pageIconSize); | ||||
| 		empty.fill(Qt::transparent); | ||||
| 		m_emptyIcon = QIcon(empty); | ||||
| 	} | ||||
| 	virtual ~PageModel() {}; | ||||
|  | ||||
| 	int rowCount(const QModelIndex &parent = QModelIndex()) const | ||||
| 	{ | ||||
| 		return parent.isValid() ? 0 : m_pages.size(); | ||||
| 	} | ||||
| 	QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const | ||||
| 	{ | ||||
| 		switch (role) | ||||
| 		{ | ||||
| 		case Qt::DisplayRole: | ||||
| 			return m_pages.at(index.row())->displayName(); | ||||
| 		case Qt::DecorationRole: | ||||
| 		{ | ||||
| 			QIcon icon = m_pages.at(index.row())->icon(); | ||||
| 			if (icon.isNull()) | ||||
| 				icon = m_emptyIcon; | ||||
| 			return icon; | ||||
| 		} | ||||
| 		} | ||||
| 		return QVariant(); | ||||
| 	} | ||||
|  | ||||
| 	void setPages(const QList<BasePage *> &pages) | ||||
| 	{ | ||||
| 		beginResetModel(); | ||||
| 		m_pages = pages; | ||||
| 		endResetModel(); | ||||
| 	} | ||||
| 	const QList<BasePage *> &pages() const | ||||
| 	{ | ||||
| 		return m_pages; | ||||
| 	} | ||||
|  | ||||
| 	BasePage * findPageEntryById(QString id) | ||||
| 	{ | ||||
| 		for(auto page: m_pages) | ||||
| 		{ | ||||
| 			if (page->id() == id) | ||||
| 				return page; | ||||
| 		} | ||||
| 		return nullptr; | ||||
| 	} | ||||
|  | ||||
| 	QList<BasePage *> m_pages; | ||||
| 	QIcon m_emptyIcon; | ||||
| }; | ||||
|  | ||||
| class PageView : public QListView | ||||
| { | ||||
| public: | ||||
| 	PageView(QWidget *parent = 0) : QListView(parent) | ||||
| 	{ | ||||
| 		setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding); | ||||
| 		setItemDelegate(new PageViewDelegate(this)); | ||||
| 		setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); | ||||
| 	} | ||||
|  | ||||
| 	virtual QSize sizeHint() const | ||||
| 	{ | ||||
| 		int width = sizeHintForColumn(0) + frameWidth() * 2 + 5; | ||||
| 		if (verticalScrollBar()->isVisible()) | ||||
| 			width += verticalScrollBar()->width(); | ||||
| 		return QSize(width, 100); | ||||
| 	} | ||||
|  | ||||
| 	virtual bool eventFilter(QObject *obj, QEvent *event) | ||||
| 	{ | ||||
| 		if (obj == verticalScrollBar() && | ||||
| 			(event->type() == QEvent::Show || event->type() == QEvent::Hide)) | ||||
| 			updateGeometry(); | ||||
| 		return QListView::eventFilter(obj, event); | ||||
| 	} | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user