Search feature for layer list

To enable the search feature just type into the layer list.

This change set also contains some more fixes:
 * Tab/Backtab now is functional also before the
   Display menu has been used the first time
 * Arrow keys work from the cell list again
This commit is contained in:
Matthias Koefferlein 2017-03-02 23:45:37 +01:00
parent 08076de815
commit 5c414ef0be
14 changed files with 486 additions and 208 deletions

View File

@ -581,16 +581,6 @@ MainWindow::MainWindow (QApplication *app, const char *name)
cp_frame_ly->insertSpacing (-1, 6);
// connect to the menus to provide the dynamic parts
QMenu *edit_menu = mp_menu->menu ("edit_menu");
tl_assert (edit_menu != 0);
connect (edit_menu, SIGNAL (aboutToShow ()), this, SLOT (popup_menu_show ()));
connect (edit_menu, SIGNAL (aboutToHide ()), this, SLOT (popup_menu_hide ()));
QMenu *zoom_menu = mp_menu->menu ("zoom_menu");
tl_assert (zoom_menu != 0);
connect (zoom_menu, SIGNAL (aboutToShow ()), this, SLOT (popup_menu_show ()));
connect (zoom_menu, SIGNAL (aboutToHide ()), this, SLOT (popup_menu_hide ()));
QMenu *bookmark_menu = mp_menu->menu ("bookmark_menu");
tl_assert (bookmark_menu != 0);
connect (bookmark_menu, SIGNAL (aboutToShow ()), this, SLOT (bookmark_menu_show ()));
@ -673,6 +663,11 @@ MainWindow::MainWindow (QApplication *app, const char *name)
connect (&m_file_changed_timer, SIGNAL (timeout ()), this, SLOT (file_changed_timer()));
m_file_changed_timer.setSingleShot (true);
// install timer for menu update
connect (&m_menu_update_timer, SIGNAL (timeout ()), this, SLOT (update_action_states ()));
m_menu_update_timer.setSingleShot (false);
m_menu_update_timer.start (200);
connect (&lay::LayoutHandle::file_watcher (), SIGNAL (fileChanged (const QString &)), this, SLOT (file_changed (const QString &)));
connect (&lay::LayoutHandle::file_watcher (), SIGNAL (fileRemoved (const QString &)), this, SLOT (file_removed (const QString &)));
@ -1695,9 +1690,6 @@ MainWindow::edits_enabled_changed ()
for (std::vector<std::string>::const_iterator g = edit_grp.begin (); g != edit_grp.end (); ++g) {
mp_menu->action (*g).set_enabled (enable);
}
// call this to establish a consistent set of options on the menu entries
popup_menu_show ();
}
void
@ -2664,123 +2656,73 @@ MainWindow::cm_zoom_out ()
}
void
MainWindow::popup_menu_hide ()
MainWindow::update_action_states ()
{
// Enable all menu items as far as required on closing of the menu. Otherwise,
// keyboard shortcuts are not effective when the window is closed and the actions are
// left disabled.
try {
BEGIN_PROTECTED
if (mp_menu->is_valid ("edit_menu.undo")) {
if (mp_menu->is_valid ("edit_menu.undo")) {
Action undo_action = mp_menu->action ("edit_menu.undo");
undo_action.set_enabled (edits_enabled ());
}
Action undo_action = mp_menu->action ("edit_menu.undo");
if (mp_menu->is_valid ("edit_menu.redo")) {
Action redo_action = mp_menu->action ("edit_menu.redo");
redo_action.set_enabled (edits_enabled ());
}
std::string undo_txt (tl::to_string (QObject::tr ("&Undo")));
bool undo_enable = false;
if (current_view () && m_manager.available_undo ().first) {
undo_txt += " - " + m_manager.available_undo ().second;
undo_enable = true;
}
undo_action.set_title (undo_txt);
undo_action.set_enabled (undo_enable && edits_enabled ());
if (mp_menu->is_valid ("edit_menu.copy")) {
Action copy_action = mp_menu->action ("edit_menu.copy");
copy_action.set_enabled (edits_enabled ());
}
if (mp_menu->is_valid ("edit_menu.cut")) {
Action cut_action = mp_menu->action ("edit_menu.cut");
cut_action.set_enabled (edits_enabled ());
}
if (mp_menu->is_valid ("edit_menu.paste")) {
Action paste_action = mp_menu->action ("edit_menu.paste");
paste_action.set_enabled (edits_enabled ());
}
if (mp_menu->is_valid ("edit_menu.duplicate")) {
Action paste_action = mp_menu->action ("edit_menu.duplicate");
paste_action.set_enabled (edits_enabled ());
}
if (mp_menu->is_valid ("zoom_menu.next_display_state")) {
Action next_display_state_action = mp_menu->action ("zoom_menu.next_display_state");
next_display_state_action.set_enabled (true);
}
if (mp_menu->is_valid ("zoom_menu.last_display_state")) {
Action last_display_state_action = mp_menu->action ("zoom_menu.last_display_state");
last_display_state_action.set_enabled (true);
}
END_PROTECTED
}
void
MainWindow::popup_menu_show ()
{
BEGIN_PROTECTED
if (mp_menu->is_valid ("edit_menu.undo")) {
Action undo_action = mp_menu->action ("edit_menu.undo");
std::string undo_txt (tl::to_string (QObject::tr ("&Undo")));
bool undo_enable = false;
if (current_view () && m_manager.available_undo ().first) {
undo_txt += " - " + m_manager.available_undo ().second;
undo_enable = true;
}
undo_action.set_title (undo_txt);
undo_action.set_enabled (undo_enable && edits_enabled ());
}
if (mp_menu->is_valid ("edit_menu.redo")) {
if (mp_menu->is_valid ("edit_menu.redo")) {
Action redo_action = mp_menu->action ("edit_menu.redo");
Action redo_action = mp_menu->action ("edit_menu.redo");
std::string redo_txt (tl::to_string (QObject::tr ("&Redo")));
bool redo_enable = false;
if (current_view () && m_manager.available_redo ().first) {
redo_txt += " - " + m_manager.available_redo ().second;
redo_enable = true;
}
redo_action.set_title (redo_txt);
redo_action.set_enabled (redo_enable && edits_enabled ());
std::string redo_txt (tl::to_string (QObject::tr ("&Redo")));
bool redo_enable = false;
if (current_view () && m_manager.available_redo ().first) {
redo_txt += " - " + m_manager.available_redo ().second;
redo_enable = true;
}
redo_action.set_title (redo_txt);
redo_action.set_enabled (redo_enable && edits_enabled ());
if (mp_menu->is_valid ("edit_menu.copy")) {
Action copy_action = mp_menu->action ("edit_menu.copy");
copy_action.set_enabled (current_view () && current_view ()->has_selection () && edits_enabled ());
}
if (mp_menu->is_valid ("edit_menu.duplicate")) {
Action copy_action = mp_menu->action ("edit_menu.duplicate");
copy_action.set_enabled (current_view () && current_view ()->has_selection () && edits_enabled ());
}
if (mp_menu->is_valid ("edit_menu.cut")) {
Action cut_action = mp_menu->action ("edit_menu.cut");
cut_action.set_enabled (current_view () && current_view ()->has_selection () && edits_enabled ());
}
if (mp_menu->is_valid ("edit_menu.paste")) {
Action paste_action = mp_menu->action ("edit_menu.paste");
paste_action.set_enabled (! db::Clipboard::instance ().empty () && edits_enabled ());
}
if (mp_menu->is_valid ("zoom_menu.next_display_state")) {
Action next_display_state_action = mp_menu->action ("zoom_menu.next_display_state");
next_display_state_action.set_enabled (has_next_display_state ());
}
if (mp_menu->is_valid ("zoom_menu.last_display_state")) {
Action last_display_state_action = mp_menu->action ("zoom_menu.last_display_state");
last_display_state_action.set_enabled (has_last_display_state ());
}
} catch (...) {
// ignore exceptions
}
if (mp_menu->is_valid ("edit_menu.copy")) {
Action copy_action = mp_menu->action ("edit_menu.copy");
copy_action.set_enabled (current_view () && current_view ()->has_selection () && edits_enabled ());
}
if (mp_menu->is_valid ("edit_menu.duplicate")) {
Action copy_action = mp_menu->action ("edit_menu.duplicate");
copy_action.set_enabled (current_view () && current_view ()->has_selection () && edits_enabled ());
}
if (mp_menu->is_valid ("edit_menu.cut")) {
Action cut_action = mp_menu->action ("edit_menu.cut");
cut_action.set_enabled (current_view () && current_view ()->has_selection () && edits_enabled ());
}
if (mp_menu->is_valid ("edit_menu.paste")) {
Action paste_action = mp_menu->action ("edit_menu.paste");
paste_action.set_enabled (! db::Clipboard::instance ().empty () && edits_enabled ());
}
if (mp_menu->is_valid ("zoom_menu.next_display_state")) {
Action next_display_state_action = mp_menu->action ("zoom_menu.next_display_state");
next_display_state_action.set_enabled (has_next_display_state ());
}
if (mp_menu->is_valid ("zoom_menu.last_display_state")) {
Action last_display_state_action = mp_menu->action ("zoom_menu.last_display_state");
last_display_state_action.set_enabled (has_last_display_state ());
}
END_PROTECTED
}
void

View File

@ -662,8 +662,7 @@ public slots:
*/
void intrinsic_mode_triggered ();
void popup_menu_show ();
void popup_menu_hide ();
void update_action_states ();
void cancel ();
void redraw ();
void exit ();
@ -900,6 +899,7 @@ private:
tl::DeferredMethod<MainWindow> dm_do_update_menu;
QTimer m_message_timer;
QTimer m_file_changed_timer;
QTimer m_menu_update_timer;
std::string m_config_window_state;
std::string m_initial_technology;

View File

@ -756,21 +756,6 @@ CellTreeModel::search_children (const tl::GlobPattern &pattern, CellTreeItem *it
}
}
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)
{

View File

@ -238,7 +238,6 @@ private:
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

@ -69,13 +69,9 @@ public:
// --------------------------------------------------------------------
// HCPCellTreeWidget implementation
HCPCellTreeWidget::HCPCellTreeWidget (QWidget *parent, const char *name)
: QTreeView (parent)
HCPCellTreeWidget::HCPCellTreeWidget (QWidget *parent, const char *name, QWidget *key_event_receiver)
: QTreeView (parent), mp_key_event_receiver (key_event_receiver)
{
// Don't request focus: this leaves focus on the canvas and the arrow keys functional there
// @@@ setFocusPolicy (Qt::NoFocus); -> solve differently!!!
setFocusPolicy (Qt::ClickFocus);
// Allow dragging from here to
setDragDropMode (QAbstractItemView::DragOnly);
@ -97,12 +93,24 @@ HCPCellTreeWidget::event (QEvent *event)
return QTreeView::event (event);
}
bool
HCPCellTreeWidget::focusNextPrevChild (bool /*next*/)
{
return false;
}
void
HCPCellTreeWidget::keyPressEvent (QKeyEvent *event)
{
QString t = event->text ();
if (!t.isEmpty ()) {
if (!t.isEmpty () && t[0].isPrint ()) {
emit search_triggered (t);
} else if (mp_key_event_receiver) {
// send other key events to the alternative receiver - this way we can make the
// view receive arrow keys for panning.
QCoreApplication::sendEvent (mp_key_event_receiver, event);
} else {
return QTreeView::keyPressEvent (event);
}
}
@ -885,7 +893,7 @@ HierarchyControlPanel::do_update_content (int cv_index)
header->setVisible (split_mode);
cl_ly->addWidget (header);
HCPCellTreeWidget *cell_list = new HCPCellTreeWidget (cl_frame, "tree");
HCPCellTreeWidget *cell_list = new HCPCellTreeWidget (cl_frame, "tree", mp_view->view_object_widget ());
cl_ly->addWidget (cell_list);
cell_list->setStyle (mp_tree_style.get ());
cell_list->setModel (new CellTreeModel (cell_list, mp_view, cv_index, m_flat ? CellTreeModel::Flat : 0, 0, m_sorting));

View File

@ -65,7 +65,7 @@ class HCPCellTreeWidget
Q_OBJECT
public:
HCPCellTreeWidget (QWidget *parent, const char *name);
HCPCellTreeWidget (QWidget *parent, const char *name, QWidget *key_event_receiver);
signals:
void cell_clicked (const QModelIndex &);
@ -78,8 +78,11 @@ protected:
virtual void mousePressEvent (QMouseEvent *event);
virtual void mouseReleaseEvent (QMouseEvent *event);
virtual void startDrag (Qt::DropActions supportedActions);
virtual bool focusNextPrevChild (bool next);
virtual void keyPressEvent (QKeyEvent *event);
virtual bool event (QEvent *event);
QWidget *mp_key_event_receiver;
};
/**
@ -255,6 +258,14 @@ public:
return m_split_mode;
}
/**
* @brief Gets the layout view this panel is attached to
*/
lay::LayoutView *view ()
{
return mp_view;
}
signals:
void cell_selected (cell_path_type path, int cellview_index);
void active_cellview_changed (int cellview_index);

View File

@ -97,9 +97,6 @@ private:
LCPTreeWidget::LCPTreeWidget (QWidget *parent, lay::LayerTreeModel *model, const char *name)
: QTreeView (parent), mp_model (model)
{
// Don't request focus: this leaves focus on the canvas and the arrow keys functional there
setFocusPolicy (Qt::NoFocus);
setObjectName (QString::fromUtf8 (name));
setModel (model);
setItemDelegate (new LCPItemDelegate (this));
@ -149,7 +146,38 @@ LCPTreeWidget::mouseDoubleClickEvent (QMouseEvent *event)
}
}
void
bool
LCPTreeWidget::focusNextPrevChild (bool /*next*/)
{
return false;
}
bool
LCPTreeWidget::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
LCPTreeWidget::keyPressEvent (QKeyEvent *event)
{
QString t = event->text ();
if (!t.isEmpty () && t[0].isPrint ()) {
emit search_triggered (t);
} else {
QTreeView::keyPressEvent (event);
}
}
void
LCPTreeWidget::collapse_all ()
{
#if QT_VERSION >= 0x040200
@ -299,6 +327,70 @@ LayerControlPanel::LayerControlPanel (lay::LayoutView *view, db::Manager *manage
l->setMargin (0);
l->setSpacing (0);
mp_search_frame = new QFrame (this);
l->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_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_tab_bar = new QTabBar (this);
mp_tab_bar->setObjectName (QString::fromUtf8 ("lcp_tabs"));
connect (mp_tab_bar, SIGNAL (currentChanged (int)), this, SLOT (tab_selected (int)));
@ -321,6 +413,7 @@ LayerControlPanel::LayerControlPanel (lay::LayoutView *view, db::Manager *manage
connect (mp_layer_list, SIGNAL (double_clicked (const QModelIndex &, Qt::KeyboardModifiers)), this, SLOT (double_clicked (const QModelIndex &, Qt::KeyboardModifiers)));
connect (mp_layer_list, SIGNAL (collapsed (const QModelIndex &)), this, SLOT (group_collapsed (const QModelIndex &)));
connect (mp_layer_list, SIGNAL (expanded (const QModelIndex &)), this, SLOT (group_expanded (const QModelIndex &)));
connect (mp_layer_list, SIGNAL (search_triggered (const QString &)), this, SLOT (search_triggered (const QString &)));
mp_layer_list->setContextMenuPolicy (Qt::CustomContextMenu);
connect (mp_layer_list, SIGNAL(customContextMenuRequested (const QPoint &)), this, SLOT (context_menu (const QPoint &)));
mp_layer_list->header ()->hide ();
@ -1130,6 +1223,77 @@ LayerControlPanel::clear_selection ()
set_selection (empty_sel);
}
void
LayerControlPanel::search_triggered (const QString &t)
{
if (mp_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
LayerControlPanel::search_edited ()
{
if (! mp_model) {
return;
}
QString t = mp_search_edit_box->text ();
if (t.isEmpty ()) {
mp_model->clear_locate ();
mp_layer_list->setCurrentIndex (QModelIndex ());
} else {
QModelIndex found = mp_model->locate (t.toUtf8 ().constData (), mp_use_regular_expressions->isChecked (), mp_case_sensitive->isChecked (), false);
mp_layer_list->setCurrentIndex (found);
if (found.isValid ()) {
mp_layer_list->scrollTo (found);
}
}
}
void
LayerControlPanel::search_next ()
{
if (! mp_model) {
return;
}
QModelIndex found = mp_model->locate_next ();
if (found.isValid ()) {
mp_layer_list->setCurrentIndex (found);
mp_layer_list->scrollTo (found);
}
}
void
LayerControlPanel::search_prev ()
{
if (! mp_model) {
return;
}
QModelIndex found = mp_model->locate_prev ();
if (found.isValid ()) {
mp_layer_list->setCurrentIndex (found);
mp_layer_list->scrollTo (found);
}
}
void
LayerControlPanel::search_editing_finished ()
{
if (! mp_model) {
return;
}
mp_model->clear_locate ();
mp_search_frame->hide ();
}
void
LayerControlPanel::cm_regroup_flatten ()
{
@ -1727,6 +1891,10 @@ set_hidden_flags_rec (LayerTreeModel *model, QTreeView *tree_view, const QModelI
void
LayerControlPanel::do_update_content ()
{
// clear search. TODO: update search instead of clearing
mp_search_edit_box->clear ();
mp_model->clear_locate();
mp_model->set_phase (m_phase);
if (m_tabs_need_update) {

View File

@ -44,6 +44,7 @@
#include "layDitherPattern.h"
#include "layLayerProperties.h"
#include "layLayerTreeModel.h"
#include "layWidgets.h"
#include "dbObject.h"
#include "tlDeferredExecution.h"
@ -52,6 +53,7 @@ class QModelIndex;
class QMenu;
class QLabel;
class QTabBar;
class QCheckBox;
namespace lay
{
@ -85,6 +87,12 @@ public:
signals:
void double_clicked (const QModelIndex &, Qt::KeyboardModifiers);
void search_triggered (const QString &t);
protected:
virtual void keyPressEvent (QKeyEvent *event);
virtual bool event (QEvent *event);
virtual bool focusNextPrevChild (bool next);
private:
lay::LayerTreeModel *mp_model;
@ -322,6 +330,11 @@ public slots:
void upup_clicked ();
void down_clicked ();
void downdown_clicked ();
void search_triggered (const QString &t);
void search_edited ();
void search_editing_finished ();
void search_next ();
void search_prev ();
private:
QTabBar *mp_tab_bar;
@ -341,6 +354,11 @@ private:
std::set<unsigned int> m_expanded;
bool m_no_stipples;
QLabel *m_no_stipples_label;
lay::DecoratedLineEdit *mp_search_edit_box;
QAction *mp_case_sensitive;
QAction *mp_use_regular_expressions;
QFrame *mp_search_frame;
QCheckBox *mp_search_close_cb;
void clear_selection ();

View File

@ -27,6 +27,7 @@
#include "dbLayoutUtils.h"
#include "tlLog.h"
#include "tlTimer.h"
#include "tlGlobPattern.h"
#include <QTreeView>
#include <QModelIndex>
@ -278,6 +279,92 @@ LayerTreeModel::index (int row, int column, const QModelIndex &parent) const
}
}
void
LayerTreeModel::clear_locate ()
{
m_selected_indexes.clear ();
m_current_index = m_selected_indexes.begin ();
m_selected_ids.clear ();
signal_data_changed ();
}
QModelIndex
LayerTreeModel::locate_next ()
{
if (m_current_index == m_selected_indexes.end ()) {
return QModelIndex ();
} else {
++m_current_index;
if (m_current_index == m_selected_indexes.end ()) {
m_current_index = m_selected_indexes.begin ();
}
return *m_current_index;
}
}
QModelIndex
LayerTreeModel::locate_prev ()
{
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
LayerTreeModel::search_children (const tl::GlobPattern &pattern, const QModelIndex &parent, bool recurse)
{
int children = rowCount (parent);
for (int i = 0; i < children; ++i) {
QModelIndex child = index (i, 0, parent);
lay::LayerPropertiesConstIterator iter (iterator (child));
if (!iter.is_null () && !iter.at_end () &&
pattern.match (iter->display_string (mp_view, true /*real*/))) {
m_selected_indexes.push_back (child);
}
if (recurse && iter->has_children ()) {
search_children (pattern, child, recurse);
}
}
}
QModelIndex
LayerTreeModel::locate (const char *name, bool glob_pattern, bool case_sensitive, bool top_only)
{
m_selected_indexes.clear ();
tl::GlobPattern p = tl::GlobPattern (std::string (name));
p.set_case_sensitive (case_sensitive);
p.set_exact (!glob_pattern);
p.set_header_match (true);
search_children (p, QModelIndex (), !top_only);
m_selected_ids.clear ();
for (std::vector<QModelIndex>::const_iterator i = m_selected_indexes.begin (); i != m_selected_indexes.end (); ++i) {
m_selected_ids.insert (size_t (i->internalPointer ()));
}
signal_data_changed ();
m_current_index = m_selected_indexes.begin ();
if (m_current_index == m_selected_indexes.end ()) {
return QModelIndex ();
} else {
return *m_current_index;
}
}
void
LayerTreeModel::signal_data_changed ()
{
@ -648,6 +735,18 @@ LayerTreeModel::data (const QModelIndex &index, int role) const
}
} else if (role == Qt::BackgroundRole) {
if (m_selected_ids.find (size_t (index.internalPointer ())) != m_selected_ids.end ()) {
// for selected items pick a color between Highlight and Base
QPalette pl (mp_view->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 ();
}
} else if (role == Qt::TextColorRole || role == Qt::FontRole) {
if (index.column () == 1) {

View File

@ -38,6 +38,11 @@ namespace db
class Layout;
}
namespace tl
{
class GlobPattern;
}
namespace lay
{
@ -161,6 +166,29 @@ public:
*/
void signal_data_changed ();
/**
* @brief Locate an index by name (at least closest)
*
* 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, 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
*/
void clear_locate ();
/**
* @brief Set the test_shapes_in_view flag
*
@ -194,6 +222,11 @@ private:
QFont m_font;
QColor m_text_color, m_background_color;
mutable EmptyWithinViewCache m_test_shapes_cache;
std::set <size_t> m_selected_ids;
std::vector <QModelIndex> m_selected_indexes;
std::vector <QModelIndex>::const_iterator m_current_index;
void search_children (const tl::GlobPattern &pattern, const QModelIndex &parent, bool recurse);
};
}

View File

@ -42,6 +42,7 @@
#include "tlString.h"
#include "tlLog.h"
#include "tlAssert.h"
#include "layLayoutView.h"
#include "layViewOp.h"
#include "layViewObject.h"
#include "layLayoutViewConfigPages.h"

View File

@ -25,6 +25,7 @@
#include <QWheelEvent>
#include <QKeyEvent>
#include <QMimeData>
#include <QCoreApplication>
#include "layViewObject.h"
#include "layCanvasPlane.h"
@ -367,6 +368,12 @@ ViewObjectWidget::end_mouse_event ()
}
}
bool
ViewObjectWidget::focusNextPrevChild (bool /*next*/)
{
return false;
}
void
ViewObjectWidget::keyPressEvent (QKeyEvent *e)
{

View File

@ -603,66 +603,6 @@ public:
*/
~ViewObjectWidget ();
/**
* @brief Qt keyboard event handler
*/
void keyPressEvent (QKeyEvent *e);
/**
* @brief Qt mouse move event handler
*/
void mouseMoveEvent (QMouseEvent *e);
/**
* @brief Qt mouse leave event handler
*/
void leaveEvent (QEvent *e);
/**
* @brief Qt mouse enter event handler
*/
void enterEvent (QEvent *e);
/**
* @brief Qt mouse button press event handler
*/
void mousePressEvent (QMouseEvent *e);
/**
* @brief Qt mouse button double-click event handler
*/
void mouseDoubleClickEvent (QMouseEvent *e);
/**
* @brief Qt mouse button release event handler
*/
void mouseReleaseEvent (QMouseEvent *e);
/**
* @brief Qt drag enter event handler
*/
void dragEnterEvent (QDragEnterEvent *event);
/**
* @brief Qt drag leave event handler
*/
void dragLeaveEvent (QDragLeaveEvent *event);
/**
* @brief Qt drag enter event handler
*/
void dragMoveEvent (QDragMoveEvent *event);
/**
* @brief Qt drop event handler
*/
void dropEvent (QDropEvent *event);
/**
* @brief Qt mouse wheel event handler
*/
void wheelEvent (QWheelEvent *e);
/**
* @brief Cancel all drag operations
*/
@ -966,6 +906,71 @@ public:
void set_default_cursor (lay::Cursor::cursor_shape cursor);
protected:
/**
* @brief Qt focus event handler
*/
bool focusNextPrevChild (bool next);
/**
* @brief Qt keyboard event handler
*/
void keyPressEvent (QKeyEvent *e);
/**
* @brief Qt mouse move event handler
*/
void mouseMoveEvent (QMouseEvent *e);
/**
* @brief Qt mouse leave event handler
*/
void leaveEvent (QEvent *e);
/**
* @brief Qt mouse enter event handler
*/
void enterEvent (QEvent *e);
/**
* @brief Qt mouse button press event handler
*/
void mousePressEvent (QMouseEvent *e);
/**
* @brief Qt mouse button double-click event handler
*/
void mouseDoubleClickEvent (QMouseEvent *e);
/**
* @brief Qt mouse button release event handler
*/
void mouseReleaseEvent (QMouseEvent *e);
/**
* @brief Qt drag enter event handler
*/
void dragEnterEvent (QDragEnterEvent *event);
/**
* @brief Qt drag leave event handler
*/
void dragLeaveEvent (QDragLeaveEvent *event);
/**
* @brief Qt drag enter event handler
*/
void dragMoveEvent (QDragMoveEvent *event);
/**
* @brief Qt drop event handler
*/
void dropEvent (QDropEvent *event);
/**
* @brief Qt mouse wheel event handler
*/
void wheelEvent (QWheelEvent *e);
/**
* @brief Set the transformation for mouse events
*/

View File

@ -976,6 +976,8 @@ bool DecoratedLineEdit::event (QEvent *event)
QKeyEvent *ke = static_cast<QKeyEvent *> (event);
if (ke->key () == Qt::Key_Escape && m_escape_signal_enabled) {
ke->accept ();
} else if ((ke->key () == Qt::Key_Tab || ke->key () == Qt::Key_Backtab) && m_tab_signal_enabled) {
ke->accept ();
}
}
return QLineEdit::event (event);