+class FilterItemDelegate : public QAbstractItemDelegate {
+public:
+ ///
+ explicit FilterItemDelegate(QObject * parent = 0)
+ : QAbstractItemDelegate(parent) {}
+
+ ///
+ void paint(QPainter * painter, const QStyleOptionViewItem & option,
+ const QModelIndex &index) const {
+ QComboBox * combo = static_cast<QComboBox const *>(parent());
+
+ // Draw using the menu item style (this is how QComboBox does it).
+ // But for the rich text drawing below we will call it with an
+ // empty string, and later then draw over it the real string.
+ painter->save();
+ QStyleOptionMenuItem opt = getStyleOption(option, index);
+ QString text = underlineFilter(opt.text);
+ opt.text = QString();
+ painter->eraseRect(option.rect);
+ combo->style()->drawControl(QStyle::CE_MenuItem, &opt, painter, combo->view());
+ painter->restore();
+
+ // Draw the rich text.
+ painter->save();
+ QColor col = opt.palette.text().color();
+ if (opt.state & QStyle::State_Selected)
+ col = opt.palette.highlightedText().color();
+ QAbstractTextDocumentLayout::PaintContext context;
+ context.palette.setColor(QPalette::Text, col);
+
+ QTextDocument doc;
+ doc.setDefaultFont(opt.font);
+ doc.setHtml(text);
+ painter->translate(opt.rect.x() + 20, opt.rect.y());
+ doc.documentLayout()->draw(painter, context);
+ painter->restore();
+ }
+
+ ///
+ QSize sizeHint(const QStyleOptionViewItem &option,
+ const QModelIndex &index) const {
+ QComboBox * combo = static_cast<QComboBox const *>(parent());
+
+ QStyleOptionMenuItem opt = getStyleOption(option, index);
+ return combo->style()->sizeFromContents(
+ QStyle::CT_MenuItem, &opt, option.rect.size(), combo);
+ }
+
+private:
+ ///
+ QString underlineFilter(QString const & s) const
+ {
+ // get filter
+ GuiLayoutBox * p = static_cast<GuiLayoutBox *>(parent());
+ QString const & f = p->filter();
+ if (f.isEmpty())
+ return s;
+
+ // step through data item and put "(x)" for every matching character
+ QString r;
+ int lastp = -1;
+ p->filter();
+ for (int i = 0; i < f.length(); ++i) {
+ int p = s.indexOf(f[i], lastp + 1, Qt::CaseInsensitive);
+ BOOST_ASSERT(p != -1);
+ if (lastp == p - 1 && lastp != -1) {
+ // remove ")" and append "x)"
+ r = r.left(r.length() - 4) + s[p] + "</u>";
+ } else {
+ // append "(x)"
+ r += s.mid(lastp + 1, p - lastp - 1);
+ r += QString("<u>") + s[p] + "</u>";
+ }
+ lastp = p;
+ }
+ r += s.mid(lastp + 1);
+ return r;
+ }
+
+ ///
+ QStyleOptionMenuItem getStyleOption(const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+ {
+ QComboBox * combo = static_cast<QComboBox const *>(parent());
+
+ // create the options for a menu item
+ QStyleOptionMenuItem menuOption;
+ menuOption.palette = QApplication::palette("QMenu");
+ menuOption.state = QStyle::State_Active | QStyle::State_Enabled;
+ if (option.state & QStyle::State_Selected)
+ menuOption.state |= QStyle::State_Selected;
+ menuOption.checkType = QStyleOptionMenuItem::NonExclusive;
+ menuOption.checked = combo->currentIndex() == index.row();
+ menuOption.menuItemType = QStyleOptionMenuItem::Normal;
+ menuOption.text = index.model()->data(index, Qt::DisplayRole).toString()
+ .replace(QLatin1Char('&'), QLatin1String("&&"));
+ menuOption.tabWidth = 0;
+ menuOption.menuRect = option.rect;
+ menuOption.rect = option.rect;
+ menuOption.font = combo->font();
+ menuOption.fontMetrics = QFontMetrics(menuOption.font);
+ return menuOption;
+ }
+};
+
+
+class GuiFilterProxyModel : public QSortFilterProxyModel
+{
+public:
+ ///
+ GuiFilterProxyModel(QObject * parent)
+ : QSortFilterProxyModel(parent) {}
+
+ ///
+ void setCharFilter(QString const & f)
+ {
+ setFilterRegExp(charFilterRegExp(f));
+ dataChanged(index(0, 0), index(rowCount() - 1, 1));
+ }
+
+private:
+ ///
+ QString charFilterRegExp(QString const & filter)
+ {
+ QString re;
+ for (int i = 0; i < filter.length(); ++i)
+ re += ".*" + QRegExp::escape(filter[i]);
+ return re;
+ }
+};
+
+