diff --git a/src/laybasic/laybasic/layLayerControlPanel.cc b/src/laybasic/laybasic/layLayerControlPanel.cc index 9cfeb1ec5..0316d6711 100644 --- a/src/laybasic/laybasic/layLayerControlPanel.cc +++ b/src/laybasic/laybasic/layLayerControlPanel.cc @@ -34,6 +34,7 @@ #include "layDialogs.h" #include "layLayoutCanvas.h" #include "layAbstractMenu.h" +#include "layQtTools.h" #include "tlExceptions.h" #include "tlInternational.h" #include "tlAssert.h" @@ -203,12 +204,10 @@ LayerControlPanel::LayerControlPanel (lay::LayoutView *view, db::Manager *manage mp_view (view), m_needs_update (true), m_tabs_need_update (true), - m_force_update_hidden_flags (true), m_in_update (false), m_phase (0), m_do_update_content_dm (this, &LayerControlPanel::do_update_content), - m_hide_empty_layers (false), - m_test_shapes_in_view (false), + m_do_update_hidden_flags_dm (this, &LayerControlPanel::do_update_hidden_flags), m_no_stipples (false) { setObjectName (QString::fromUtf8 (name)); @@ -269,11 +268,18 @@ LayerControlPanel::LayerControlPanel (lay::LayoutView *view, db::Manager *manage mp_case_sensitive->setChecked (true); mp_case_sensitive->setText (tr ("Case sensitive search")); + mp_filter = new QAction (this); + mp_filter->setCheckable (true); + mp_filter->setChecked (false); + mp_filter->setText (tr ("Apply as filter")); + QMenu *m = new QMenu (mp_search_edit_box); m->addAction (mp_use_regular_expressions); m->addAction (mp_case_sensitive); + m->addAction (mp_filter); connect (mp_use_regular_expressions, SIGNAL (triggered ()), this, SLOT (search_edited ())); connect (mp_case_sensitive, SIGNAL (triggered ()), this, SLOT (search_edited ())); + connect (mp_filter, SIGNAL (triggered ()), this, SLOT (search_edited ())); mp_search_edit_box->set_clear_button_enabled (true); mp_search_edit_box->set_options_button_enabled (true); @@ -370,6 +376,8 @@ LayerControlPanel::LayerControlPanel (lay::LayoutView *view, db::Manager *manage m_no_stipples_label->setPixmap (QPixmap (QString::fromUtf8 (":/important.png"))); m_no_stipples_label->setToolTip (tr ("Stipples are disabled - unselect \"View/Show Layers Without Fill\" to re-enable them")); ltb->addWidget (m_no_stipples_label); + + connect (mp_model, SIGNAL (hidden_flags_need_update ()), this, SLOT (update_hidden_flags ())); } LayerControlPanel::~LayerControlPanel () @@ -1126,6 +1134,10 @@ LayerControlPanel::search_edited () return; } + mp_model->set_filter_mode (mp_filter->isChecked ()); + + bool filter_invalid = false; + QString t = mp_search_edit_box->text (); if (t.isEmpty ()) { mp_model->clear_locate (); @@ -1135,8 +1147,12 @@ LayerControlPanel::search_edited () mp_layer_list->setCurrentIndex (found); if (found.isValid ()) { mp_layer_list->scrollTo (found); + } else { + filter_invalid = true; } } + + lay::indicate_error (mp_search_edit_box, filter_invalid); } void @@ -1642,27 +1658,28 @@ LayerControlPanel::set_text_color (QColor c) mp_model->set_text_color (c); } -void +void +LayerControlPanel::update_hidden_flags () +{ + m_do_update_hidden_flags_dm (); +} + +void LayerControlPanel::set_hide_empty_layers (bool f) { - if (f != m_hide_empty_layers) { - m_hide_empty_layers = f; - m_force_update_hidden_flags = true; - m_do_update_content_dm (); - } + mp_model->set_hide_empty_layers (f); +} + +bool +LayerControlPanel::hide_empty_layers () +{ + return mp_model->get_hide_empty_layers (); } void LayerControlPanel::set_test_shapes_in_view (bool f) { - if (f != m_test_shapes_in_view) { - m_test_shapes_in_view = f; - mp_model->set_test_shapes_in_view (f); - if (m_hide_empty_layers) { - m_force_update_hidden_flags = true; - } - m_do_update_content_dm (); - } + mp_model->set_test_shapes_in_view (f); } void @@ -1707,7 +1724,6 @@ LayerControlPanel::cancel_updates () void LayerControlPanel::end_updates () { - m_force_update_hidden_flags = true; do_update_content (); } @@ -1721,7 +1737,7 @@ LayerControlPanel::set_phase (int phase) } static void -set_hidden_flags_within_view_rec (LayerTreeModel *model, QTreeView *tree_view, const QModelIndex &parent, bool hide_empty) +set_hidden_flags_rec (LayerTreeModel *model, QTreeView *tree_view, const QModelIndex &parent) { int rows = model->rowCount (parent); for (int r = 0; r < rows; ++r) { @@ -1730,7 +1746,7 @@ set_hidden_flags_within_view_rec (LayerTreeModel *model, QTreeView *tree_view, c if (! model->hasChildren (index)) { - if (hide_empty && model->empty_within_view_predicate (index)) { + if (model->is_hidden (index)) { tree_view->setRowHidden (r, parent, true); } else { tree_view->setRowHidden (r, parent, false); @@ -1738,43 +1754,33 @@ set_hidden_flags_within_view_rec (LayerTreeModel *model, QTreeView *tree_view, c } else { tree_view->setRowHidden (r, parent, false); - set_hidden_flags_within_view_rec (model, tree_view, index, hide_empty); - } - - } -} - -static void -set_hidden_flags_rec (LayerTreeModel *model, QTreeView *tree_view, const QModelIndex &parent, bool hide_empty) -{ - int rows = model->rowCount (parent); - for (int r = 0; r < rows; ++r) { - - QModelIndex index = model->index (r, 0, parent); - - if (! model->hasChildren (index)) { - - if (hide_empty && model->empty_predicate (index)) { - tree_view->setRowHidden (r, parent, true); - } else { - tree_view->setRowHidden (r, parent, false); - } - - } else { - tree_view->setRowHidden (r, parent, false); - set_hidden_flags_rec (model, tree_view, index, hide_empty); + set_hidden_flags_rec (model, tree_view, index); } } } +void +LayerControlPanel::do_update_hidden_flags () +{ + set_hidden_flags_rec (mp_model, mp_layer_list, QModelIndex ()); + + // scroll the current index into view if it was not visible before + QModelIndex current = mp_layer_list->currentIndex (); + if (current.isValid ()) { + QModelIndex parent = mp_layer_list->model ()->parent (current); + if (! mp_layer_list->isRowHidden (current.row (), parent)) { + QRect visual_rect = mp_layer_list->visualRect (current); + if (! visual_rect.intersects (mp_layer_list->viewport ()->rect ())) { + mp_layer_list->scrollTo (current, QAbstractItemView::PositionAtCenter); + } + } + } +} + 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) { @@ -1853,48 +1859,21 @@ LayerControlPanel::do_update_content () m_needs_update = false; + } else if (m_needs_update) { + + m_needs_update = false; + + bool has_children = false; + for (lay::LayerPropertiesConstIterator l = mp_view->begin_layers (); l != mp_view->end_layers () && ! has_children; ++l) { + if (l->has_children ()) { + has_children = true; + } + } + mp_layer_list->setRootIsDecorated (has_children); + mp_layer_list->reset (); + } else { - - if (m_needs_update) { - - m_needs_update = false; - - bool has_children = false; - for (lay::LayerPropertiesConstIterator l = mp_view->begin_layers (); l != mp_view->end_layers () && ! has_children; ++l) { - if (l->has_children ()) { - has_children = true; - } - } - mp_layer_list->setRootIsDecorated (has_children); - mp_layer_list->reset (); - - } else { - mp_model->signal_data_changed (); // this makes the view redraw the data - } - - } - - if (m_hide_empty_layers || m_force_update_hidden_flags) { - - m_force_update_hidden_flags = false; - if (m_test_shapes_in_view) { - set_hidden_flags_within_view_rec (mp_model, mp_layer_list, QModelIndex (), m_hide_empty_layers); - } else { - set_hidden_flags_rec (mp_model, mp_layer_list, QModelIndex (), m_hide_empty_layers); - } - - // scroll the current index into view if it was not visible before - QModelIndex current = mp_layer_list->currentIndex (); - if (current.isValid ()) { - QModelIndex parent = mp_layer_list->model ()->parent (current); - if (! mp_layer_list->isRowHidden (current.row (), parent)) { - QRect visual_rect = mp_layer_list->visualRect (current); - if (! visual_rect.intersects (mp_layer_list->viewport ()->rect ())) { - mp_layer_list->scrollTo (current, QAbstractItemView::PositionAtCenter); - } - } - } - + mp_model->signal_data_changed (); // this makes the view redraw the data } } @@ -1975,7 +1954,7 @@ LayerControlPanel::redo (db::Op *op) void LayerControlPanel::signal_vp_changed () { - if (m_test_shapes_in_view) { + if (mp_model->get_test_shapes_in_view ()) { update_required (1); } } @@ -2028,7 +2007,7 @@ LayerControlPanel::update_required (int f) } if ((f & 3) != 0) { - m_force_update_hidden_flags = true; + m_do_update_hidden_flags_dm (); } m_do_update_content_dm (); diff --git a/src/laybasic/laybasic/layLayerControlPanel.h b/src/laybasic/laybasic/layLayerControlPanel.h index 95f0acf34..8d235c877 100644 --- a/src/laybasic/laybasic/layLayerControlPanel.h +++ b/src/laybasic/laybasic/layLayerControlPanel.h @@ -184,10 +184,7 @@ public: /** * @brief Get the "hide empty layers" flag */ - bool hide_empty_layers () - { - return m_hide_empty_layers; - } + bool hide_empty_layers (); /** * @brief Set the "test_shapes_in_view" flag @@ -201,7 +198,7 @@ public: */ bool test_shapes_in_view () { - return m_test_shapes_in_view; + return mp_model->get_test_shapes_in_view (); } /** @@ -333,6 +330,9 @@ public slots: void search_next (); void search_prev (); +private slots: + void update_hidden_flags (); + private: QTabBar *mp_tab_bar; LCPTreeWidget *mp_layer_list; @@ -341,19 +341,17 @@ private: lay::LayoutView *mp_view; bool m_needs_update; bool m_tabs_need_update; - bool m_force_update_hidden_flags; bool m_in_update; std::vector m_new_sel; int m_phase; - tl::DeferredMethod m_do_update_content_dm; - bool m_hide_empty_layers; - bool m_test_shapes_in_view; + tl::DeferredMethod m_do_update_content_dm, m_do_update_hidden_flags_dm; std::set 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; + QAction *mp_filter; QFrame *mp_search_frame; QCheckBox *mp_search_close_cb; @@ -369,6 +367,7 @@ private: void signal_vp_changed (); void do_update_content (); + void do_update_hidden_flags (); void do_delete (); void do_copy (); void recover (); diff --git a/src/laybasic/laybasic/layLayerTreeModel.cc b/src/laybasic/laybasic/layLayerTreeModel.cc index 9182580e1..c5c6f2b99 100644 --- a/src/laybasic/laybasic/layLayerTreeModel.cc +++ b/src/laybasic/laybasic/layLayerTreeModel.cc @@ -180,7 +180,7 @@ EmptyWithinViewCache::determine_empty_layers (const db::Layout *layout, unsigned LayerTreeModel::LayerTreeModel (QWidget *parent, lay::LayoutView *view) : QAbstractItemModel (parent), - mp_view (view), m_id_start (0), m_id_end (0), m_phase ((unsigned int) -1), m_test_shapes_in_view (false) + mp_view (view), m_filter_mode (false), m_id_start (0), m_id_end (0), m_phase ((unsigned int) -1), m_test_shapes_in_view (false), m_hide_empty_layers (false) { // .. nothing yet .. } @@ -210,6 +210,37 @@ LayerTreeModel::set_text_color (QColor color) signal_data_changed (); } +void +LayerTreeModel::set_test_shapes_in_view (bool f) +{ + if (m_test_shapes_in_view != f) { + m_test_shapes_in_view = f; + if (m_hide_empty_layers) { + emit hidden_flags_need_update (); + } + signal_data_changed (); + } +} + +void +LayerTreeModel::set_hide_empty_layers (bool f) +{ + if (m_hide_empty_layers != f) { + m_hide_empty_layers = f; + // we actually can't do this ourselves. + emit hidden_flags_need_update (); + } +} + +void +LayerTreeModel::set_filter_mode (bool f) +{ + if (f != m_filter_mode) { + m_filter_mode = f; + emit hidden_flags_need_update (); + } +} + void LayerTreeModel::set_background_color (QColor background) { @@ -288,6 +319,10 @@ LayerTreeModel::clear_locate () m_selected_ids.clear (); signal_data_changed (); + + if (m_filter_mode) { + emit hidden_flags_need_update (); + } } QModelIndex @@ -358,6 +393,10 @@ LayerTreeModel::locate (const char *name, bool glob_pattern, bool case_sensitive signal_data_changed (); + if (m_filter_mode) { + emit hidden_flags_need_update (); + } + m_current_index = m_selected_indexes.begin (); if (m_current_index == m_selected_indexes.end ()) { return QModelIndex (); @@ -481,6 +520,22 @@ single_bitmap_to_image (const lay::ViewOp &view_op, lay::Bitmap &bitmap, lay::bitmaps_to_image (view_ops, pbitmaps, dither_pattern, line_styles, pimage, width, height, false, 0); } +bool +LayerTreeModel::is_hidden (const QModelIndex &index) const +{ + if (m_filter_mode && ! m_selected_ids.empty () && m_selected_ids.find (size_t (index.internalPointer ())) == m_selected_ids.end ()) { + return true; + } + + if (! m_hide_empty_layers) { + return false; + } else if (m_test_shapes_in_view) { + return empty_within_view_predicate (index); + } else { + return empty_predicate (index); + } +} + bool LayerTreeModel::empty_predicate (const QModelIndex &index) const { diff --git a/src/laybasic/laybasic/layLayerTreeModel.h b/src/laybasic/laybasic/layLayerTreeModel.h index 2d2882889..10404160c 100644 --- a/src/laybasic/laybasic/layLayerTreeModel.h +++ b/src/laybasic/laybasic/layLayerTreeModel.h @@ -126,21 +126,9 @@ public: lay::LayerPropertiesConstIterator iterator (const QModelIndex &index) const; /** - * @brief Get a flag indicating that a layer is empty + * @brief Get a flag indicating that an entry is hidden */ - bool empty_predicate (const QModelIndex &index) const; - - /** - * @brief Get a flag indicating that a layer does not have shapes within the shown area - */ - bool empty_within_view_predicate (const QModelIndex &index) const; - - /** - * @brief Set the non-empty layers (the "uint" for the layer iterators) for the "test shapes is view" mode - * - * @return True, if a change has been made. - */ - bool set_non_empty_layers (const std::set &non_empty_layers); + bool is_hidden (const QModelIndex &index) const; /** * @brief Set the animation phase @@ -201,13 +189,42 @@ public: void clear_locate (); /** - * @brief Set the test_shapes_in_view flag - * - * This method does not issue a data changed signal. This has to be done somewhere else. + * @brief Sets a flag indicating whether to test shapes in view for highlighting non-empty layers */ - void set_test_shapes_in_view (bool f) + void set_test_shapes_in_view (bool f); + + /** + * @brief Gets a flag indicating whether to test shapes in view for highlighting non-empty layers + */ + bool get_test_shapes_in_view () { - m_test_shapes_in_view = f; + return m_test_shapes_in_view; + } + + /** + * @brief Sets the flag indicating whether to hide empty layers + */ + void set_hide_empty_layers (bool f); + + /** + * @brief Gets the flag indicating whether to hide empty layers + */ + bool get_hide_empty_layers () const + { + return m_hide_empty_layers; + } + + /** + * @brief Sets a flag indicating whether selected indexes are filtered or highlighted + */ + void set_filter_mode (bool f); + + /** + * @brief Gets a flag indicating whether selected indexes are filtered or highlighted + */ + bool get_filter_mode () const + { + return m_filter_mode; } /** @@ -220,11 +237,19 @@ public: */ void signal_layer_changed (); +signals: + /** + * @brief This signal is emitted to indicate + */ + void hidden_flags_need_update (); + private: lay::LayoutView *mp_view; + bool m_filter_mode; size_t m_id_start, m_id_end; unsigned int m_phase; bool m_test_shapes_in_view; + bool m_hide_empty_layers; QFont m_font; QColor m_text_color, m_background_color; mutable EmptyWithinViewCache m_test_shapes_cache; @@ -232,6 +257,16 @@ private: std::vector m_selected_indexes; std::vector ::const_iterator m_current_index; + /** + * @brief Get a flag indicating that a layer is empty + */ + bool empty_predicate (const QModelIndex &index) const; + + /** + * @brief Get a flag indicating that a layer does not have shapes within the shown area + */ + bool empty_within_view_predicate (const QModelIndex &index) const; + void search_children (const tl::GlobPattern &pattern, const QModelIndex &parent, bool recurse); };