#include "toolbox.h" #include "style/styledbar.h" #include #include #include #include #include #include #include ToolBox::ToolBox(bool pagesOpenOnInsertion, QWidget *parent, Qt::WindowFlags f) : QFrame(parent, f) , mLayout(0) , mLargestMinimalInputWidth(0) , mDefaultPagesOpen(pagesOpenOnInsertion) { mLayout = new QVBoxLayout(); mLayout->setAlignment(Qt::AlignTop); mLayout->setSpacing(0); mLayout->setMargin(0); mLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::MinimumExpanding)); setLayout(mLayout); } ToolBox::~ToolBox() { } bool ToolBox::addPage(ToolBoxPage *page) { return insertPage(-1, page); } bool ToolBox::insertPage(int index, ToolBoxPage *page) { if (index == -1) index = layout()->count() - 1; //As the spacer is the layout's last item if (index < 0 || index > layout()->count() - 1) return false; page->setStyle(style()); page->mHeaderBar->setStyle(style()); page->mButton->setStyle(style()); mLayout->insertWidget(index, page); mPages.insert(index, page); connect(page, SIGNAL(minimalInputWidthChanged(int)), SLOT(processPageMinimalInputWidth(int))); page->init(); if (mDefaultPagesOpen && page->isHidden()) page->showContent(true); return true; } bool ToolBox::insertPageIntoLayout(int index, ToolBoxPage *page) { if (index == -1) index = layout()->count() - 1; //As the spacer is the layout's last item if (index < 0 || index > layout()->count() - 1) return false; mLayout->insertWidget(index, page); return true; } bool ToolBox::removePageFromLayout(ToolBoxPage *page) { int pageIndex = mLayout->indexOf(page); if (pageIndex == -1) return false; mLayout->removeWidget(page); return true; } void ToolBox::filtersChanged(const QString &filters) { QStringList filterList = filters.split(' ', QString::SkipEmptyParts); int i = 0; foreach(ToolBoxPage *page, mPages) { int itemCount = 0; itemCount = page->filtersChanged(filterList); int pageIndex = mLayout->indexOf(page); // Increase i a) if the layout already contains the page and it is not removed // or b) if the page is added. Thereby we keep the order of the toolboxpages. if (pageIndex != -1) { if (itemCount == 0) { removePageFromLayout(page); page->setVisible(false); } else { i++; } } else if (itemCount > 0 && pageIndex == -1) { insertPageIntoLayout(i, page); page->setVisible(true); i++; } } } void ToolBox::processPageMinimalInputWidth(int newWidth) { if (newWidth > mLargestMinimalInputWidth) { mLargestMinimalInputWidth = newWidth; foreach (ToolBoxPage *page, mPages) page->setFixedInputWidth(newWidth); } } ToolBoxPage::ToolBoxPage(QWidget *parent) : QFrame(parent) , mButton(0) , mPage(0) , mInnerLayout(0) , mHeaderLayout(0) , mAdvancedMode(false) , mExplicitOpen(false) , mMinimalInputWidth(0) { setFrameShadow(QFrame::Raised); QVBoxLayout *vLayout = new QVBoxLayout(); vLayout->setMargin(0); setLayout(vLayout); mButton = new QToolButton(this); mButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); mButton->setArrowType(Qt::RightArrow); mButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); connect(mButton, SIGNAL(clicked()), SLOT(toggleOpenExplicitly())); mHeaderLayout = new QHBoxLayout(); mHeaderLayout->setSpacing(0); mHeaderLayout->setContentsMargins(0,0,0,0); mHeaderLayout->addWidget(mButton); mHeaderBar = new StyledBar; mHeaderBar->setLightColored(true); mHeaderBar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); mHeaderBar->setLayout(mHeaderLayout); vLayout->addWidget(mHeaderBar); mPage = new QWidget(this); mInnerLayout = new QFormLayout(); mInnerLayout->setVerticalSpacing(9); mInnerLayout->setRowWrapPolicy(QFormLayout::WrapLongRows); mInnerLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); mInnerLayout->setLabelAlignment(Qt::AlignLeft); mPage->setLayout(mInnerLayout); mPage->hide(); } ToolBoxPage::~ToolBoxPage() { } void ToolBoxPage::setOptions(const QList &options) { // ### TODO: Make this work once it's already in a toolbox. mOptions = options; } void ToolBoxPage::setTitle(const QString &title) { mButton->setText(title); } void ToolBoxPage::init() { //Initially add all the "basic" items to the page, even if nothing is visible int foundItems = findUnfilteredItems(); //If the number of unfiltered items is smaller than the one of the given options, //there have to be advanced items if (foundItems < mOptions.count()) addAdvancedButtonToHeader(); emit minimalInputWidthChanged(mMinimalInputWidth); } void ToolBoxPage::showContent(bool show) { QVBoxLayout *vLayout = qobject_cast(layout()); if (show) { if (vLayout->indexOf(mPage) == -1) vLayout->addWidget(mPage); mPage->show(); mButton->setArrowType(Qt::DownArrow); } else { if (vLayout->indexOf(mPage) != -1) vLayout->removeWidget(mPage); mPage->hide(); mButton->setArrowType(Qt::RightArrow); } } void ToolBoxPage::toggleOpenExplicitly() { if (mPage->isHidden()) mExplicitOpen = true; else mExplicitOpen = false; showContent(mExplicitOpen); } void ToolBoxPage::setAdvanced(bool advanced) { mAdvancedMode = advanced; if (mLastFilters.isEmpty()) { findUnfilteredItems(); showContent(true); } } void ToolBoxPage::addItem(OptionsItem *item) { insertItem(-1, item); } void ToolBoxPage::insertItem(int row, OptionsItem *item) { if (row == -1) row = mInnerLayout->count(); if (item->type() == OptionsItem::FullWidthType) mInnerLayout->insertRow(row, item->inputWidget()); else { item->inputLayout()->setParent(0); mInnerLayout->insertRow(row, item->label(), item->inputLayout()); } item->setVisible(true); if (item->type() == OptionsItem::AdvancedType) { connect(item, SIGNAL(toggleAdvanced(OptionsItem *)), this, SLOT(advancedToggled(OptionsItem *))); } int width = item->inputWidget()->sizeHint().width(); if (item->type() != OptionsItem::FullWidthType && width > mMinimalInputWidth) mMinimalInputWidth = width; } void ToolBoxPage::addItemsAndSpacer(QList items) { foreach (OptionsItem *item, items) addItem(item); if (mInnerLayout->count() > 0) mInnerLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum)); } void ToolBoxPage::setFixedInputWidth(int newInputWidth) { // force size foreach (OptionsItem *item, mOptions) { if (item->type() != OptionsItem::FullWidthType) item->inputWidget()->setFixedWidth(newInputWidth); } } void ToolBoxPage::addAdvancedButtonToHeader() { if (mHeaderLayout->count() == 1) { QToolButton *advancedButton = new QToolButton(); advancedButton->setCheckable(true); advancedButton->setIcon(QIcon(":/style/images/advanced.png")); mHeaderLayout->addWidget(advancedButton); connect(advancedButton, SIGNAL(toggled(bool)), SLOT(setAdvanced(bool))); } } unsigned int ToolBoxPage::filtersChanged(const QStringList &filters) { mLastFilters = filters; int foundItems = 0; if (filters.length() == 0) { foundItems = findUnfilteredItems(); showContent(mExplicitOpen); } else { foundItems = findFilteredItems(filters); if (foundItems > 0) showContent(true); } return foundItems; } bool ToolBoxPage::filterItem(const QStringList &filters, OptionsItem *option) { // If the option has an advanced page and this page is opened, close it before applying the filter if (option->type() == OptionsItem::AdvancedType && !option->advancedPage()->inputWidget()->isHidden()) advancedToggled(option); if (option->isExplicitlyHidden()) return false; option->setVisible(false); foreach (const QString &filter, filters) { if (option->matchTag(filter)) { addItem(option); return true; } } return false; } unsigned int ToolBoxPage::findFilteredItems(const QStringList &filters) { // remove current options while (mInnerLayout->count()) mInnerLayout->takeAt(0); // add matching QList shownItems; foreach(OptionsItem *item, mOptions) { if (item->type() == OptionsItem::AdvancedType) { if (!item->advancedPage()->inputWidget()->isHidden()) advancedToggled(item); disconnect(item, SIGNAL(toggleAdvanced(OptionsItem *)), this, SLOT(advancedToggled(OptionsItem *))); } if (filterItem(filters, item)) { shownItems += item; } } addItemsAndSpacer(shownItems); return shownItems.count(); } unsigned int ToolBoxPage::findUnfilteredItems() { //If a filter is applied, just ignore the call if (mLastFilters.length() > 0) return 0; while (mInnerLayout->count()) mInnerLayout->takeAt(0); QList shownItems; foreach(OptionsItem *item, mOptions) { if (item && item->type() == OptionsItem::AdvancedType) { if (!item->advancedPage()->inputWidget()->isHidden()) advancedToggled(item); disconnect(item, SIGNAL(toggleAdvanced(OptionsItem *)), this, SLOT(advancedToggled(OptionsItem *))); } if ((!mAdvancedMode && item->isAdvanced()) || item->isExplicitlyHidden()) { item->setVisible(false); continue; } shownItems += item; } addItemsAndSpacer(shownItems); return shownItems.count(); } void ToolBoxPage::advancedToggled(OptionsItem *item) { QAbstractButton *clickedButton = qobject_cast(item->inputWidget()); if (clickedButton->text() == tr("Show")) clickedButton->setText(tr("Hide")); else clickedButton->setText(tr("Show")); QWidget *advancedInput = item->advancedPage()->inputWidget(); if (!advancedInput->isHidden()) { mInnerLayout->removeWidget(advancedInput); advancedInput->hide(); } else { int row = 0; mInnerLayout->getLayoutPosition(item->inputLayout(), &row, 0); ++row; mInnerLayout->insertRow(row, advancedInput); advancedInput->show(); } }