On 13-4-2011 16:26, venom00 wrote: > Here's the patch. I hope works fine. It would be nice to put it in 2.0 but I > think it's impossible as it's late and I've added a string ("Search", maybe > we already have it). Moreover it's my first patch in C++ to LyX, so probably > it will be full of inconsistencies. > > It adds a search box to Tools -> Preferences and Document -> Settings. It > looks for the searched text in all the widgets of the panes and highlights > them if match. Panes without matching widgets are disabled and grayed. > > Some questions: > - I'm using QLineEdit::setPlaceHolder(), which was introduced in Qt 4.7, it > that OK? > - To translate the string I used tr("Search"), is that correct? > - Currently the widgets are highlighted in red, alternative ideas? > > I took insipiration from Qt Creator and Eclipse. > > Hope you like it. > venom00 > > Index: src/frontends/qt4/PanelStack.cpp > =================================================================== > --- src/frontends/qt4/PanelStack.cpp (revisione 38358) > +++ src/frontends/qt4/PanelStack.cpp (copia locale) > @@ -18,9 +18,17 @@ > > #include <QFontMetrics> > #include <QHBoxLayout> > +#include <QVBoxLayout> > #include <QHeaderView> > #include <QStackedWidget> > #include <QTreeWidget> > +#include <QLineEdit> > +#include <QGroupBox> > +#include <QLabel> > +#include <QAbstractButton> > +#include <QComboBox> > +#include <QApplication> > +#include <QListWidget>
We try to sort the includes. > > - QHBoxLayout * layout = new QHBoxLayout(this); > - layout->addWidget(list_, 0); > - layout->addWidget(stack_, 1); > + // Configure the search box #if QT_VERSION >= 0x040700 > + search_->setPlaceholderText(tr("Search")); #endif > + > + connect(search_, SIGNAL(textEdited(QString)), this, > SLOT(filterChanged(QString))); > + > @@ -136,11 +158,18 @@ > 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) { if (!item->child(i)->isDisabled()) { (although now I see this is introduced in Qt 4.3) > + switchPanel( item->child(i), previous ); Style: no spaces next to the braces. > + break; > + } > + } > + } > } > else if (QWidget * w = widget_map_.value(item, 0)) { > stack_->setCurrentWidget(w); > @@ -148,6 +177,115 @@ > } > > > +void PanelStack::filterChanged(QString search) { > + bool enable_all = search.length() == 0; bool const enable_all = search.isEmpty(); > + > + // Iterator for the tree > + QHashIterator<QString, QTreeWidgetItem *> > panes_iterator(this->panel_map_); "this" is unnecessary. Usually we use iterators like: PanelMap::const_iterator it = panel_map_.begin(); PanelMap::const_iterator end = panel_map_.end(); for (; it != end; ++it) { QTreeWidgetItem * item = *it; [..] } > + > + // If the search string is empty we have to re-enable everything > + if (enable_all) { > + while (panes_iterator.hasNext()) { > + panes_iterator.next(); > + panes_iterator.value()->setDisabled(false); > + panes_iterator.value()->setTextColor(0, > QApplication::palette().color(QPalette::Active, QPalette::Text)); > + } > + } else { > + // Otherwise disable everything and then re-enable panes > matching the > + // search criteria > + while (panes_iterator.hasNext()) { > + panes_iterator.next(); > + panes_iterator.value()->setDisabled(true); > + panes_iterator.value()->setTextColor(0, > QApplication::palette().color(QPalette::Disabled, QPalette::Text)); > + } > + } It's strange that Qt doesn't paint the items in the Disabled color whenever the item is disabled. > + > + // Reset the iterator > + panes_iterator.toFront(); it = panel_map_.begin(); > + > + while (panes_iterator.hasNext()) { > + panes_iterator.next(); > + > + // Current widget > + QWidget * pane_widget = > this->widget_map_[panes_iterator.value()]; > + > + // First of all we look in the pane name > + bool pane_matches = > panes_iterator.value()->text(0).contains(search, Qt::CaseInsensitive); > + > + // If the tree item has an associated pane > + if (pane_widget) { > + > + // Collect all the children widgets (recursive) > + QList<QWidget *> children = > pane_widget->findChildren<QWidget *>(); > + > + // Loops on the list of children widgets > + size_t last_child = children.size(); > + for (size_t child_index = 0; child_index != last_child; > ++child_index) { > + bool widget_matches = false; > + > + // Try to cast to the most common widgets and > looks in it's content by each > + // 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<QAbstractButton *>(children[child_index])) { > + widget_matches = (new > QString(button->text()))->replace('&', "") > + .contains(search, > Qt::CaseInsensitive); > + > + } else if (QGroupBox * group_box = > qobject_cast<QGroupBox *>(children[child_index])) { > + widget_matches = (new > QString(group_box->title()))->replace('&', "") > + .contains(search, > Qt::CaseInsensitive); > + > + } else if (QLabel * label = qobject_cast<QLabel > *>(children[child_index])) { > + widget_matches = (new > QString(label->text()))->replace('&', "") > + .contains(search, > Qt::CaseInsensitive); > + > + } else if (QLineEdit * line_edit = > qobject_cast<QLineEdit *>(children[child_index])) { > + widget_matches = (new > QString(line_edit->text()))->replace('&', "") > + .contains(search, > Qt::CaseInsensitive); > + > + } else if (QListWidget * list_widget = > qobject_cast<QListWidget *>(children[child_index])) { > + widget_matches = > (list_widget->findItems(search, Qt::MatchContains)).count() != 0; > + > + } else if (QTreeWidget * tree_view = > qobject_cast<QTreeWidget *>(children[child_index])) { > + widget_matches = > (tree_view->findItems(search, Qt::MatchContains)).count() != 0; > + > + } else if (QComboBox * combo_box = > qobject_cast<QComboBox *>(children[child_index])) { > + widget_matches = > (combo_box->findText(search, Qt::MatchContains)) != -1; > + > + } else { > + continue; > + } > + This is really ugly, but I can't think of how to solve it right now. > + // 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 = > children[child_index]->palette(); > + > widget_palette.setColor(children[child_index]->foregroundRole(), Qt::red); > + > children[child_index]->setPalette(widget_palette); > + } else { > + // Reset the color of the widget > + children[child_index]->setPalette( > QApplication::palette( children[child_index] ) ); > + } > + } > + > + // 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 = panes_iterator.value(); > + do { > + item->setExpanded(true); > + item->setDisabled(false); > + item->setTextColor(0, > QApplication::palette().color(QPalette::Active, QPalette::Text)); > + item = item->parent(); > + } while (item); > + } > + } > + > + } > +} > + > void PanelStack::itemSelected(QTreeWidgetItem * item, int) > { > // de-select the category if a child is selected > Index: src/frontends/qt4/PanelStack.h > =================================================================== > --- src/frontends/qt4/PanelStack.h (revisione 38358) > +++ src/frontends/qt4/PanelStack.h (copia locale) > @@ -19,6 +19,7 @@ > class QTreeWidget; > class QTreeWidgetItem; > class QStackedWidget; > +class QLineEdit; I guess we try to sort this as well. Vincent