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

View File

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

View File

@ -27,6 +27,7 @@
#include "dbPCellHeader.h"
#include <QTreeView>
#include <QPalette>
#include <QMimeData>
#include <string.h>
@ -314,22 +315,24 @@ CellTreeModel::build_top_level ()
m_flat = true; // no "hierarchical children" yet.
m_toplevel.reserve (mp_base->child_cells ());
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);
m_toplevel.push_back (item);
if (mp_base) {
m_toplevel.reserve (mp_base->child_cells ());
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);
m_toplevel.push_back (item);
}
}
} else if ((m_flags & Parents) != 0) {
m_flat = true; // no "hierarchical parents" yet.
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) {
CellTreeItem *item = new CellTreeItem (mp_layout, 0, false, *parent, true, m_sorting);
m_toplevel.push_back (item);
if (mp_base) {
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) {
CellTreeItem *item = new CellTreeItem (mp_layout, 0, false, *parent, true, m_sorting);
m_toplevel.push_back (item);
}
}
} else {
@ -498,8 +501,12 @@ CellTreeModel::data (const QModelIndex &index, int role) const
} else if (role == Qt::BackgroundRole) {
if (m_selected_indexes.find (index) != m_selected_indexes.end ()) {
return QVariant (QColor (Qt::blue).lighter (180));
if (m_selected_indexes_set.find (index) != m_selected_indexes_set.end ()) {
// 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 {
return QVariant ();
}
@ -512,11 +519,11 @@ CellTreeModel::data (const QModelIndex &index, int role) const
} else {
QPalette pl (mp_parent->palette ());
if (mp_view->is_cell_hidden (item->cell_index (), m_cv_index)) {
QColor c1 = pl.color (QColorGroup::Text);
QColor cb = pl.color (QColorGroup::Base);
QColor c1 = pl.color (QPalette::Text);
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 {
return QVariant (pl.color (QColorGroup::Text));
return QVariant (pl.color (QPalette::Text));
}
}
#else
@ -693,6 +700,7 @@ CellTreeModel::clear_locate ()
{
m_selected_indexes.clear ();
m_current_index = m_selected_indexes.begin ();
m_selected_indexes_set.clear ();
signal_data_changed ();
}
@ -715,8 +723,56 @@ CellTreeModel::locate_next ()
}
}
QModelIndex
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)
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 ())) {
return QModelIndex ();
@ -724,25 +780,22 @@ CellTreeModel::locate (const char *name, bool glob_pattern)
m_selected_indexes.clear ();
std::vector <CellTreeItem *>::const_iterator lc;
if (m_sorting == ByName && ! glob_pattern) {
// employ sorting to look for the cell with that name
lc = std::lower_bound (m_toplevel.begin (), m_toplevel.end (), name, cmp_cell_tree_item_vs_name_f ());
} else if (glob_pattern) {
tl::GlobPattern p (std::string (name) + "*");
for (lc = m_toplevel.begin (); lc != m_toplevel.end (); ++lc) {
if ((*lc)->name_matches (p)) {
m_selected_indexes.insert (model_index (*lc));
}
tl::GlobPattern p = tl::GlobPattern (std::string (name));
p.set_case_sensitive (case_sensitive);
p.set_exact (!glob_pattern);
p.set_header_match (true);
for (std::vector <CellTreeItem *>::const_iterator lc = m_toplevel.begin (); lc != m_toplevel.end (); ++lc) {
if ((*lc)->name_matches (p)) {
m_selected_indexes.push_back (model_index (*lc));
}
} else {
// 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));
}
if (! top_only) {
search_children (p, *lc);
}
}
m_selected_indexes_set.clear ();
m_selected_indexes_set.insert (m_selected_indexes.begin (), m_selected_indexes.end ());
signal_data_changed ();

View File

@ -168,16 +168,21 @@ public:
/**
* @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.
*/
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)
*/
QModelIndex locate_next ();
/**
* @brief Locate the previous index (after the first locate)
*/
QModelIndex locate_prev ();
/**
* @brief Clears the locate flags
*/
@ -226,11 +231,14 @@ private:
int m_cv_index;
const db::Cell *mp_base;
std::vector <CellTreeItem *> m_toplevel;
std::set <QModelIndex> m_selected_indexes;
std::set <QModelIndex>::const_iterator m_current_index;
std::set <QModelIndex> m_selected_indexes_set;
std::vector <QModelIndex> m_selected_indexes;
std::vector <QModelIndex>::const_iterator m_current_index;
void build_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 <QLabel>
#include <QToolButton>
#include <QCheckBox>
#include "dbClipboard.h"
#include "dbClipboardData.h"
@ -69,13 +70,39 @@ HCPCellTreeWidget::HCPCellTreeWidget (QWidget *parent, const char *name)
: QTreeView (parent)
{
// 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
setDragDropMode (QAbstractItemView::DragOnly);
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
HCPCellTreeWidget::startDrag (Qt::DropActions supportedActions)
{
@ -216,6 +243,71 @@ HierarchyControlPanel::HierarchyControlPanel (lay::LayoutView *view, QWidget *pa
mp_selector->setObjectName (QString::fromUtf8 ("cellview_selection"));
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);
ly->addWidget (mp_splitter);
@ -335,6 +427,105 @@ HierarchyControlPanel::cm_cell_select ()
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
HierarchyControlPanel::middle_clicked (const QModelIndex &index)
{
@ -469,6 +660,13 @@ void
HierarchyControlPanel::set_background_color (QColor 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) {
QPalette pl ((*f)->palette ());
pl.setColor (QPalette::Base, c);
@ -490,7 +688,7 @@ HierarchyControlPanel::set_text_color (QColor c)
void
HierarchyControlPanel::do_full_update_content ()
{
size_t i = 0;
size_t i = 0;
for (std::vector <lay::CellView>::const_iterator cv = m_cellviews.begin (); cv != m_cellviews.end (); ++cv, ++i) {
if (m_needs_update.size () > i) {
m_needs_update [i] = true;
@ -614,6 +812,10 @@ HierarchyControlPanel::display_string (int n) const
void
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 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_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 (search_triggered (const QString &)), this, SLOT (search_triggered (const QString &)));
mp_cell_lists.push_back (cell_list);
mp_cell_list_frames.push_back (cl_frame);

View File

@ -36,6 +36,7 @@
#include "layViewOp.h"
#include "layLayoutView.h"
#include "layCellTreeModel.h"
#include "layWidgets.h"
#include "tlDeferredExecution.h"
class QModelIndex;
@ -44,6 +45,9 @@ class QMenu;
class QSplitter;
class QFrame;
class QToolButton;
class QLineEdit;
class QAction;
class QCheckBox;
namespace lay
{
@ -67,12 +71,15 @@ signals:
void cell_clicked (const QModelIndex &);
void cell_double_clicked (const QModelIndex &);
void cell_middle_clicked (const QModelIndex &);
void search_triggered (const QString &t);
protected:
virtual void mouseDoubleClickEvent (QMouseEvent *event);
virtual void mousePressEvent (QMouseEvent *event);
virtual void mouseReleaseEvent (QMouseEvent *event);
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 selection_changed (int index);
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 ();
private:
@ -277,6 +289,12 @@ private:
bool m_split_mode;
CellTreeModel::Sorting m_sorting;
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;
QColor m_background_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)
: 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->hide ();
@ -957,6 +958,56 @@ DecoratedLineEdit::~DecoratedLineEdit ()
// .. 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)
{
if (en != m_clear_button_enabled) {

View File

@ -392,17 +392,51 @@ public:
*/
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:
void options_button_clicked ();
void esc_pressed ();
void tab_pressed ();
void backtab_pressed ();
protected:
void mousePressEvent (QMouseEvent *event);
void mouseReleaseEvent (QMouseEvent *event);
void resizeEvent (QResizeEvent *event);
void keyPressEvent (QKeyEvent *event);
bool focusNextPrevChild (bool next);
bool event (QEvent *event);
private:
bool m_clear_button_enabled;
bool m_options_button_enabled;
bool m_escape_signal_enabled;
bool m_tab_signal_enabled;
QLabel *mp_options_label;
QLabel *mp_clear_label;
QMenu *mp_options_menu;

View File

@ -27,11 +27,11 @@ namespace tl
{
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) {
if (*p == '\\') {
if (!exact && *p == '\\') {
++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;
} else if (*p == '?') {
} else if (!exact && *p == '?') {
++p;
if (! *s) {
@ -50,7 +50,7 @@ do_match (const char *p, const char *s, std::vector<std::string> *o, std::vector
}
++s;
} else if (*p == '*') {
} else if (!exact && *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;
while (*s) {
if (do_match (p, s, o, bstart)) {
if (do_match (p, s, cs, exact, hm, o, bstart)) {
return true;
}
bstart = bs;
@ -73,7 +73,7 @@ do_match (const char *p, const char *s, std::vector<std::string> *o, std::vector
++s;
}
} else if (*p == '[') {
} else if (!exact && *p == '[') {
if (! *s) {
return false;
@ -111,7 +111,10 @@ do_match (const char *p, const char *s, std::vector<std::string> *o, std::vector
}
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;
}
}
@ -127,7 +130,7 @@ do_match (const char *p, const char *s, std::vector<std::string> *o, std::vector
++p;
}
} else if (*p == '{') {
} else if (!exact && *p == '{') {
++p;
@ -158,7 +161,10 @@ do_match (const char *p, const char *s, std::vector<std::string> *o, std::vector
if (hit) {
if (! *s) {
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;
} else {
++s;
@ -184,7 +190,7 @@ do_match (const char *p, const char *s, std::vector<std::string> *o, std::vector
return false;
}
} else if (*p == ')') {
} else if (!exact && *p == ')') {
++p;
@ -195,7 +201,7 @@ do_match (const char *p, const char *s, std::vector<std::string> *o, std::vector
bstart.pop_back ();
}
} else if (*p == '(') {
} else if (!exact && *p == '(') {
++p;
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 ());
}
} else if (*s != *p) {
return false;
} else {
++s;
++p;
if (cs) {
if (*s != *p) {
return false;
} else {
++s;
++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 ()
: m_case_sensitive (true), m_exact (false), m_header_match (false)
{
// .. nothing yet ..
}
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 ..
}
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
{
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
@ -238,13 +289,13 @@ bool GlobPattern::match (const char *s, std::vector<std::string> &e) const
e.clear ();
}
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
{
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
@ -253,7 +304,7 @@ bool GlobPattern::match (const std::string &s, std::vector<std::string> &e) cons
e.clear ();
}
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;
}
/**
* @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
*/
@ -94,6 +124,9 @@ public:
private:
std::string m_p;
bool m_case_sensitive;
bool m_exact;
bool m_header_match;
};
} // namespace tl

View File

@ -116,7 +116,7 @@ TEST(6)
EXPECT_EQ (a.match ("ah"), false);
}
TEST(7)
TEST(7)
{
tl::GlobPattern a ("(*({bc,d}))(*)");
@ -134,5 +134,64 @@ TEST(7)
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);
}