Commit deb43b4c authored by Eike Ziller's avatar Eike Ziller

Preferences: Add default implementation for filtering

The default "matches" method now takes the widget and looks for all
child labels, checkboxes, push buttons and group boxes.
Because of that, the former "createWidget" method
can be called multiple times without creating a new widget
(-->widget()), and the "finished" method must ensure that the created
widget gets deleted, since not all widgets that were created are added
to the UI anymore.

Change-Id: Ia231c7c78dd8819146668e6447d36d22e7836904
Reviewed-by: default avatarEike Ziller <eike.ziller@digia.com>
parent ea1a9248
......@@ -52,16 +52,10 @@ AndroidSettingsPage::AndroidSettingsPage(QObject *parent)
setCategoryIcon(QLatin1String(Constants::ANDROID_SETTINGS_CATEGORY_ICON));
}
bool AndroidSettingsPage::matches(const QString &searchKeyWord) const
QWidget *AndroidSettingsPage::widget()
{
return m_keywords.contains(searchKeyWord, Qt::CaseInsensitive);
}
QWidget *AndroidSettingsPage::createPage(QWidget *parent)
{
m_widget = new AndroidSettingsWidget(parent);
if (m_keywords.isEmpty())
m_keywords = m_widget->searchKeywords();
if (!m_widget)
m_widget = new AndroidSettingsWidget;
return m_widget;
}
......@@ -97,6 +91,7 @@ void AndroidSettingsPage::apply()
void AndroidSettingsPage::finish()
{
delete m_widget;
}
} // namespace Internal
......
......@@ -32,6 +32,8 @@
#include <coreplugin/dialogs/ioptionspage.h>
#include <QPointer>
namespace Android {
namespace Internal {
......@@ -44,14 +46,12 @@ class AndroidSettingsPage : public Core::IOptionsPage
public:
explicit AndroidSettingsPage(QObject *parent = 0);
bool matches(const QString &searchKeyWord) const;
QWidget *createPage(QWidget *parent);
QWidget *widget();
void apply();
void finish();
private:
QString m_keywords;
AndroidSettingsWidget *m_widget;
QPointer<AndroidSettingsWidget> m_widget;
};
} // namespace Internal
......
......@@ -129,24 +129,6 @@ AndroidSettingsWidget::~AndroidSettingsWidget()
delete m_ui;
}
QString AndroidSettingsWidget::searchKeywords() const
{
QString rc;
QTextStream(&rc) << m_ui->SDKLocationLabel->text()
<< ' ' << m_ui->SDKLocationLineEdit->text()
<< ' ' << m_ui->NDKLocationLabel->text()
<< ' ' << m_ui->NDKLocationLineEdit->text()
<< ' ' << m_ui->AntLocationLabel->text()
<< ' ' << m_ui->AntLocationLineEdit->text()
<< ' ' << m_ui->OpenJDKLocationLabel->text()
<< ' ' << m_ui->OpenJDKLocationLineEdit->text()
<< ' ' << m_ui->AVDManagerLabel->text()
<< ' ' << m_ui->DataPartitionSizeLable->text()
<< ' ' << m_ui->DataPartitionSizeSpinBox->text();
rc.remove(QLatin1Char('&'));
return rc;
}
void AndroidSettingsWidget::initGui()
{
m_ui->setupUi(this);
......
......@@ -66,11 +66,10 @@ class AndroidSettingsWidget : public QWidget
Q_OBJECT
public:
// Todo: This would be so much simpler if it just used Utils::PathChooser!!!
AndroidSettingsWidget(QWidget *parent);
AndroidSettingsWidget(QWidget *parent = 0);
~AndroidSettingsWidget();
void saveSettings(bool saveNow = false);
QString searchKeywords() const;
private slots:
void sdkLocationEditingFinished();
......
......@@ -67,37 +67,17 @@ void OptionsPageWidget::setSettings(const BazaarSettings &s)
m_ui.timeout->setValue(s.intValue(BazaarSettings::timeoutKey));
}
QString OptionsPageWidget::searchKeywords() const
{
QString rc;
QLatin1Char sep(' ');
QTextStream(&rc)
<< sep << m_ui.configGroupBox->title()
<< sep << m_ui.commandLabel->text()
<< sep << m_ui.userGroupBox->title()
<< sep << m_ui.defaultUsernameLabel->text()
<< sep << m_ui.defaultEmailLabel->text()
<< sep << m_ui.miscGroupBox->title()
<< sep << m_ui.showLogEntriesLabel->text()
<< sep << m_ui.timeoutSecondsLabel->text()
;
rc.remove(QLatin1Char('&'));
return rc;
}
OptionsPage::OptionsPage()
{
setId(VcsBase::Constants::VCS_ID_BAZAAR);
setDisplayName(tr("Bazaar"));
}
QWidget *OptionsPage::createPage(QWidget *parent)
QWidget *OptionsPage::widget()
{
if (!m_optionsPageWidget)
m_optionsPageWidget = new OptionsPageWidget(parent);
m_optionsPageWidget = new OptionsPageWidget;
m_optionsPageWidget->setSettings(BazaarPlugin::instance()->settings());
if (m_searchKeywords.isEmpty())
m_searchKeywords = m_optionsPageWidget->searchKeywords();
return m_optionsPageWidget;
}
......@@ -114,8 +94,3 @@ void OptionsPage::apply()
emit settingsChanged();
}
}
bool OptionsPage::matches(const QString &s) const
{
return m_searchKeywords.contains(s, Qt::CaseInsensitive);
}
......@@ -50,7 +50,6 @@ public:
BazaarSettings settings() const;
void setSettings(const BazaarSettings &s);
QString searchKeywords() const;
private:
Ui::OptionsPage m_ui;
......@@ -64,16 +63,14 @@ class OptionsPage : public VcsBase::VcsBaseOptionsPage
public:
OptionsPage();
QWidget *createPage(QWidget *parent);
QWidget *widget();
void apply();
void finish() { }
bool matches(const QString &s) const;
signals:
void settingsChanged();
private:
QString m_searchKeywords;
QPointer<OptionsPageWidget> m_optionsPageWidget;
};
......
......@@ -107,25 +107,6 @@ void SettingsPageWidget::setSettings(const ClearCaseSettings &s)
m_ui.indexOnlyVOBsEdit->setText(s.indexOnlyVOBs);
}
QString SettingsPageWidget::searchKeywords() const
{
QString rc;
QLatin1Char sep(' ');
QTextStream(&rc) << m_ui.commandLabel->text()
<< sep << m_ui.autoCheckOutCheckBox->text()
<< sep << m_ui.externalDiffRadioButton->text()
<< sep << m_ui.graphicalDiffRadioButton->text()
<< sep << m_ui.diffArgsLabel->text()
<< sep << m_ui.historyCountLabel->text()
<< sep << m_ui.promptCheckBox->text()
<< sep << m_ui.disableIndexerCheckBox->text()
<< sep << m_ui.timeOutLabel->text()
<< sep << m_ui.indexOnlyVOBsLabel->text()
;
rc.remove(QLatin1Char('&'));
return rc;
}
SettingsPage::SettingsPage() :
m_widget(0)
{
......@@ -133,12 +114,11 @@ SettingsPage::SettingsPage() :
setDisplayName(tr("ClearCase"));
}
QWidget *SettingsPage::createPage(QWidget *parent)
QWidget *SettingsPage::widget()
{
m_widget = new SettingsPageWidget(parent);
if (!m_widget)
m_widget = new SettingsPageWidget;
m_widget->setSettings(ClearCasePlugin::instance()->settings());
if (m_searchKeywords.isEmpty())
m_searchKeywords = m_widget->searchKeywords();
return m_widget;
}
......@@ -146,8 +126,3 @@ void SettingsPage::apply()
{
ClearCasePlugin::instance()->setSettings(m_widget->settings());
}
bool SettingsPage::matches(const QString &s) const
{
return m_searchKeywords.contains(s, Qt::CaseInsensitive);
}
......@@ -35,6 +35,8 @@
#include "ui_settingspage.h"
#include <QPointer>
namespace ClearCase {
namespace Internal {
......@@ -50,8 +52,6 @@ public:
ClearCaseSettings settings() const;
void setSettings(const ClearCaseSettings &);
QString searchKeywords() const;
private:
Ui::SettingsPage m_ui;
};
......@@ -64,14 +64,12 @@ class SettingsPage : public VcsBase::VcsBaseOptionsPage
public:
SettingsPage();
QWidget *createPage(QWidget *parent);
QWidget *widget();
void apply();
void finish() { }
bool matches(const QString &) const;
private:
QString m_searchKeywords;
SettingsPageWidget* m_widget;
QPointer<SettingsPageWidget> m_widget;
};
} // namespace ClearCase
......
......@@ -291,22 +291,23 @@ QString CMakeSettingsPage::findCmakeExecutable() const
return Utils::Environment::systemEnvironment().searchInPath(QLatin1String("cmake"));
}
QWidget *CMakeSettingsPage::createPage(QWidget *parent)
QWidget *CMakeSettingsPage::widget()
{
QWidget *outerWidget = new QWidget(parent);
QFormLayout *formLayout = new QFormLayout(outerWidget);
formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
m_pathchooser = new Utils::PathChooser;
m_pathchooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
formLayout->addRow(tr("Executable:"), m_pathchooser);
formLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding));
if (!m_widget) {
m_widget = new QWidget;
QFormLayout *formLayout = new QFormLayout(m_widget);
formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
m_pathchooser = new Utils::PathChooser;
m_pathchooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
formLayout->addRow(tr("Executable:"), m_pathchooser);
formLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding));
m_preferNinja = new QCheckBox(tr("Prefer Ninja generator (CMake 2.8.9 or higher required)"));
formLayout->addRow(m_preferNinja);
}
m_pathchooser->setPath(m_cmakeValidatorForUser.cmakeExecutable());
m_preferNinja = new QCheckBox(tr("Prefer Ninja generator (CMake 2.8.9 or higher required)"));
m_preferNinja->setChecked(preferNinja());
formLayout->addRow(m_preferNinja);
return outerWidget;
return m_widget;
}
void CMakeSettingsPage::saveSettings() const
......@@ -329,7 +330,7 @@ void CMakeSettingsPage::apply()
void CMakeSettingsPage::finish()
{
delete m_widget;
}
QString CMakeSettingsPage::cmakeExecutable() const
......
......@@ -40,12 +40,13 @@
#include <utils/environment.h>
#include <utils/pathchooser.h>
#include <QFuture>
#include <QStringList>
#include <QAction>
#include <QCheckBox>
#include <QDir>
#include <QFuture>
#include <QPointer>
#include <QStringList>
#include <QVector>
#include <QAction>
#include "cmakevalidator.h"
......@@ -108,7 +109,7 @@ public:
CMakeSettingsPage();
~CMakeSettingsPage();
QWidget *createPage(QWidget *parent);
QWidget *widget();
void apply();
void finish();
......@@ -125,6 +126,7 @@ private:
void saveSettings() const;
QString findCmakeExecutable() const;
QPointer<QWidget> m_widget;
Utils::PathChooser *m_pathchooser;
QCheckBox *m_preferNinja;
CMakeValidator m_cmakeValidatorForUser;
......
......@@ -50,42 +50,43 @@ CommandMappings::CommandMappings(QObject *parent)
// IOptionsPage
QWidget *CommandMappings::createPage(QWidget *parent)
QWidget *CommandMappings::widget()
{
m_page = new Ui::CommandMappings();
QWidget *w = new QWidget(parent);
m_page->setupUi(w);
m_page->targetEdit->setAutoHideButton(Utils::FancyLineEdit::Right, true);
m_page->targetEdit->setPlaceholderText(QString());
m_page->targetEdit->installEventFilter(this);
connect(m_page->targetEdit, SIGNAL(buttonClicked(Utils::FancyLineEdit::Side)),
this, SLOT(removeTargetIdentifier()));
connect(m_page->resetButton, SIGNAL(clicked()),
this, SLOT(resetTargetIdentifier()));
connect(m_page->exportButton, SIGNAL(clicked()),
this, SLOT(exportAction()));
connect(m_page->importButton, SIGNAL(clicked()),
this, SLOT(importAction()));
connect(m_page->defaultButton, SIGNAL(clicked()),
this, SLOT(defaultAction()));
initialize();
m_page->commandList->sortByColumn(0, Qt::AscendingOrder);
connect(m_page->filterEdit, SIGNAL(textChanged(QString)),
this, SLOT(filterChanged(QString)));
connect(m_page->commandList, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
this, SLOT(commandChanged(QTreeWidgetItem*)));
connect(m_page->targetEdit, SIGNAL(textChanged(QString)),
this, SLOT(targetIdentifierChanged()));
new Utils::HeaderViewStretcher(m_page->commandList->header(), 1);
commandChanged(0);
return w;
if (!m_widget) {
m_page = new Ui::CommandMappings();
m_widget = new QWidget;
m_page->setupUi(m_widget);
m_page->targetEdit->setAutoHideButton(Utils::FancyLineEdit::Right, true);
m_page->targetEdit->setPlaceholderText(QString());
m_page->targetEdit->installEventFilter(this);
connect(m_page->targetEdit, SIGNAL(buttonClicked(Utils::FancyLineEdit::Side)),
this, SLOT(removeTargetIdentifier()));
connect(m_page->resetButton, SIGNAL(clicked()),
this, SLOT(resetTargetIdentifier()));
connect(m_page->exportButton, SIGNAL(clicked()),
this, SLOT(exportAction()));
connect(m_page->importButton, SIGNAL(clicked()),
this, SLOT(importAction()));
connect(m_page->defaultButton, SIGNAL(clicked()),
this, SLOT(defaultAction()));
initialize();
m_page->commandList->sortByColumn(0, Qt::AscendingOrder);
connect(m_page->filterEdit, SIGNAL(textChanged(QString)),
this, SLOT(filterChanged(QString)));
connect(m_page->commandList, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
this, SLOT(commandChanged(QTreeWidgetItem*)));
connect(m_page->targetEdit, SIGNAL(textChanged(QString)),
this, SLOT(targetIdentifierChanged()));
new Utils::HeaderViewStretcher(m_page->commandList->header(), 1);
commandChanged(0);
}
return m_widget;
}
void CommandMappings::setImportExportEnabled(bool enabled)
......@@ -126,6 +127,7 @@ void CommandMappings::setTargetHeader(const QString &s)
void CommandMappings::finish()
{
delete m_widget;
if (!m_page) // page was never shown
return;
delete m_page;
......
......@@ -33,6 +33,7 @@
#include <coreplugin/dialogs/ioptionspage.h>
#include <QObject>
#include <QPointer>
QT_BEGIN_NAMESPACE
class QLineEdit;
......@@ -60,7 +61,7 @@ protected slots:
protected:
// IOptionsPage
QWidget *createPage(QWidget *parent);
QWidget *widget();
virtual void apply() {}
virtual void finish();
......@@ -80,6 +81,7 @@ protected:
virtual void markPossibleCollisions(QTreeWidgetItem *) {}
virtual void resetCollisionMarkers() {}
private:
QPointer<QWidget> m_widget;
Internal::Ui::CommandMappings *m_page;
};
......
......@@ -29,6 +29,11 @@
#include "ioptionspage.h"
#include <QCheckBox>
#include <QGroupBox>
#include <QLabel>
#include <QPushButton>
/*!
\class Core::IOptionsPage
\mainclass
......@@ -43,12 +48,58 @@
\li \c displayName() is the (translated) name for display
\li \c category() is the unique id for the category that the page should be displayed in
\li \c displayCategory() is the translated name of the category
\li \c createPage() is called to retrieve the widget to show in the
\gui Options dialog
The widget will be destroyed by the widget hierarchy when the dialog closes
\li \c widget() is called to retrieve the widget to show in the
\gui Options dialog. You should create a widget lazily here, and delete it again in the
finish() method. This method can be called multiple times, so you should only create a new
widget if the old one was deleted.
\li \c apply() is called to store the settings. It should detect if any changes have been
made and store those
\li \c finish() is called directly before the \gui Options dialog closes
\li \c matches() is used for the \gui Options dialog search filter
\li \c finish() is called directly before the \gui Options dialog closes. Here you should delete
the widget that was created in widget() to free resources.
\li \c matches() is used for the \gui Options dialog search filter. The default implementation
takes the widget() and searches for all labels, buttons, checkboxes and group boxes,
and matches on their texts/titles. You can implement your own matching algorithm, but
usually the default implementation will work fine.
\endlist
*/
Core::IOptionsPage::IOptionsPage(QObject *parent)
: QObject(parent),
m_keywordsInitialized(false)
{
}
Core::IOptionsPage::~IOptionsPage()
{
}
bool Core::IOptionsPage::matches(const QString &searchKeyWord) const
{
if (!m_keywordsInitialized) {
IOptionsPage *that = const_cast<IOptionsPage *>(this);
QWidget *widget = that->widget();
if (!widget)
return false;
// find common subwidgets
foreach (const QLabel *label, widget->findChildren<QLabel *>())
m_keywords << label->text();
foreach (const QCheckBox *checkbox, widget->findChildren<QCheckBox *>())
m_keywords << checkbox->text();
foreach (const QPushButton *pushButton, widget->findChildren<QPushButton *>())
m_keywords << pushButton->text();
foreach (const QGroupBox *groupBox, widget->findChildren<QGroupBox *>())
m_keywords << groupBox->title();
// clean up accelerators
QMutableStringListIterator it(m_keywords);
while (it.hasNext())
it.next().remove(QLatin1Char('&'));
m_keywordsInitialized = true;
}
foreach (const QString &keyword, m_keywords)
if (keyword.contains(searchKeyWord, Qt::CaseInsensitive))
return true;
return false;
}
......@@ -34,6 +34,7 @@
#include <QIcon>
#include <QObject>
#include <QStringList>
namespace Core {
......@@ -42,7 +43,8 @@ class CORE_EXPORT IOptionsPage : public QObject
Q_OBJECT
public:
IOptionsPage(QObject *parent = 0) : QObject(parent) {}
IOptionsPage(QObject *parent = 0);
virtual ~IOptionsPage();
Id id() const { return m_id; }
QString displayName() const { return m_displayName; }
......@@ -50,8 +52,8 @@ public:
QString displayCategory() const { return m_displayCategory; }
QIcon categoryIcon() const { return QIcon(m_categoryIcon); }
virtual bool matches(const QString & /* searchKeyWord*/) const { return false; }
virtual QWidget *createPage(QWidget *parent) = 0;
virtual bool matches(const QString &searchKeyWord) const;
virtual QWidget *widget() = 0;
virtual void apply() = 0;
virtual void finish() = 0;
......@@ -67,6 +69,9 @@ protected:
QString m_displayName;
QString m_displayCategory;
QString m_categoryIcon;
mutable bool m_keywordsInitialized;
mutable QStringList m_keywords;
};
/*
......
......@@ -440,7 +440,7 @@ void SettingsDialog::ensureCategoryWidget(Category *category)
QTabWidget *tabWidget = new QTabWidget;
for (int j = 0; j < category->pages.size(); ++j) {
IOptionsPage *page = category->pages.at(j);
QWidget *widget = page->createPage(0);
QWidget *widget = page->widget();
tabWidget->addTab(widget, page->displayName());
}
......
......@@ -61,12 +61,12 @@ ShortcutSettings::ShortcutSettings(QObject *parent)
setCategoryIcon(QLatin1String(Core::Constants::SETTINGS_CATEGORY_CORE_ICON));
}
QWidget *ShortcutSettings::createPage(QWidget *parent)
QWidget *ShortcutSettings::widget()
{
m_initialized = true;
m_keyNum = m_key[0] = m_key[1] = m_key[2] = m_key[3] = 0;
QWidget *w = CommandMappings::createPage(parent);
QWidget *w = CommandMappings::widget();