"Find cell" feature: just type into the cell list

This feature includes:
 * Enhancements to tl::GlobPattern
   (exact mode, case insensitive)
   TODO: UTF8 support
 * Enhancements to DecoratedLineEdit
   (ESC key handling, Tab key handling)
This commit is contained in:
Matthias Koefferlein 2017-02-28 22:24:14 +01:00
parent 8e22d7bba8
commit bf15e46c10
12 changed files with 801 additions and 237 deletions

View File

@ -74,3 +74,6 @@ plugins.depends += lay ext lib ut
klayout_main.depends += lay ext lib plugins klayout_main.depends += lay ext lib plugins
unit_tests.depends += ut plugins unit_tests.depends += ut plugins
RESOURCES += \
laybasic/layResources.qrc

View File

@ -1,7 +1,8 @@
<ui version="4.0" > <?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SimpleCellSelectionForm</class> <class>SimpleCellSelectionForm</class>
<widget class="QDialog" name="SimpleCellSelectionForm" > <widget class="QDialog" name="SimpleCellSelectionForm">
<property name="geometry" > <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
@ -9,40 +10,58 @@
<height>525</height> <height>525</height>
</rect> </rect>
</property> </property>
<property name="windowTitle" > <property name="windowTitle">
<string>Select Cell</string> <string>Select Cell</string>
</property> </property>
<layout class="QVBoxLayout" > <layout class="QVBoxLayout">
<property name="margin" > <property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>9</number> <number>9</number>
</property> </property>
<property name="spacing" > <property name="topMargin">
<number>6</number> <number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property> </property>
<item> <item>
<widget class="QFrame" name="frame8" > <widget class="QFrame" name="frame8">
<property name="frameShape" > <property name="frameShape">
<enum>QFrame::NoFrame</enum> <enum>QFrame::NoFrame</enum>
</property> </property>
<property name="frameShadow" > <property name="frameShadow">
<enum>QFrame::Raised</enum> <enum>QFrame::Raised</enum>
</property> </property>
<layout class="QGridLayout" > <layout class="QGridLayout">
<property name="margin" > <property name="leftMargin">
<number>0</number> <number>0</number>
</property> </property>
<property name="spacing" > <property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>6</number> <number>6</number>
</property> </property>
<item row="1" column="0" colspan="2" > <item row="1" column="0" colspan="2">
<spacer> <spacer>
<property name="orientation" > <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>
</property> </property>
<property name="sizeType" > <property name="sizeType">
<enum>QSizePolicy::Fixed</enum> <enum>QSizePolicy::Fixed</enum>
</property> </property>
<property name="sizeHint" > <property name="sizeHint" stdset="0">
<size> <size>
<width>451</width> <width>451</width>
<height>16</height> <height>16</height>
@ -50,62 +69,70 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="0" column="0" colspan="2" > <item row="0" column="0" colspan="2">
<widget class="QFrame" name="frame_4" > <widget class="QFrame" name="frame_4">
<property name="frameShape" > <property name="frameShape">
<enum>QFrame::NoFrame</enum> <enum>QFrame::NoFrame</enum>
</property> </property>
<property name="frameShadow" > <property name="frameShadow">
<enum>QFrame::Raised</enum> <enum>QFrame::Raised</enum>
</property> </property>
<layout class="QGridLayout" > <layout class="QGridLayout">
<property name="margin" > <property name="leftMargin">
<number>0</number> <number>0</number>
</property> </property>
<property name="spacing" > <property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>6</number> <number>6</number>
</property> </property>
<item row="0" column="1" > <item row="0" column="1">
<widget class="QLineEdit" name="le_cell_name" > <widget class="QLineEdit" name="le_cell_name">
<property name="sizePolicy" > <property name="sizePolicy">
<sizepolicy> <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<hsizetype>7</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>1</horstretch> <horstretch>1</horstretch>
<verstretch>1</verstretch> <verstretch>1</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="3" > <item row="0" column="3">
<widget class="QLabel" name="label_5" > <widget class="QLabel" name="label_5">
<property name="text" > <property name="text">
<string>(* and ? can be used to match any text)</string> <string>(* and ? can be used to match any text)</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="0" > <item row="0" column="0">
<widget class="QLabel" name="label_2" > <widget class="QLabel" name="label_2">
<property name="text" > <property name="text">
<string>Selected cell</string> <string>Selected cell</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="2" > <item row="0" column="2">
<widget class="QToolButton" name="find_next" > <widget class="QToolButton" name="find_next">
<property name="toolTip" > <property name="toolTip">
<string>&lt;html>&lt;head>&lt;meta name="qrichtext" content="1" />&lt;style type="text/css"> <string>&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; } p, li { white-space: pre-wrap; }
&lt;/style>&lt;/head>&lt;body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;"> &lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;&quot;&gt;
&lt;p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Find next&lt;/p>&lt;/body>&lt;/html></string> &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Find next&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="text" > <property name="text">
<string>...</string> <string>...</string>
</property> </property>
<property name="icon" > <property name="icon">
<iconset resource="layResources.qrc" >:/find.png</iconset> <iconset resource="../lay/layResources.qrc">
<normaloff>:/find.png</normaloff>:/find.png</iconset>
</property> </property>
<property name="autoRaise" > <property name="autoRaise">
<bool>true</bool> <bool>true</bool>
</property> </property>
</widget> </widget>
@ -113,83 +140,95 @@ p, li { white-space: pre-wrap; }
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="2" column="0" colspan="2" > <item row="2" column="0" colspan="2">
<widget class="QLabel" name="label_3" > <widget class="QLabel" name="label_3">
<property name="text" > <property name="text">
<string>Cell list</string> <string>Cell list</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0" > <item row="3" column="0">
<widget class="QTreeView" name="lv_cells" > <widget class="QTreeView" name="lv_cells">
<property name="sizePolicy" > <property name="sizePolicy">
<sizepolicy> <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<hsizetype>5</hsizetype>
<vsizetype>7</vsizetype>
<horstretch>1</horstretch> <horstretch>1</horstretch>
<verstretch>1</verstretch> <verstretch>1</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="selectionMode" > <property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum> <enum>QAbstractItemView::ExtendedSelection</enum>
</property> </property>
<property name="uniformRowHeights" > <property name="uniformRowHeights">
<bool>true</bool> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1" > <item row="3" column="1">
<widget class="QFrame" name="frame" > <widget class="QFrame" name="frame">
<property name="sizePolicy" > <property name="sizePolicy">
<sizepolicy> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<hsizetype>5</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>1</horstretch> <horstretch>1</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="frameShape" > <property name="frameShape">
<enum>QFrame::NoFrame</enum> <enum>QFrame::NoFrame</enum>
</property> </property>
<property name="frameShadow" > <property name="frameShadow">
<enum>QFrame::Raised</enum> <enum>QFrame::Raised</enum>
</property> </property>
<layout class="QVBoxLayout" > <layout class="QVBoxLayout">
<property name="margin" > <property name="spacing">
<number>0</number>
</property>
<property name="spacing" >
<number>6</number> <number>6</number>
</property> </property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item> <item>
<widget class="QFrame" name="frame_5" > <widget class="QFrame" name="frame_5">
<property name="sizePolicy" > <property name="sizePolicy">
<sizepolicy> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<hsizetype>5</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>1</horstretch> <horstretch>1</horstretch>
<verstretch>1</verstretch> <verstretch>1</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="frameShape" > <property name="frameShape">
<enum>QFrame::NoFrame</enum> <enum>QFrame::NoFrame</enum>
</property> </property>
<property name="frameShadow" > <property name="frameShadow">
<enum>QFrame::Raised</enum> <enum>QFrame::Raised</enum>
</property> </property>
<layout class="QGridLayout" > <layout class="QGridLayout">
<property name="margin" > <property name="leftMargin">
<number>0</number> <number>0</number>
</property> </property>
<property name="spacing" > <property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>6</number> <number>6</number>
</property> </property>
<item row="2" column="1" > <item row="2" column="1">
<spacer> <spacer>
<property name="orientation" > <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="sizeHint" > <property name="sizeHint" stdset="0">
<size> <size>
<width>40</width> <width>40</width>
<height>20</height> <height>20</height>
@ -197,50 +236,46 @@ p, li { white-space: pre-wrap; }
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="1" column="1" colspan="2" > <item row="1" column="1" colspan="2">
<widget class="QTreeView" name="lv_parents" > <widget class="QTreeView" name="lv_parents">
<property name="sizePolicy" > <property name="sizePolicy">
<sizepolicy> <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<hsizetype>7</hsizetype>
<vsizetype>7</vsizetype>
<horstretch>1</horstretch> <horstretch>1</horstretch>
<verstretch>1</verstretch> <verstretch>1</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="uniformRowHeights" > <property name="uniformRowHeights">
<bool>true</bool> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1" colspan="2" > <item row="0" column="1" colspan="2">
<widget class="QLabel" name="textLabel1" > <widget class="QLabel" name="textLabel1">
<property name="text" > <property name="text">
<string>Parents</string> <string>Parents</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="2" > <item row="2" column="2">
<widget class="QToolButton" name="tb_set_parent" > <widget class="QToolButton" name="tb_set_parent">
<property name="sizePolicy" > <property name="sizePolicy">
<sizepolicy> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<hsizetype>5</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="text" > <property name="text">
<string>Select</string> <string>Select</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="0" > <item row="0" column="0">
<widget class="QLabel" name="label" > <widget class="QLabel" name="label">
<property name="text" > <property name="text">
<string/> <string/>
</property> </property>
<property name="pixmap" > <property name="pixmap">
<pixmap resource="layResources.qrc" >:/right.png</pixmap> <pixmap resource="../lay/layResources.qrc">:/right.png</pixmap>
</property> </property>
</widget> </widget>
</item> </item>
@ -248,34 +283,41 @@ p, li { white-space: pre-wrap; }
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QFrame" name="frame_6" > <widget class="QFrame" name="frame_6">
<property name="sizePolicy" > <property name="sizePolicy">
<sizepolicy> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<hsizetype>5</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>1</horstretch> <horstretch>1</horstretch>
<verstretch>1</verstretch> <verstretch>1</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="frameShape" > <property name="frameShape">
<enum>QFrame::NoFrame</enum> <enum>QFrame::NoFrame</enum>
</property> </property>
<property name="frameShadow" > <property name="frameShadow">
<enum>QFrame::Raised</enum> <enum>QFrame::Raised</enum>
</property> </property>
<layout class="QGridLayout" > <layout class="QGridLayout">
<property name="margin" > <property name="leftMargin">
<number>0</number> <number>0</number>
</property> </property>
<property name="spacing" > <property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>6</number> <number>6</number>
</property> </property>
<item row="2" column="1" > <item row="2" column="1">
<spacer> <spacer>
<property name="orientation" > <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="sizeHint" > <property name="sizeHint" stdset="0">
<size> <size>
<width>40</width> <width>40</width>
<height>20</height> <height>20</height>
@ -283,50 +325,46 @@ p, li { white-space: pre-wrap; }
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="0" column="1" > <item row="0" column="1">
<widget class="QLabel" name="textLabel2" > <widget class="QLabel" name="textLabel2">
<property name="text" > <property name="text">
<string>Children</string> <string>Children</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1" colspan="2" > <item row="1" column="1" colspan="2">
<widget class="QTreeView" name="lv_children" > <widget class="QTreeView" name="lv_children">
<property name="sizePolicy" > <property name="sizePolicy">
<sizepolicy> <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<hsizetype>7</hsizetype>
<vsizetype>7</vsizetype>
<horstretch>1</horstretch> <horstretch>1</horstretch>
<verstretch>1</verstretch> <verstretch>1</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="uniformRowHeights" > <property name="uniformRowHeights">
<bool>true</bool> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="2" > <item row="2" column="2">
<widget class="QToolButton" name="tb_set_child" > <widget class="QToolButton" name="tb_set_child">
<property name="sizePolicy" > <property name="sizePolicy">
<sizepolicy> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<hsizetype>5</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="text" > <property name="text">
<string>Select</string> <string>Select</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="0" > <item row="0" column="0">
<widget class="QLabel" name="label_4" > <widget class="QLabel" name="label_4">
<property name="text" > <property name="text">
<string/> <string/>
</property> </property>
<property name="pixmap" > <property name="pixmap">
<pixmap resource="layResources.qrc" >:/right.png</pixmap> <pixmap resource="../lay/layResources.qrc">:/right.png</pixmap>
</property> </property>
</widget> </widget>
</item> </item>
@ -341,13 +379,13 @@ p, li { white-space: pre-wrap; }
</item> </item>
<item> <item>
<spacer> <spacer>
<property name="orientation" > <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>
</property> </property>
<property name="sizeType" > <property name="sizeType">
<enum>QSizePolicy::Fixed</enum> <enum>QSizePolicy::Fixed</enum>
</property> </property>
<property name="sizeHint" > <property name="sizeHint" stdset="0">
<size> <size>
<width>611</width> <width>611</width>
<height>16</height> <height>16</height>
@ -356,36 +394,45 @@ p, li { white-space: pre-wrap; }
</spacer> </spacer>
</item> </item>
<item> <item>
<widget class="Line" name="line_4" > <widget class="Line" name="line_4">
<property name="orientation" > <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QFrame" name="frame5" > <widget class="QFrame" name="frame5">
<property name="frameShape" > <property name="frameShape">
<enum>QFrame::NoFrame</enum> <enum>QFrame::NoFrame</enum>
</property> </property>
<property name="frameShadow" > <property name="frameShadow">
<enum>QFrame::Raised</enum> <enum>QFrame::Raised</enum>
</property> </property>
<layout class="QHBoxLayout" > <layout class="QHBoxLayout">
<property name="margin" > <property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number> <number>0</number>
</property> </property>
<property name="spacing" > <property name="topMargin">
<number>6</number> <number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property> </property>
<item> <item>
<spacer> <spacer>
<property name="orientation" > <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="sizeType" > <property name="sizeType">
<enum>QSizePolicy::Expanding</enum> <enum>QSizePolicy::Expanding</enum>
</property> </property>
<property name="sizeHint" > <property name="sizeHint" stdset="0">
<size> <size>
<width>91</width> <width>91</width>
<height>31</height> <height>31</height>
@ -394,19 +441,19 @@ p, li { white-space: pre-wrap; }
</spacer> </spacer>
</item> </item>
<item> <item>
<widget class="QPushButton" name="ok_button" > <widget class="QPushButton" name="ok_button">
<property name="text" > <property name="text">
<string>_ok</string> <string>Ok</string>
</property> </property>
<property name="default" > <property name="default">
<bool>true</bool> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QPushButton" name="cancel_button" > <widget class="QPushButton" name="cancel_button">
<property name="text" > <property name="text">
<string>_cancel</string> <string>Cancel</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -415,9 +462,9 @@ p, li { white-space: pre-wrap; }
</item> </item>
</layout> </layout>
</widget> </widget>
<layoutdefault spacing="6" margin="11" /> <layoutdefault spacing="6" margin="11"/>
<resources> <resources>
<include location="layResources.qrc" /> <include location="../lay/layResources.qrc"/>
</resources> </resources>
<connections/> <connections/>
</ui> </ui>

View File

@ -394,19 +394,23 @@ CellSelectionForm::name_changed (const QString &s)
return; return;
} }
QModelIndex mi = model->locate (tl::to_string (s).c_str (), true); QModelIndex mi;
if (mi.isValid ()) { if (!s.isEmpty ()) {
mi = model->locate (tl::to_string (s).c_str (), true);
} else {
model->clear_locate ();
}
m_cells_cb_enabled = false; m_cells_cb_enabled = false;
lv_cells->selectionModel ()->setCurrentIndex (mi, QItemSelectionModel::SelectCurrent); lv_cells->selectionModel ()->setCurrentIndex (mi, QItemSelectionModel::SelectCurrent);
if (mi.isValid ()) {
lv_cells->scrollTo (mi); lv_cells->scrollTo (mi);
}
update_children_list (); update_children_list ();
update_parents_list (); update_parents_list ();
m_cells_cb_enabled = true; m_cells_cb_enabled = true;
} }
}
} }
void void

View File

@ -27,6 +27,7 @@
#include "dbPCellHeader.h" #include "dbPCellHeader.h"
#include <QTreeView> #include <QTreeView>
#include <QPalette>
#include <QMimeData> #include <QMimeData>
#include <string.h> #include <string.h>
@ -314,23 +315,25 @@ CellTreeModel::build_top_level ()
m_flat = true; // no "hierarchical children" yet. m_flat = true; // no "hierarchical children" yet.
if (mp_base) {
m_toplevel.reserve (mp_base->child_cells ()); m_toplevel.reserve (mp_base->child_cells ());
for (db::Cell::child_cell_iterator child = mp_base->begin_child_cells (); ! child.at_end (); ++child) { for (db::Cell::child_cell_iterator child = mp_base->begin_child_cells (); ! child.at_end (); ++child) {
CellTreeItem *item = new CellTreeItem (mp_layout, 0, false, *child, true, m_sorting); CellTreeItem *item = new CellTreeItem (mp_layout, 0, false, *child, true, m_sorting);
m_toplevel.push_back (item); m_toplevel.push_back (item);
} }
}
} else if ((m_flags & Parents) != 0) { } else if ((m_flags & Parents) != 0) {
m_flat = true; // no "hierarchical parents" yet. m_flat = true; // no "hierarchical parents" yet.
if (mp_base) {
m_toplevel.reserve (mp_base->parent_cells ()); m_toplevel.reserve (mp_base->parent_cells ());
for (db::Cell::parent_cell_iterator parent = mp_base->begin_parent_cells (); parent != mp_base->end_parent_cells (); ++parent) { for (db::Cell::parent_cell_iterator parent = mp_base->begin_parent_cells (); parent != mp_base->end_parent_cells (); ++parent) {
CellTreeItem *item = new CellTreeItem (mp_layout, 0, false, *parent, true, m_sorting); CellTreeItem *item = new CellTreeItem (mp_layout, 0, false, *parent, true, m_sorting);
m_toplevel.push_back (item); m_toplevel.push_back (item);
} }
}
} else { } else {
@ -498,8 +501,12 @@ CellTreeModel::data (const QModelIndex &index, int role) const
} else if (role == Qt::BackgroundRole) { } else if (role == Qt::BackgroundRole) {
if (m_selected_indexes.find (index) != m_selected_indexes.end ()) { if (m_selected_indexes_set.find (index) != m_selected_indexes_set.end ()) {
return QVariant (QColor (Qt::blue).lighter (180)); // for selected items pick a color between Highlight and Base
QPalette pl (mp_parent->palette ());
QColor c1 = pl.color (QPalette::Highlight);
QColor cb = pl.color (QPalette::Base);
return QVariant (QColor ((c1.red () + cb.red ()) / 2, (c1.green () + cb.green ()) / 2, (c1.blue () + cb.blue ()) / 2));
} else { } else {
return QVariant (); return QVariant ();
} }
@ -512,11 +519,11 @@ CellTreeModel::data (const QModelIndex &index, int role) const
} else { } else {
QPalette pl (mp_parent->palette ()); QPalette pl (mp_parent->palette ());
if (mp_view->is_cell_hidden (item->cell_index (), m_cv_index)) { if (mp_view->is_cell_hidden (item->cell_index (), m_cv_index)) {
QColor c1 = pl.color (QColorGroup::Text); QColor c1 = pl.color (QPalette::Text);
QColor cb = pl.color (QColorGroup::Base); QColor cb = pl.color (QPalette::Base);
return QVariant (QColor ((c1.red () + cb.red ()) / 2, (c1.green () + cb.green ()) / 2, (c1.blue () + cb.blue ()) / 2)); return QVariant (QColor ((c1.red () + cb.red ()) / 2, (c1.green () + cb.green ()) / 2, (c1.blue () + cb.blue ()) / 2));
} else { } else {
return QVariant (pl.color (QColorGroup::Text)); return QVariant (pl.color (QPalette::Text));
} }
} }
#else #else
@ -693,6 +700,7 @@ CellTreeModel::clear_locate ()
{ {
m_selected_indexes.clear (); m_selected_indexes.clear ();
m_current_index = m_selected_indexes.begin (); m_current_index = m_selected_indexes.begin ();
m_selected_indexes_set.clear ();
signal_data_changed (); signal_data_changed ();
} }
@ -716,7 +724,55 @@ CellTreeModel::locate_next ()
} }
QModelIndex QModelIndex
CellTreeModel::locate (const char *name, bool glob_pattern) CellTreeModel::locate_prev ()
{
if (mp_layout->under_construction () || (mp_layout->manager () && mp_layout->manager ()->transacting ())) {
return QModelIndex ();
}
if (m_current_index == m_selected_indexes.end ()) {
return QModelIndex ();
} else {
if (m_current_index == m_selected_indexes.begin ()) {
m_current_index = m_selected_indexes.end ();
}
--m_current_index;
return *m_current_index;
}
}
void
CellTreeModel::search_children (const tl::GlobPattern &pattern, CellTreeItem *item)
{
int children = item->children ();
for (int i = 0; i < children; ++i) {
CellTreeItem *c = item->child (i);
if (c) {
if (c->name_matches (pattern)) {
m_selected_indexes.push_back (model_index (c));
}
search_children (pattern, c);
}
}
}
void
CellTreeModel::search_children (const char *name, CellTreeItem *item)
{
int children = item->children ();
for (int i = 0; i < children; ++i) {
CellTreeItem *c = item->child (i);
if (c) {
if (c->name_equals (name)) {
m_selected_indexes.push_back (model_index (c));
}
search_children (name, c);
}
}
}
QModelIndex
CellTreeModel::locate (const char *name, bool glob_pattern, bool case_sensitive, bool top_only)
{ {
if (mp_layout->under_construction () || (mp_layout->manager () && mp_layout->manager ()->transacting ())) { if (mp_layout->under_construction () || (mp_layout->manager () && mp_layout->manager ()->transacting ())) {
return QModelIndex (); return QModelIndex ();
@ -724,26 +780,23 @@ CellTreeModel::locate (const char *name, bool glob_pattern)
m_selected_indexes.clear (); m_selected_indexes.clear ();
std::vector <CellTreeItem *>::const_iterator lc; tl::GlobPattern p = tl::GlobPattern (std::string (name));
if (m_sorting == ByName && ! glob_pattern) { p.set_case_sensitive (case_sensitive);
// employ sorting to look for the cell with that name p.set_exact (!glob_pattern);
lc = std::lower_bound (m_toplevel.begin (), m_toplevel.end (), name, cmp_cell_tree_item_vs_name_f ()); p.set_header_match (true);
} else if (glob_pattern) {
tl::GlobPattern p (std::string (name) + "*"); for (std::vector <CellTreeItem *>::const_iterator lc = m_toplevel.begin (); lc != m_toplevel.end (); ++lc) {
for (lc = m_toplevel.begin (); lc != m_toplevel.end (); ++lc) {
if ((*lc)->name_matches (p)) { if ((*lc)->name_matches (p)) {
m_selected_indexes.insert (model_index (*lc)); m_selected_indexes.push_back (model_index (*lc));
} }
} if (! top_only) {
} else { search_children (p, *lc);
// sorting does not help: linear search
for (lc = m_toplevel.begin (); lc != m_toplevel.end (); ++lc) {
if ((*lc)->name_equals (name)) {
m_selected_indexes.insert (model_index (*lc));
}
} }
} }
m_selected_indexes_set.clear ();
m_selected_indexes_set.insert (m_selected_indexes.begin (), m_selected_indexes.end ());
signal_data_changed (); signal_data_changed ();
m_current_index = m_selected_indexes.begin (); m_current_index = m_selected_indexes.begin ();

View File

@ -168,16 +168,21 @@ public:
/** /**
* @brief Locate an index by name (at least closest) * @brief Locate an index by name (at least closest)
* *
* Only top-level items are searched. An invalid model index is returned if * If top_only is set, only top-level items are searched. An invalid model index is returned if
* no corresponding item could be found. * no corresponding item could be found.
*/ */
QModelIndex locate (const char *name, bool glob_pattern = false); QModelIndex locate (const char *name, bool glob_pattern = false, bool case_sensitive = true, bool top_only = true);
/** /**
* @brief Locate the next index (after the first locate) * @brief Locate the next index (after the first locate)
*/ */
QModelIndex locate_next (); QModelIndex locate_next ();
/**
* @brief Locate the previous index (after the first locate)
*/
QModelIndex locate_prev ();
/** /**
* @brief Clears the locate flags * @brief Clears the locate flags
*/ */
@ -226,11 +231,14 @@ private:
int m_cv_index; int m_cv_index;
const db::Cell *mp_base; const db::Cell *mp_base;
std::vector <CellTreeItem *> m_toplevel; std::vector <CellTreeItem *> m_toplevel;
std::set <QModelIndex> m_selected_indexes; std::set <QModelIndex> m_selected_indexes_set;
std::set <QModelIndex>::const_iterator m_current_index; std::vector <QModelIndex> m_selected_indexes;
std::vector <QModelIndex>::const_iterator m_current_index;
void build_top_level (); void build_top_level ();
void clear_top_level (); void clear_top_level ();
void search_children (const tl::GlobPattern &pattern, CellTreeItem *item);
void search_children (const char *name, CellTreeItem *item);
}; };
/** /**

View File

@ -34,6 +34,7 @@
#include <QFrame> #include <QFrame>
#include <QLabel> #include <QLabel>
#include <QToolButton> #include <QToolButton>
#include <QCheckBox>
#include "dbClipboard.h" #include "dbClipboard.h"
#include "dbClipboardData.h" #include "dbClipboardData.h"
@ -69,13 +70,39 @@ HCPCellTreeWidget::HCPCellTreeWidget (QWidget *parent, const char *name)
: QTreeView (parent) : QTreeView (parent)
{ {
// Don't request focus: this leaves focus on the canvas and the arrow keys functional there // Don't request focus: this leaves focus on the canvas and the arrow keys functional there
setFocusPolicy (Qt::NoFocus); // @@@ setFocusPolicy (Qt::NoFocus); -> solve differently!!!
setFocusPolicy (Qt::ClickFocus);
// Allow dragging from here to // Allow dragging from here to
setDragDropMode (QAbstractItemView::DragOnly); setDragDropMode (QAbstractItemView::DragOnly);
setObjectName (QString::fromUtf8 (name)); setObjectName (QString::fromUtf8 (name));
} }
bool
HCPCellTreeWidget::event (QEvent *event)
{
// Handling this event makes the widget receive all keystrokes
if (event->type () == QEvent::ShortcutOverride) {
QKeyEvent *ke = static_cast<QKeyEvent *> (event);
QString t = ke->text ();
if (!t.isEmpty () && t[0].isPrint ()) {
ke->accept ();
}
}
return QTreeView::event (event);
}
void
HCPCellTreeWidget::keyPressEvent (QKeyEvent *event)
{
QString t = event->text ();
if (!t.isEmpty ()) {
emit search_triggered (t);
}
}
void void
HCPCellTreeWidget::startDrag (Qt::DropActions supportedActions) HCPCellTreeWidget::startDrag (Qt::DropActions supportedActions)
{ {
@ -216,6 +243,71 @@ HierarchyControlPanel::HierarchyControlPanel (lay::LayoutView *view, QWidget *pa
mp_selector->setObjectName (QString::fromUtf8 ("cellview_selection")); mp_selector->setObjectName (QString::fromUtf8 ("cellview_selection"));
ly->addWidget (mp_selector); ly->addWidget (mp_selector);
mp_search_frame = new QFrame (this);
ly->addWidget (mp_search_frame);
mp_search_frame->hide ();
mp_search_frame->setAutoFillBackground (true);
mp_search_frame->setObjectName (QString::fromUtf8 ("panel"));
mp_search_frame->setFrameStyle (QFrame::Panel | QFrame::Raised);
mp_search_frame->setLineWidth (1);
mp_search_frame->setBackgroundRole (QPalette::Highlight);
QHBoxLayout *sf_ly = new QHBoxLayout (mp_search_frame);
sf_ly->setMargin (0);
sf_ly->setContentsMargins (0, 0, 0, 0);
sf_ly->setSpacing (0);
mp_search_close_cb = new QCheckBox (mp_search_frame);
sf_ly->addWidget (mp_search_close_cb);
mp_search_close_cb->setFocusPolicy (Qt::NoFocus);
mp_search_close_cb->setBackgroundRole (QPalette::Highlight);
mp_search_close_cb->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Preferred));
QPalette pl (mp_search_close_cb->palette ());
pl.setColor (QPalette::Foreground, pl.color (QPalette::Active, QPalette::HighlightedText));
mp_search_close_cb->setPalette (pl);
mp_search_close_cb->setMaximumSize (QSize (mp_search_close_cb->maximumSize ().width (), mp_search_close_cb->sizeHint ().height () - 4));
connect (mp_search_close_cb, SIGNAL (clicked ()), this, SLOT (search_editing_finished ()));
mp_search_model = 0;
mp_search_edit_box = new lay::DecoratedLineEdit (mp_search_frame);
mp_search_edit_box->setObjectName (QString::fromUtf8 ("cellview_search_edit_box"));
mp_search_edit_box->set_escape_signal_enabled (true);
mp_search_edit_box->set_tab_signal_enabled (true);
connect (mp_search_edit_box, SIGNAL (returnPressed ()), this, SLOT (search_editing_finished ()));
connect (mp_search_edit_box, SIGNAL (textEdited (const QString &)), this, SLOT (search_edited ()));
connect (mp_search_edit_box, SIGNAL (esc_pressed ()), this, SLOT (search_editing_finished ()));
connect (mp_search_edit_box, SIGNAL (tab_pressed ()), this, SLOT (search_next ()));
connect (mp_search_edit_box, SIGNAL (backtab_pressed ()), this, SLOT (search_prev ()));
sf_ly->addWidget (mp_search_edit_box);
mp_use_regular_expressions = new QAction (this);
mp_use_regular_expressions->setCheckable (true);
mp_use_regular_expressions->setChecked (true);
mp_use_regular_expressions->setText (tr ("Use expressions (use * and ? for any character)"));
mp_case_sensitive = new QAction (this);
mp_case_sensitive->setCheckable (true);
mp_case_sensitive->setChecked (true);
mp_case_sensitive->setText (tr ("Case sensitive search"));
QMenu *m = new QMenu (mp_search_edit_box);
m->addAction (mp_use_regular_expressions);
m->addAction (mp_case_sensitive);
connect (mp_use_regular_expressions, SIGNAL (triggered ()), this, SLOT (search_edited ()));
connect (mp_case_sensitive, SIGNAL (triggered ()), this, SLOT (search_edited ()));
mp_search_edit_box->set_clear_button_enabled (true);
mp_search_edit_box->set_options_button_enabled (true);
mp_search_edit_box->set_options_menu (m);
QToolButton *sf_next = new QToolButton (mp_search_frame);
sf_next->setAutoRaise (true);
sf_next->setToolTip (tr ("Find next"));
sf_next->setIcon (QIcon (QString::fromUtf8 (":/find.png")));
connect (sf_next, SIGNAL (clicked ()), this, SLOT (search_next ()));
sf_ly->addWidget (sf_next);
mp_splitter = new QSplitter (Qt::Vertical, this); mp_splitter = new QSplitter (Qt::Vertical, this);
ly->addWidget (mp_splitter); ly->addWidget (mp_splitter);
@ -335,6 +427,105 @@ HierarchyControlPanel::cm_cell_select ()
emit cell_selected (path, active ()); emit cell_selected (path, active ());
} }
void
HierarchyControlPanel::search_triggered (const QString &t)
{
mp_search_model = 0;
lay::HCPCellTreeWidget *w = dynamic_cast<lay::HCPCellTreeWidget *> (sender ());
if (w) {
for (size_t i = 0; i < mp_cell_lists.size (); ++i) {
if (mp_cell_lists [i] == w) {
// Switch the active list for split mode -> CAUTION: this may trigger a search_editing_finished call
select_active (int (i));
mp_search_model = dynamic_cast<lay::CellTreeModel *> (w->model ());
break;
}
}
}
if (mp_search_model) {
mp_search_close_cb->setChecked (true);
mp_search_frame->show ();
mp_search_edit_box->setText (t);
mp_search_edit_box->setFocus ();
search_edited ();
}
}
void
HierarchyControlPanel::search_edited ()
{
QString t = mp_search_edit_box->text ();
for (std::vector <QTreeView *>::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) {
if ((*v)->model () == mp_search_model) {
if (t.isEmpty ()) {
mp_search_model->clear_locate ();
(*v)->setCurrentIndex (QModelIndex ());
} else {
QModelIndex found = mp_search_model->locate (t.toUtf8 ().constData (), mp_use_regular_expressions->isChecked (), mp_case_sensitive->isChecked (), false);
(*v)->setCurrentIndex (found);
if (found.isValid ()) {
(*v)->scrollTo (found);
}
}
break;
}
}
}
void
HierarchyControlPanel::search_next ()
{
for (std::vector <QTreeView *>::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) {
if ((*v)->model () == mp_search_model) {
QModelIndex found = mp_search_model->locate_next ();
if (found.isValid ()) {
(*v)->setCurrentIndex (found);
(*v)->scrollTo (found);
}
break;
}
}
}
void
HierarchyControlPanel::search_prev ()
{
for (std::vector <QTreeView *>::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) {
if ((*v)->model () == mp_search_model) {
QModelIndex found = mp_search_model->locate_prev ();
if (found.isValid ()) {
(*v)->setCurrentIndex (found);
(*v)->scrollTo (found);
}
break;
}
}
}
void
HierarchyControlPanel::search_editing_finished ()
{
for (std::vector <QTreeView *>::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) {
CellTreeModel *m = dynamic_cast<CellTreeModel *> ((*v)->model ());
if (m) {
m->clear_locate ();
}
}
// give back the focus to the cell list
for (size_t i = 0; i < mp_cell_lists.size (); ++i) {
if (mp_cell_lists [i]->model () == mp_search_model) {
mp_cell_lists [i]->setFocus ();
break;
}
}
mp_search_frame->hide ();
mp_search_model = 0;
}
void void
HierarchyControlPanel::middle_clicked (const QModelIndex &index) HierarchyControlPanel::middle_clicked (const QModelIndex &index)
{ {
@ -469,6 +660,13 @@ void
HierarchyControlPanel::set_background_color (QColor c) HierarchyControlPanel::set_background_color (QColor c)
{ {
m_background_color = c; m_background_color = c;
QColor hl;
if (c.green () > 128) {
hl = QColor (192, 192, 255);
} else {
hl = QColor (0, 0, 80);
}
for (std::vector <QTreeView *>::const_iterator f = mp_cell_lists.begin (); f != mp_cell_lists.end (); ++f) { for (std::vector <QTreeView *>::const_iterator f = mp_cell_lists.begin (); f != mp_cell_lists.end (); ++f) {
QPalette pl ((*f)->palette ()); QPalette pl ((*f)->palette ());
pl.setColor (QPalette::Base, c); pl.setColor (QPalette::Base, c);
@ -614,6 +812,10 @@ HierarchyControlPanel::display_string (int n) const
void void
HierarchyControlPanel::do_update_content (int cv_index) HierarchyControlPanel::do_update_content (int cv_index)
{ {
// close the search box since we will modify the model
mp_search_frame->hide ();
mp_search_model = 0;
unsigned int imin = (cv_index < 0 ? 0 : (unsigned int) cv_index); unsigned int imin = (cv_index < 0 ? 0 : (unsigned int) cv_index);
unsigned int imax = (cv_index < 0 ? std::numeric_limits <unsigned int>::max () : (unsigned int) cv_index); unsigned int imax = (cv_index < 0 ? std::numeric_limits <unsigned int>::max () : (unsigned int) cv_index);
@ -709,6 +911,7 @@ HierarchyControlPanel::do_update_content (int cv_index)
connect (cell_list, SIGNAL (cell_clicked (const QModelIndex &)), this, SLOT (clicked (const QModelIndex &))); connect (cell_list, SIGNAL (cell_clicked (const QModelIndex &)), this, SLOT (clicked (const QModelIndex &)));
connect (cell_list, SIGNAL (cell_double_clicked (const QModelIndex &)), this, SLOT (double_clicked (const QModelIndex &))); connect (cell_list, SIGNAL (cell_double_clicked (const QModelIndex &)), this, SLOT (double_clicked (const QModelIndex &)));
connect (cell_list, SIGNAL (cell_middle_clicked (const QModelIndex &)), this, SLOT (middle_clicked (const QModelIndex &))); connect (cell_list, SIGNAL (cell_middle_clicked (const QModelIndex &)), this, SLOT (middle_clicked (const QModelIndex &)));
connect (cell_list, SIGNAL (search_triggered (const QString &)), this, SLOT (search_triggered (const QString &)));
mp_cell_lists.push_back (cell_list); mp_cell_lists.push_back (cell_list);
mp_cell_list_frames.push_back (cl_frame); mp_cell_list_frames.push_back (cl_frame);

View File

@ -36,6 +36,7 @@
#include "layViewOp.h" #include "layViewOp.h"
#include "layLayoutView.h" #include "layLayoutView.h"
#include "layCellTreeModel.h" #include "layCellTreeModel.h"
#include "layWidgets.h"
#include "tlDeferredExecution.h" #include "tlDeferredExecution.h"
class QModelIndex; class QModelIndex;
@ -44,6 +45,9 @@ class QMenu;
class QSplitter; class QSplitter;
class QFrame; class QFrame;
class QToolButton; class QToolButton;
class QLineEdit;
class QAction;
class QCheckBox;
namespace lay namespace lay
{ {
@ -67,12 +71,15 @@ signals:
void cell_clicked (const QModelIndex &); void cell_clicked (const QModelIndex &);
void cell_double_clicked (const QModelIndex &); void cell_double_clicked (const QModelIndex &);
void cell_middle_clicked (const QModelIndex &); void cell_middle_clicked (const QModelIndex &);
void search_triggered (const QString &t);
protected: protected:
virtual void mouseDoubleClickEvent (QMouseEvent *event); virtual void mouseDoubleClickEvent (QMouseEvent *event);
virtual void mousePressEvent (QMouseEvent *event); virtual void mousePressEvent (QMouseEvent *event);
virtual void mouseReleaseEvent (QMouseEvent *event); virtual void mouseReleaseEvent (QMouseEvent *event);
virtual void startDrag (Qt::DropActions supportedActions); virtual void startDrag (Qt::DropActions supportedActions);
virtual void keyPressEvent (QKeyEvent *event);
virtual bool event (QEvent *event);
}; };
/** /**
@ -259,6 +266,11 @@ public slots:
void middle_clicked (const QModelIndex &index); void middle_clicked (const QModelIndex &index);
void selection_changed (int index); void selection_changed (int index);
void context_menu (const QPoint &pt); void context_menu (const QPoint &pt);
void search_triggered (const QString &t);
void search_edited ();
void search_editing_finished ();
void search_next ();
void search_prev ();
void cm_cell_select (); void cm_cell_select ();
private: private:
@ -277,6 +289,12 @@ private:
bool m_split_mode; bool m_split_mode;
CellTreeModel::Sorting m_sorting; CellTreeModel::Sorting m_sorting;
QComboBox *mp_selector; QComboBox *mp_selector;
lay::DecoratedLineEdit *mp_search_edit_box;
QAction *mp_case_sensitive;
QAction *mp_use_regular_expressions;
CellTreeModel *mp_search_model;
QFrame *mp_search_frame;
QCheckBox *mp_search_close_cb;
QSplitter *mp_splitter; QSplitter *mp_splitter;
QColor m_background_color; QColor m_background_color;
QColor m_text_color; QColor m_text_color;

View File

@ -934,7 +934,8 @@ const int le_decoration_space = 2; // additional distance between decoration ic
DecoratedLineEdit::DecoratedLineEdit (QWidget *parent) DecoratedLineEdit::DecoratedLineEdit (QWidget *parent)
: QLineEdit (parent), : QLineEdit (parent),
m_clear_button_enabled (false), m_options_button_enabled (false), mp_options_menu (0) m_clear_button_enabled (false), m_options_button_enabled (false), mp_options_menu (0),
m_escape_signal_enabled (false), m_tab_signal_enabled (false)
{ {
mp_options_label = new QLabel (this); mp_options_label = new QLabel (this);
mp_options_label->hide (); mp_options_label->hide ();
@ -957,6 +958,56 @@ DecoratedLineEdit::~DecoratedLineEdit ()
// .. nothing yet .. // .. nothing yet ..
} }
void DecoratedLineEdit::set_escape_signal_enabled (bool en)
{
m_escape_signal_enabled = en;
}
void DecoratedLineEdit::set_tab_signal_enabled (bool en)
{
m_tab_signal_enabled = en;
}
bool DecoratedLineEdit::event (QEvent *event)
{
// Handling this event makes the widget receive all keystrokes
if (event->type () == QEvent::ShortcutOverride) {
QKeyEvent *ke = static_cast<QKeyEvent *> (event);
if (ke->key () == Qt::Key_Escape && m_escape_signal_enabled) {
ke->accept ();
}
}
return QLineEdit::event (event);
}
void DecoratedLineEdit::keyPressEvent (QKeyEvent *event)
{
if (m_escape_signal_enabled && event->key () == Qt::Key_Escape) {
emit esc_pressed ();
event->accept ();
} else if (m_tab_signal_enabled && event->key () == Qt::Key_Tab) {
emit tab_pressed ();
event->accept ();
} else if (m_tab_signal_enabled && event->key () == Qt::Key_Backtab) {
emit backtab_pressed ();
event->accept ();
} else {
QLineEdit::keyPressEvent (event);
}
}
bool DecoratedLineEdit::focusNextPrevChild (bool next)
{
if (m_tab_signal_enabled && isEnabled ()) {
QKeyEvent event (QEvent::KeyPress, next ? Qt::Key_Tab : Qt::Key_Backtab, Qt::NoModifier);
keyPressEvent (&event);
if (event.isAccepted ()) {
return true;
}
}
return QLineEdit::focusNextPrevChild (next);
}
void DecoratedLineEdit::set_clear_button_enabled (bool en) void DecoratedLineEdit::set_clear_button_enabled (bool en)
{ {
if (en != m_clear_button_enabled) { if (en != m_clear_button_enabled) {

View File

@ -392,17 +392,51 @@ public:
*/ */
QMenu *options_menu () const; QMenu *options_menu () const;
/**
* @brief Sets a value indicating whether the widgets accepts ESC keys and sends an esc_pressed signal for this
*/
void set_escape_signal_enabled (bool f);
/**
* @brief gets a value indicating whether the widgets accepts ESC keys and sends an esc_pressed signal for this
*/
bool escape_signal_enabled () const
{
return m_escape_signal_enabled;
}
/**
* @brief Sets a value indicating whether the widgets accepts Tab keys and sends an tab_pressed or backtab_pressed signal for this
*/
void set_tab_signal_enabled (bool f);
/**
* @brief gets a value indicating whether the widgets accepts Tab keys and sends an tab_pressed or backtab_pressed signal for this
*/
bool tab_signal_enabled () const
{
return m_tab_signal_enabled;
}
signals: signals:
void options_button_clicked (); void options_button_clicked ();
void esc_pressed ();
void tab_pressed ();
void backtab_pressed ();
protected: protected:
void mousePressEvent (QMouseEvent *event); void mousePressEvent (QMouseEvent *event);
void mouseReleaseEvent (QMouseEvent *event); void mouseReleaseEvent (QMouseEvent *event);
void resizeEvent (QResizeEvent *event); void resizeEvent (QResizeEvent *event);
void keyPressEvent (QKeyEvent *event);
bool focusNextPrevChild (bool next);
bool event (QEvent *event);
private: private:
bool m_clear_button_enabled; bool m_clear_button_enabled;
bool m_options_button_enabled; bool m_options_button_enabled;
bool m_escape_signal_enabled;
bool m_tab_signal_enabled;
QLabel *mp_options_label; QLabel *mp_options_label;
QLabel *mp_clear_label; QLabel *mp_clear_label;
QMenu *mp_options_menu; QMenu *mp_options_menu;

View File

@ -27,11 +27,11 @@ namespace tl
{ {
static bool static bool
do_match (const char *p, const char *s, std::vector<std::string> *o, std::vector<std::pair<unsigned int, const char *> > &bstart) do_match (const char *p, const char *s, bool cs, bool exact, bool hm, std::vector<std::string> *o, std::vector<std::pair<unsigned int, const char *> > &bstart)
{ {
while (*p) { while (*p) {
if (*p == '\\') { if (!exact && *p == '\\') {
++p; ++p;
if (!*s || *s != *p) { if (!*s || *s != *p) {
@ -42,7 +42,7 @@ do_match (const char *p, const char *s, std::vector<std::string> *o, std::vector
} }
++s; ++s;
} else if (*p == '?') { } else if (!exact && *p == '?') {
++p; ++p;
if (! *s) { if (! *s) {
@ -50,7 +50,7 @@ do_match (const char *p, const char *s, std::vector<std::string> *o, std::vector
} }
++s; ++s;
} else if (*p == '*') { } else if (!exact && *p == '*') {
++p; ++p;
@ -63,7 +63,7 @@ do_match (const char *p, const char *s, std::vector<std::string> *o, std::vector
size_t no = o ? o->size () : 0; size_t no = o ? o->size () : 0;
while (*s) { while (*s) {
if (do_match (p, s, o, bstart)) { if (do_match (p, s, cs, exact, hm, o, bstart)) {
return true; return true;
} }
bstart = bs; bstart = bs;
@ -73,7 +73,7 @@ do_match (const char *p, const char *s, std::vector<std::string> *o, std::vector
++s; ++s;
} }
} else if (*p == '[') { } else if (!exact && *p == '[') {
if (! *s) { if (! *s) {
return false; return false;
@ -111,7 +111,10 @@ do_match (const char *p, const char *s, std::vector<std::string> *o, std::vector
} }
if (! hit) { if (! hit) {
if (*s >= c1 && *s <= c2) { if (cs && *s >= c1 && *s <= c2) {
hit = true;
// TODO: implement UTF-8 support
} else if (!cs && tolower (*s) >= tolower (c1) && tolower (*s) <= tolower (c2)) {
hit = true; hit = true;
} }
} }
@ -127,7 +130,7 @@ do_match (const char *p, const char *s, std::vector<std::string> *o, std::vector
++p; ++p;
} }
} else if (*p == '{') { } else if (!exact && *p == '{') {
++p; ++p;
@ -158,7 +161,10 @@ do_match (const char *p, const char *s, std::vector<std::string> *o, std::vector
if (hit) { if (hit) {
if (! *s) { if (! *s) {
hit = false; hit = false;
} else if (*p != *s) { } else if (cs && *p != *s) {
hit = false;
// TODO: implement UTF-8 support
} else if (!cs && tolower (*p) != tolower (*s)) {
hit = false; hit = false;
} else { } else {
++s; ++s;
@ -184,7 +190,7 @@ do_match (const char *p, const char *s, std::vector<std::string> *o, std::vector
return false; return false;
} }
} else if (*p == ')') { } else if (!exact && *p == ')') {
++p; ++p;
@ -195,7 +201,7 @@ do_match (const char *p, const char *s, std::vector<std::string> *o, std::vector
bstart.pop_back (); bstart.pop_back ();
} }
} else if (*p == '(') { } else if (!exact && *p == '(') {
++p; ++p;
if (o) { if (o) {
@ -203,33 +209,78 @@ do_match (const char *p, const char *s, std::vector<std::string> *o, std::vector
o->push_back (std::string ()); o->push_back (std::string ());
} }
} else if (*s != *p) { } else {
if (cs) {
if (*s != *p) {
return false; return false;
} else { } else {
++s; ++s;
++p; ++p;
} }
} else {
// TODO: implement UTF-8 support
if (tolower (*s) != tolower (*p)) {
return false;
} else {
++s;
++p;
}
}
} }
return (*s == 0); }
return (hm || *s == 0);
} }
GlobPattern::GlobPattern () GlobPattern::GlobPattern ()
: m_case_sensitive (true), m_exact (false), m_header_match (false)
{ {
// .. nothing yet .. // .. nothing yet ..
} }
GlobPattern::GlobPattern (const std::string &p) GlobPattern::GlobPattern (const std::string &p)
: m_p (p) : m_p (p), m_case_sensitive (true), m_exact (false), m_header_match (false)
{ {
// .. nothing yet .. // .. nothing yet ..
} }
void GlobPattern::set_case_sensitive (bool f)
{
m_case_sensitive = f;
}
bool GlobPattern::case_sensitive () const
{
return m_case_sensitive;
}
void GlobPattern::set_exact (bool f)
{
m_exact = f;
}
bool GlobPattern::exact () const
{
return m_exact;
}
void GlobPattern::set_header_match (bool f)
{
m_header_match = f;
}
bool GlobPattern::header_match () const
{
return m_header_match;
}
bool GlobPattern::match (const char *s) const bool GlobPattern::match (const char *s) const
{ {
std::vector<std::pair<unsigned int, const char *> > bstart; std::vector<std::pair<unsigned int, const char *> > bstart;
return do_match (m_p.c_str (), s, 0, bstart); return do_match (m_p.c_str (), s, m_case_sensitive, m_exact, m_header_match, 0, bstart);
} }
bool GlobPattern::match (const char *s, std::vector<std::string> &e) const bool GlobPattern::match (const char *s, std::vector<std::string> &e) const
@ -238,13 +289,13 @@ bool GlobPattern::match (const char *s, std::vector<std::string> &e) const
e.clear (); e.clear ();
} }
std::vector<std::pair<unsigned int, const char *> > bstart; std::vector<std::pair<unsigned int, const char *> > bstart;
return do_match (m_p.c_str (), s, &e, bstart); return do_match (m_p.c_str (), s, m_case_sensitive, m_exact, m_header_match, &e, bstart);
} }
bool GlobPattern::match (const std::string &s) const bool GlobPattern::match (const std::string &s) const
{ {
std::vector<std::pair<unsigned int, const char *> > bstart; std::vector<std::pair<unsigned int, const char *> > bstart;
return do_match (m_p.c_str (), s.c_str (), 0, bstart); return do_match (m_p.c_str (), s.c_str (), m_case_sensitive, m_exact, m_header_match, 0, bstart);
} }
bool GlobPattern::match (const std::string &s, std::vector<std::string> &e) const bool GlobPattern::match (const std::string &s, std::vector<std::string> &e) const
@ -253,7 +304,7 @@ bool GlobPattern::match (const std::string &s, std::vector<std::string> &e) cons
e.clear (); e.clear ();
} }
std::vector<std::pair<unsigned int, const char *> > bstart; std::vector<std::pair<unsigned int, const char *> > bstart;
return do_match (m_p.c_str (), s.c_str (), &e, bstart); return do_match (m_p.c_str (), s.c_str (), m_case_sensitive, m_exact, m_header_match, &e, bstart);
} }
} }

View File

@ -60,6 +60,36 @@ public:
return *this; return *this;
} }
/**
* @brief Sets a value indicating whether to treat the match case sensitive
*/
void set_case_sensitive (bool f);
/**
* @brief Gets a value indicating whether to treat the match case sensitive
*/
bool case_sensitive () const;
/**
* @brief Sets a value indicating whether to match exact (without brackets and wildcards)
*/
void set_exact (bool f);
/**
* @brief Gets a value indicating whether to match exact (without brackets and wildcards)
*/
bool exact () const;
/**
* @brief Sets a value indicating whether to allow trailing characters in the subject
*/
void set_header_match (bool f);
/**
* @brief Gets a value indicating whether to allow trailing characters in the subject
*/
bool header_match () const;
/** /**
* @brief Get the pattern string * @brief Get the pattern string
*/ */
@ -94,6 +124,9 @@ public:
private: private:
std::string m_p; std::string m_p;
bool m_case_sensitive;
bool m_exact;
bool m_header_match;
}; };
} // namespace tl } // namespace tl

View File

@ -134,5 +134,64 @@ TEST(7)
EXPECT_EQ (v[2], ""); EXPECT_EQ (v[2], "");
} }
TEST(8)
{
// case insensitive
tl::GlobPattern a ("(*({bc,d}))(*)");
std::vector <std::string> v;
EXPECT_EQ (a.case_sensitive (), true);
EXPECT_EQ (a.match ("aBcG", v), false);
a.set_case_sensitive (false);
EXPECT_EQ (a.case_sensitive (), false);
EXPECT_EQ (a.match ("aBcG", v), true);
EXPECT_EQ (v.size (), 3);
EXPECT_EQ (v[0], "aBc");
EXPECT_EQ (v[1], "Bc");
EXPECT_EQ (v[2], "G");
tl::GlobPattern b ("*a[bcd]");
EXPECT_EQ (b.match ("ab"), true);
EXPECT_EQ (b.match ("Ab"), false);
EXPECT_EQ (b.match ("aB"), false);
b.set_case_sensitive (false);
EXPECT_EQ (b.match ("ab"), true);
EXPECT_EQ (b.match ("Ab"), true);
EXPECT_EQ (b.match ("aB"), true);
}
TEST(9)
{
// exact match
tl::GlobPattern a ("(*({bc,d}))(*)");
a.set_exact (true);
EXPECT_EQ (a.exact (), true);
EXPECT_EQ (a.match ("abcg"), false);
EXPECT_EQ (a.match ("(*({bc,d}))(*)"), true);
EXPECT_EQ (a.match ("(*({bc,D}))(*)"), false);
a.set_case_sensitive (false);
EXPECT_EQ (a.match ("abcg"), false);
EXPECT_EQ (a.match ("(*({bc,d}))(*)"), true);
EXPECT_EQ (a.match ("(*({bc,D}))(*)"), true);
}
TEST(10)
{
// header match
tl::GlobPattern a ("abc");
EXPECT_EQ (a.match ("abcg"), false);
EXPECT_EQ (a.match ("abc"), true);
a.set_header_match (true);
EXPECT_EQ (a.header_match (), true);
EXPECT_EQ (a.match ("abcg"), true);
EXPECT_EQ (a.match ("abc"), true);
}