From: Vincent van Ravesteijn Date: Sun, 5 Jun 2011 17:54:27 +0000 (+0000) Subject: Add a search box to the Document Settings and Preferences dialog. X-Git-Tag: 2.1.0beta1~3113 X-Git-Url: https://git.lyx.org/gitweb/?a=commitdiff_plain;h=519f74ab61e4b86b11c252dc9f24d503adf0e571;p=features.git Add a search box to the Document Settings and Preferences dialog. Patch from venmo00. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@38959 a592a061-630c-0410-9148-cb99ea01b6c8 --- diff --git a/lib/Makefile.am b/lib/Makefile.am index 7c98949076..6bba536488 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -371,6 +371,7 @@ dist_images_DATA = \ images/dialog-toggle_findreplaceadv.png \ images/dialog-toggle_toc.png \ images/down.png \ + images/editclear.png \ images/ert-insert.png \ images/file-open.png \ images/float-insert_figure.png \ diff --git a/lib/images/editclear.png b/lib/images/editclear.png new file mode 100644 index 0000000000..ec52c41bc2 Binary files /dev/null and b/lib/images/editclear.png differ diff --git a/src/frontends/qt4/PanelStack.cpp b/src/frontends/qt4/PanelStack.cpp index 60793c31f8..1863040bd1 100644 --- a/src/frontends/qt4/PanelStack.cpp +++ b/src/frontends/qt4/PanelStack.cpp @@ -12,17 +12,32 @@ #include "PanelStack.h" +#include "GuiApplication.h" #include "qt_helpers.h" #include "support/debug.h" +#include "support/foreach.h" +#include "support/lassert.h" +#include +#include +#include +#include #include +#include +#include +#include #include #include +#include +#include +#include +#include +#include #include +#include #include - -#include "support/lassert.h" +#include using namespace std; @@ -33,9 +48,16 @@ namespace frontend { PanelStack::PanelStack(QWidget * parent) : QWidget(parent) { + delay_search_ = new QTimer(this); list_ = new QTreeWidget(this); stack_ = new QStackedWidget(this); + search_ = new FancyLineEdit(this); + + // Configure the timer + delay_search_->setSingleShot(true); + connect(delay_search_, SIGNAL(timeout()), this, SLOT(search())); + // Configure tree list_->setRootIsDecorated(false); list_->setColumnCount(1); list_->header()->hide(); @@ -48,9 +70,27 @@ PanelStack::PanelStack(QWidget * parent) connect(list_, SIGNAL(itemClicked (QTreeWidgetItem*, int)), this, SLOT(itemSelected(QTreeWidgetItem *, int))); - QHBoxLayout * layout = new QHBoxLayout(this); - layout->addWidget(list_, 0); - layout->addWidget(stack_, 1); + // Configure the search box +#if QT_VERSION >= 0x040700 + search_->setPlaceholderText(qt_("Search")); +#endif + + search_->setButtonPixmap(FancyLineEdit::Right, getPixmap("images/", "editclear", "png")); + search_->setButtonVisible(FancyLineEdit::Right, true); + search_->setButtonToolTip(FancyLineEdit::Right, qt_("Clear text")); + search_->setAutoHideButton(FancyLineEdit::Right, true); + connect(search_, SIGNAL(rightButtonClicked()), this, SLOT(resetSearch())); + connect(search_, SIGNAL(textEdited(QString)), this, SLOT(filterChanged(QString))); + + // Create the output layout, horizontal plus a VBox on the left with the search + // box and the tree + QVBoxLayout * left_layout = new QVBoxLayout(); + left_layout->addWidget(search_, 0); + left_layout->addWidget(list_, 1); + + QHBoxLayout * main_layout = new QHBoxLayout(this); + main_layout->addLayout(left_layout, 0); + main_layout->addWidget(stack_, 1); } @@ -132,21 +172,153 @@ void PanelStack::switchPanel(QTreeWidgetItem * item, QTreeWidgetItem * previous) { // do nothing when clicked on whitespace (item=NULL) - if( !item ) + if (!item) return; // if we have a category, expand the tree and go to the - // first item + // first enabled item if (item->childCount() > 0) { item->setExpanded(true); - if (previous && previous->parent() != item) - switchPanel( item->child(0), previous ); + if (previous && previous->parent() != item) { + // Looks for a child not disabled + for (int i = 0; i < item->childCount(); ++i) { + if (item->child(i)->flags() & Qt::ItemIsEnabled) { + switchPanel(item->child(i), previous); + break; + } + } + } } else if (QWidget * w = widget_map_.value(item, 0)) { stack_->setCurrentWidget(w); } } +static bool matches(QString const & input, QString const & search) +{ + QString text = input; + + // Check if the input contains the search string + return text.remove('&').contains(search, Qt::CaseInsensitive); +} + +static void setTreeItemStatus(QTreeWidgetItem * tree_item, bool enabled) +{ + // Enable/disable the item + tree_item->setDisabled(!enabled); + + // Change the color from black to gray or viceversa + QPalette::ColorGroup new_color = enabled ? QPalette::Active : QPalette::Disabled; + tree_item->setTextColor(0, QApplication::palette().color(new_color, QPalette::Text)); +} + +void PanelStack::hideEvent(QHideEvent * event) +{ + QWidget::hideEvent(event); + + // Programatically hidden (not simply minimized by the user) + if (!event->spontaneous()) { + resetSearch(); + } +} + +void PanelStack::resetSearch() +{ + search_->setText(QString()); + search(); +} + +void PanelStack::filterChanged(QString const & /*search*/) +{ + // The text in the search box is changed, reset the timer + // and then search in the widgets + delay_search_->start(300); +} + +void PanelStack::search() +{ + QString search = search_->text(); + bool enable_all = search.isEmpty(); + + // If the search string is empty we enable all the items + // otherwise we disable everything and then selectively + // re-enable matching items + foreach (QTreeWidgetItem * tree_item, panel_map_) { + setTreeItemStatus(tree_item, enable_all); + } + + foreach (QTreeWidgetItem * tree_item, panel_map_) { + // Current widget + QWidget * pane_widget = widget_map_[tree_item]; + + // First of all we look in the pane name + bool pane_matches = tree_item->text(0).contains(search, Qt::CaseInsensitive); + + // If the tree item has an associated pane + if (pane_widget) { + // Loops on the list of children widgets (recursive) + QWidgetList children = pane_widget->findChildren(); + foreach (QWidget * child_widget, children) { + bool widget_matches = false; + + // Try to cast to the most common widgets and looks in it's content + // It's bad OOP, it would be nice to have a QWidget::toString() overloaded by + // each widget, but this would require to change Qt or subclass each widget. + // Note that we have to ignore the amperstand symbol + if (QAbstractButton * button = qobject_cast(child_widget)) { + widget_matches = matches(button->text(), search); + + } else if (QGroupBox * group_box = qobject_cast(child_widget)) { + widget_matches = matches(group_box->title(), search); + + } else if (QLabel * label = qobject_cast(child_widget)) { + widget_matches = matches(label->text(), search); + + } else if (QLineEdit * line_edit = qobject_cast(child_widget)) { + widget_matches = matches(line_edit->text(), search); + + } else if (QListWidget * list_widget = qobject_cast(child_widget)) { + widget_matches = (list_widget->findItems(search, Qt::MatchContains)).count() > 0; + + } else if (QTreeWidget * tree_view = qobject_cast(child_widget)) { + widget_matches = (tree_view->findItems(search, Qt::MatchContains)).count() > 0; + + } else if (QComboBox * combo_box = qobject_cast(child_widget)) { + widget_matches = (combo_box->findText(search, Qt::MatchContains)) != -1; + + } else { + continue; + } + + // If this widget meets the search criteria + if (widget_matches && !enable_all) { + // The pane too meets the search criteria + pane_matches = true; + + // Highlight the widget + QPalette widget_palette = child_widget->palette(); + widget_palette.setColor(child_widget->foregroundRole(), Qt::red); + child_widget->setPalette(widget_palette); + } else { + // Reset the color of the widget + child_widget->setPalette(QApplication::palette(child_widget)); + } + } + + // If the pane meets the search criteria + if (pane_matches && !enable_all) { + // Expand and enable the pane and his ancestors (typically just the parent) + QTreeWidgetItem * item = tree_item; + do { + item->setExpanded(true); + setTreeItemStatus(item, true); + item = item->parent(); + } while (item); + } + } + + } +} void PanelStack::itemSelected(QTreeWidgetItem * item, int) { diff --git a/src/frontends/qt4/PanelStack.h b/src/frontends/qt4/PanelStack.h index fbc807de3b..e0d03a189f 100644 --- a/src/frontends/qt4/PanelStack.h +++ b/src/frontends/qt4/PanelStack.h @@ -13,12 +13,19 @@ #ifndef PANELSTACK_H #define PANELSTACK_H -#include +#include "FancyLineEdit.h" + #include +#include +class QAbstractButton; +class QHideEvent; +class QLineEdit; +class QPushButton; +class QStackedWidget; +class QTimer; class QTreeWidget; class QTreeWidgetItem; -class QStackedWidget; namespace lyx { namespace frontend { @@ -46,11 +53,21 @@ public: QSize sizeHint() const; public Q_SLOTS: + /// the option filter changed + void filterChanged(QString const & search); + /// perform the search + void search(); + /// reset the search box + void resetSearch(); /// set current panel from an item void switchPanel(QTreeWidgetItem * it, QTreeWidgetItem * previous = 0); /// click on the tree void itemSelected(QTreeWidgetItem *, int); +protected: + /// widget hidden + void hideEvent(QHideEvent * event); + private: /// typedef QHash PanelMap; @@ -61,11 +78,18 @@ private: WidgetMap widget_map_; + /// contains the search box + FancyLineEdit * search_; + /// contains the items QTreeWidget * list_; /// contains the panes QStackedWidget * stack_; + + // timer to delay the search between options + QTimer * delay_search_; + }; } // namespace frontend