Make find options in tool bar more accessible.

Open a popup that doesn't close on every change of an option.
Make the options button accessible through tab.

Task-number: QTCREATORBUG-11340

Change-Id: I61b83243ead4b0b3d7075c1e8f8327cd31d9c2c4
Reviewed-by: Bojan Petrovic <bojan85@gmail.com>
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
This commit is contained in:
Eike Ziller
2014-02-25 18:38:35 +01:00
parent 880a834b11
commit 8e51a93d37
4 changed files with 156 additions and 14 deletions

View File

@@ -30,13 +30,14 @@
#include "execmenu.h" #include "execmenu.h"
#include "fancylineedit.h" #include "fancylineedit.h"
#include "historycompleter.h" #include "historycompleter.h"
#include "hostosinfo.h"
#include "qtcassert.h" #include "qtcassert.h"
#include <QAbstractItemView> #include <QAbstractItemView>
#include <QDebug> #include <QDebug>
#include <QKeyEvent> #include <QKeyEvent>
#include <QMenu> #include <QMenu>
#include <QPainter> #include <QStylePainter>
#include <QPropertyAnimation> #include <QPropertyAnimation>
#include <QStyle> #include <QStyle>
@@ -184,6 +185,11 @@ bool FancyLineEdit::isButtonVisible(Side side) const
return d->m_iconEnabled[side]; return d->m_iconEnabled[side];
} }
QAbstractButton *FancyLineEdit::button(FancyLineEdit::Side side) const
{
return d->m_iconbutton[side];
}
void FancyLineEdit::iconClicked() void FancyLineEdit::iconClicked()
{ {
IconButton *button = qobject_cast<IconButton *>(sender()); IconButton *button = qobject_cast<IconButton *>(sender());
@@ -480,7 +486,7 @@ IconButton::IconButton(QWidget *parent)
void IconButton::paintEvent(QPaintEvent *) void IconButton::paintEvent(QPaintEvent *)
{ {
QPainter painter(this); QStylePainter painter(this);
QRect pixmapRect = QRect(0, 0, m_pixmap.width(), m_pixmap.height()); QRect pixmapRect = QRect(0, 0, m_pixmap.width(), m_pixmap.height());
pixmapRect.moveCenter(rect().center()); pixmapRect.moveCenter(rect().center());
@@ -488,6 +494,18 @@ void IconButton::paintEvent(QPaintEvent *)
painter.setOpacity(m_iconOpacity); painter.setOpacity(m_iconOpacity);
painter.drawPixmap(pixmapRect, m_pixmap); painter.drawPixmap(pixmapRect, m_pixmap);
if (hasFocus()) {
QStyleOptionFocusRect focusOption;
focusOption.initFrom(this);
focusOption.rect = pixmapRect;
if (HostOsInfo::isMacHost()) {
focusOption.rect.adjust(-4, -4, 4, 4);
painter.drawControl(QStyle::CE_FocusFrame, focusOption);
} else {
painter.drawPrimitive(QStyle::PE_FrameFocusRect, focusOption);
}
}
} }
void IconButton::animateShow(bool visible) void IconButton::animateShow(bool visible)
@@ -505,4 +523,20 @@ void IconButton::animateShow(bool visible)
} }
} }
void IconButton::keyPressEvent(QKeyEvent *ke)
{
QAbstractButton::keyPressEvent(ke);
if (!ke->modifiers() && (ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_Return))
click();
// do not forward to line edit
ke->accept();
}
void IconButton::keyReleaseEvent(QKeyEvent *ke)
{
QAbstractButton::keyReleaseEvent(ke);
// do not forward to line edit
ke->accept();
}
} // namespace Utils } // namespace Utils

View File

@@ -60,6 +60,11 @@ public:
void setAutoHide(bool hide) { m_autoHide = hide; } void setAutoHide(bool hide) { m_autoHide = hide; }
bool hasAutoHide() const { return m_autoHide; } bool hasAutoHide() const { return m_autoHide; }
protected:
void keyPressEvent(QKeyEvent *ke);
void keyReleaseEvent(QKeyEvent *ke);
private: private:
float m_iconOpacity; float m_iconOpacity;
bool m_autoHide; bool m_autoHide;
@@ -89,6 +94,7 @@ public:
void setButtonVisible(Side side, bool visible); void setButtonVisible(Side side, bool visible);
bool isButtonVisible(Side side) const; bool isButtonVisible(Side side) const;
QAbstractButton *button(Side side) const;
void setButtonToolTip(Side side, const QString &); void setButtonToolTip(Side side, const QString &);
void setButtonFocusPolicy(Side side, Qt::FocusPolicy policy); void setButtonFocusPolicy(Side side, Qt::FocusPolicy policy);

View File

@@ -42,10 +42,12 @@
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <utils/flowlayout.h> #include <utils/flowlayout.h>
#include <utils/qtcassert.h>
#include <QDebug> #include <QDebug>
#include <QSettings> #include <QSettings>
#include <QCheckBox>
#include <QClipboard> #include <QClipboard>
#include <QCompleter> #include <QCompleter>
#include <QKeyEvent> #include <QKeyEvent>
@@ -100,14 +102,15 @@ FindToolBar::FindToolBar(FindPlugin *plugin, CurrentDocumentFind *currentDocumen
m_ui.findEdit->setSpecialCompleter(m_findCompleter); m_ui.findEdit->setSpecialCompleter(m_findCompleter);
m_ui.replaceEdit->setSpecialCompleter(m_replaceCompleter); m_ui.replaceEdit->setSpecialCompleter(m_replaceCompleter);
QMenu *lineEditMenu = new QMenu(m_ui.findEdit);
m_ui.findEdit->setButtonMenu(Utils::FancyLineEdit::Left, lineEditMenu);
m_ui.findEdit->setButtonVisible(Utils::FancyLineEdit::Left, true); m_ui.findEdit->setButtonVisible(Utils::FancyLineEdit::Left, true);
m_ui.findEdit->setFiltering(true); m_ui.findEdit->setFiltering(true);
m_ui.findEdit->setPlaceholderText(QString()); m_ui.findEdit->setPlaceholderText(QString());
m_ui.findEdit->button(Utils::FancyLineEdit::Left)->setFocusPolicy(Qt::TabFocus);
m_ui.replaceEdit->setPlaceholderText(QString()); m_ui.replaceEdit->setPlaceholderText(QString());
connect(m_ui.findEdit, SIGNAL(textChanged(QString)), this, SLOT(invokeFindIncremental())); connect(m_ui.findEdit, SIGNAL(textChanged(QString)), this, SLOT(invokeFindIncremental()));
connect(m_ui.findEdit, SIGNAL(leftButtonClicked()),
this, SLOT(findEditButtonClicked()));
// invoke{Find,Replace}Helper change the completion model. QueuedConnection is used to perform these // invoke{Find,Replace}Helper change the completion model. QueuedConnection is used to perform these
// changes only after the completer's activated() signal is handled (QTCREATORBUG-8408) // changes only after the completer's activated() signal is handled (QTCREATORBUG-8408)
@@ -222,8 +225,7 @@ FindToolBar::FindToolBar(FindPlugin *plugin, CurrentDocumentFind *currentDocumen
m_caseSensitiveAction->setChecked(false); m_caseSensitiveAction->setChecked(false);
cmd = Core::ActionManager::registerAction(m_caseSensitiveAction, Constants::CASE_SENSITIVE, globalcontext); cmd = Core::ActionManager::registerAction(m_caseSensitiveAction, Constants::CASE_SENSITIVE, globalcontext);
mfind->addAction(cmd, Constants::G_FIND_FLAGS); mfind->addAction(cmd, Constants::G_FIND_FLAGS);
connect(m_caseSensitiveAction, SIGNAL(triggered(bool)), this, SLOT(setCaseSensitive(bool))); connect(m_caseSensitiveAction, SIGNAL(toggled(bool)), this, SLOT(setCaseSensitive(bool)));
lineEditMenu->addAction(m_caseSensitiveAction);
m_wholeWordAction = new QAction(tr("Whole Words Only"), this); m_wholeWordAction = new QAction(tr("Whole Words Only"), this);
m_wholeWordAction->setIcon(QIcon(QLatin1String(":/find/images/wholewords.png"))); m_wholeWordAction->setIcon(QIcon(QLatin1String(":/find/images/wholewords.png")));
@@ -231,8 +233,7 @@ FindToolBar::FindToolBar(FindPlugin *plugin, CurrentDocumentFind *currentDocumen
m_wholeWordAction->setChecked(false); m_wholeWordAction->setChecked(false);
cmd = Core::ActionManager::registerAction(m_wholeWordAction, Constants::WHOLE_WORDS, globalcontext); cmd = Core::ActionManager::registerAction(m_wholeWordAction, Constants::WHOLE_WORDS, globalcontext);
mfind->addAction(cmd, Constants::G_FIND_FLAGS); mfind->addAction(cmd, Constants::G_FIND_FLAGS);
connect(m_wholeWordAction, SIGNAL(triggered(bool)), this, SLOT(setWholeWord(bool))); connect(m_wholeWordAction, SIGNAL(toggled(bool)), this, SLOT(setWholeWord(bool)));
lineEditMenu->addAction(m_wholeWordAction);
m_regularExpressionAction = new QAction(tr("Use Regular Expressions"), this); m_regularExpressionAction = new QAction(tr("Use Regular Expressions"), this);
m_regularExpressionAction->setIcon(QIcon(QLatin1String(":/find/images/regexp.png"))); m_regularExpressionAction->setIcon(QIcon(QLatin1String(":/find/images/regexp.png")));
@@ -240,8 +241,7 @@ FindToolBar::FindToolBar(FindPlugin *plugin, CurrentDocumentFind *currentDocumen
m_regularExpressionAction->setChecked(false); m_regularExpressionAction->setChecked(false);
cmd = Core::ActionManager::registerAction(m_regularExpressionAction, Constants::REGULAR_EXPRESSIONS, globalcontext); cmd = Core::ActionManager::registerAction(m_regularExpressionAction, Constants::REGULAR_EXPRESSIONS, globalcontext);
mfind->addAction(cmd, Constants::G_FIND_FLAGS); mfind->addAction(cmd, Constants::G_FIND_FLAGS);
connect(m_regularExpressionAction, SIGNAL(triggered(bool)), this, SLOT(setRegularExpressions(bool))); connect(m_regularExpressionAction, SIGNAL(toggled(bool)), this, SLOT(setRegularExpressions(bool)));
lineEditMenu->addAction(m_regularExpressionAction);
m_preserveCaseAction = new QAction(tr("Preserve Case when Replacing"), this); m_preserveCaseAction = new QAction(tr("Preserve Case when Replacing"), this);
m_preserveCaseAction->setIcon(QPixmap(QLatin1String(":/find/images/preservecase.png"))); m_preserveCaseAction->setIcon(QPixmap(QLatin1String(":/find/images/preservecase.png")));
@@ -249,8 +249,7 @@ FindToolBar::FindToolBar(FindPlugin *plugin, CurrentDocumentFind *currentDocumen
m_preserveCaseAction->setChecked(false); m_preserveCaseAction->setChecked(false);
cmd = Core::ActionManager::registerAction(m_preserveCaseAction, Constants::PRESERVE_CASE, globalcontext); cmd = Core::ActionManager::registerAction(m_preserveCaseAction, Constants::PRESERVE_CASE, globalcontext);
mfind->addAction(cmd, Constants::G_FIND_FLAGS); mfind->addAction(cmd, Constants::G_FIND_FLAGS);
connect(m_preserveCaseAction, SIGNAL(triggered(bool)), this, SLOT(setPreserveCase(bool))); connect(m_preserveCaseAction, SIGNAL(toggled(bool)), this, SLOT(setPreserveCase(bool)));
lineEditMenu->addAction(m_preserveCaseAction);
connect(m_currentDocumentFind, SIGNAL(candidateChanged()), this, SLOT(adaptToCandidate())); connect(m_currentDocumentFind, SIGNAL(candidateChanged()), this, SLOT(adaptToCandidate()));
connect(m_currentDocumentFind, SIGNAL(changed()), this, SLOT(updateToolBar())); connect(m_currentDocumentFind, SIGNAL(changed()), this, SLOT(updateToolBar()));
@@ -554,6 +553,12 @@ void FindToolBar::findFlagsChanged()
m_currentDocumentFind->highlightAll(getFindText(), effectiveFindFlags()); m_currentDocumentFind->highlightAll(getFindText(), effectiveFindFlags());
} }
void FindToolBar::findEditButtonClicked()
{
OptionsPopup *popup = new OptionsPopup(m_ui.findEdit);
popup->show();
}
void FindToolBar::updateIcons() void FindToolBar::updateIcons()
{ {
FindFlags effectiveFlags = effectiveFindFlags(); FindFlags effectiveFlags = effectiveFindFlags();
@@ -685,11 +690,16 @@ void FindToolBar::findPreviousSelected()
bool FindToolBar::focusNextPrevChild(bool next) bool FindToolBar::focusNextPrevChild(bool next)
{ {
// close tab order change QAbstractButton *optionsButton = m_ui.findEdit->button(Utils::FancyLineEdit::Left);
// close tab order
if (next && m_ui.advancedButton->hasFocus()) if (next && m_ui.advancedButton->hasFocus())
optionsButton->setFocus(Qt::TabFocusReason);
else if (next && optionsButton->hasFocus())
m_ui.findEdit->setFocus(Qt::TabFocusReason); m_ui.findEdit->setFocus(Qt::TabFocusReason);
else if (!next && m_ui.findEdit->hasFocus()) else if (!next && optionsButton->hasFocus())
m_ui.advancedButton->setFocus(Qt::TabFocusReason); m_ui.advancedButton->setFocus(Qt::TabFocusReason);
else if (!next && m_ui.findEdit->hasFocus())
optionsButton->setFocus(Qt::TabFocusReason);
else else
return Utils::StyledBar::focusNextPrevChild(next); return Utils::StyledBar::focusNextPrevChild(next);
return true; return true;
@@ -778,3 +788,69 @@ void FindToolBar::setBackward(bool backward)
{ {
setFindFlag(FindBackward, backward); setFindFlag(FindBackward, backward);
} }
OptionsPopup::OptionsPopup(QWidget *parent)
: QWidget(parent, Qt::Popup)
{
setAttribute(Qt::WA_DeleteOnClose);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setContentsMargins(2, 2, 2, 2);
layout->setSpacing(2);
setLayout(layout);
QCheckBox *firstCheckBox = createCheckboxForCommand(Constants::CASE_SENSITIVE);
layout->addWidget(firstCheckBox);
layout->addWidget(createCheckboxForCommand(Constants::WHOLE_WORDS));
layout->addWidget(createCheckboxForCommand(Constants::REGULAR_EXPRESSIONS));
layout->addWidget(createCheckboxForCommand(Constants::PRESERVE_CASE));
firstCheckBox->setFocus();
move(parent->mapToGlobal(QPoint(0, -sizeHint().height())));
}
bool OptionsPopup::event(QEvent *ev)
{
if (ev->type() == QEvent::ShortcutOverride) {
QKeyEvent *ke = static_cast<QKeyEvent *>(ev);
if (ke->key() == Qt::Key_Escape && !ke->modifiers()) {
ev->accept();
return true;
}
}
return QWidget::event(ev);
}
bool OptionsPopup::eventFilter(QObject *obj, QEvent *ev)
{
QCheckBox *checkbox = qobject_cast<QCheckBox *>(obj);
if (ev->type() == QEvent::KeyPress && checkbox) {
QKeyEvent *ke = static_cast<QKeyEvent *>(ev);
if (!ke->modifiers() && (ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_Return)) {
checkbox->click();
ev->accept();
return true;
}
}
return QWidget::eventFilter(obj, ev);
}
void OptionsPopup::actionChanged()
{
QAction *action = qobject_cast<QAction *>(sender());
QTC_ASSERT(action, return);
QCheckBox *checkbox = m_checkboxMap.value(action);
QTC_ASSERT(checkbox, return);
checkbox->setEnabled(action->isEnabled());
}
QCheckBox *OptionsPopup::createCheckboxForCommand(Id id)
{
QAction *action = ActionManager::command(id)->action();
QCheckBox *checkbox = new QCheckBox(action->text());
checkbox->setToolTip(action->toolTip());
checkbox->setChecked(action->isChecked());
checkbox->setEnabled(action->isEnabled());
checkbox->installEventFilter(this); // enter key handling
QObject::connect(checkbox, SIGNAL(clicked(bool)), action, SLOT(setChecked(bool)));
QObject::connect(action, SIGNAL(changed()), this, SLOT(actionChanged()));
m_checkboxMap.insert(action, checkbox);
return checkbox;
}

View File

@@ -33,10 +33,15 @@
#include "ui_findwidget.h" #include "ui_findwidget.h"
#include "currentdocumentfind.h" #include "currentdocumentfind.h"
#include <coreplugin/id.h>
#include <utils/styledbar.h> #include <utils/styledbar.h>
#include <QTimer> #include <QTimer>
QT_BEGIN_NAMESPACE
class QCheckBox;
QT_END_NAMESPACE
namespace Core { namespace Core {
class FindToolBarPlaceHolder; class FindToolBarPlaceHolder;
@@ -44,6 +49,26 @@ class FindPlugin;
namespace Internal { namespace Internal {
class OptionsPopup : public QWidget
{
Q_OBJECT
public:
explicit OptionsPopup(QWidget *parent);
protected:
bool event(QEvent *ev);
bool eventFilter(QObject *obj, QEvent *ev);
private slots:
void actionChanged();
private:
QCheckBox *createCheckboxForCommand(Id id);
QMap<QAction *, QCheckBox *> m_checkboxMap;
};
class FindToolBar : public Utils::StyledBar class FindToolBar : public Utils::StyledBar
{ {
Q_OBJECT Q_OBJECT
@@ -85,6 +110,7 @@ private slots:
void updateFindAction(); void updateFindAction();
void updateToolBar(); void updateToolBar();
void findFlagsChanged(); void findFlagsChanged();
void findEditButtonClicked();
void setCaseSensitive(bool sensitive); void setCaseSensitive(bool sensitive);
void setWholeWord(bool wholeOnly); void setWholeWord(bool wholeOnly);