First draft of solution. Needs polishing.

This commit is contained in:
Matthias Koefferlein 2024-06-01 18:48:21 +02:00
parent d28822af3f
commit 5ee1daf945
9 changed files with 558 additions and 183 deletions

View File

@ -23,4 +23,78 @@
#include "dbInstElement.h"
// nothing yet ..
namespace db
{
// ------------------------------------------------------------
// "to_string" implementation
std::string
InstElement::to_string (bool resolve_cell_name) const
{
if (inst_ptr.is_null ()) {
return std::string ();
}
db::cell_index_type ci = inst_ptr.cell_index ();
std::string r;
if (resolve_cell_name && inst_ptr.instances () && inst_ptr.instances ()->cell () && inst_ptr.instances ()->cell ()->layout ()) {
r = inst_ptr.instances ()->cell ()->layout ()->cell_name (ci);
} else {
r = "cell_index=" + tl::to_string (ci);
}
r += " " + complex_trans ().to_string ();
return r;
}
// ------------------------------------------------------------
// Implementation of "find_path"
static bool
find_path (const db::Layout &layout, db::cell_index_type from, db::cell_index_type to, std::set <db::cell_index_type> &visited, std::vector<db::InstElement> &path)
{
const db::Cell &cell = layout.cell (from);
for (db::Cell::parent_inst_iterator p = cell.begin_parent_insts (); ! p.at_end (); ++p) {
if (p->parent_cell_index () == to) {
path.push_back (db::InstElement (p->child_inst ()));
return true;
} else if (visited.find (p->parent_cell_index ()) == visited.end ()) {
visited.insert (p->parent_cell_index ());
path.push_back (db::InstElement (p->child_inst ()));
if (find_path (layout, p->parent_cell_index (), to, visited, path)) {
return true;
}
path.pop_back ();
}
}
return false;
}
bool
find_path (const db::Layout &layout, db::cell_index_type from, db::cell_index_type to, std::vector<db::InstElement> &path)
{
path.clear ();
if (from == to) {
return true;
} else {
std::set <db::cell_index_type> v;
if (find_path (layout, from, to, v, path)) {
std::reverse (path.begin (), path.end ());
return true;
} else {
return false;
}
}
}
}

View File

@ -150,8 +150,23 @@ struct DB_PUBLIC InstElement
{
return inst_ptr.cell_inst ().complex_trans (*array_inst);
}
/**
* @brief Returns a string representation of the element
*/
std::string to_string (bool resolve_cell_name = false) const;
};
/**
* @brief Finds a path from the "from" to the "to" cell
*
* This function will determine one representative instantiation path leading
* from the "from" cell to the "to" cell. If such a path exists, it is stored
* in "path" and true is returned. If no such path exists, false is returned.
*/
DB_PUBLIC bool
find_path (const db::Layout &layout, db::cell_index_type from, db::cell_index_type to, std::vector<db::InstElement> &path);
} // namespace db
#endif

View File

@ -24,6 +24,7 @@
#include "dbLayoutQuery.h"
#include "dbCellGraphUtils.h"
#include "dbStreamLayers.h"
#include "dbInstElement.h"
#include "tlAssert.h"
#include "tlString.h"
#include "tlGlobPattern.h"
@ -476,6 +477,7 @@ struct ChildCellFilterPropertyIDs
{
path = q->register_property ("path", LQ_variant);
path_names = q->register_property ("path_names", LQ_variant);
inst_elements = q->register_property ("inst_elements", LQ_variant);
initial_cell = q->register_property ("initial_cell", LQ_cell);
initial_cell_index = q->register_property ("initial_cell_index", LQ_variant);
initial_cell_name = q->register_property ("initial_cell_name", LQ_variant);
@ -573,6 +575,7 @@ struct ChildCellFilterPropertyIDs
unsigned int inst_bbox; // inst_bbox -> The instance bounding box in the top cell
unsigned int inst_dbbox; // inst_dbbox -> The instance bounding box in the top cell in micrometer units
unsigned int inst; // inst -> The instance object
unsigned int inst_elements; // inst_elements -> Variant array with the db::InstElement objects for the path
unsigned int array_a; // array_a -> The a vector for an array instance
unsigned int array_da; // array_da -> The a vector for an array instance in micrometer units
unsigned int array_na; // array_na -> The a axis array dimension
@ -990,6 +993,31 @@ public:
v.push (tl::Variant (cell_index ()));
return true;
} else if (id == m_pids.inst_elements) {
if (! v.is_list ()) {
std::vector<tl::Variant> vd;
v = tl::Variant (vd.begin (), vd.end ());
}
if (mp_parent) {
FilterStateBase::get_property (id, v);
}
db::Instance inst;
if (m_reading) {
inst = mp_parent->sorted_inst_ptr (std::distance (mp_parent->begin_sorted_insts (), m_inst));
} else {
inst = m_i;
}
if (m_instance_mode == ArrayInstances) {
v.push (tl::Variant (db::InstElement (inst)));
} else {
v.push (tl::Variant (db::InstElement (inst, m_array_iter)));
}
return true;
} else if (id == m_pids.path_names) {
if (! v.is_list ()) {

View File

@ -1913,9 +1913,185 @@ Service::handle_guiding_shape_changes ()
}
}
// -------------------------------------------------------------
// Implementation of EditableSelectionIterator
EditableSelectionIterator::EditableSelectionIterator (const std::vector<edt::Service *> &services, bool transient)
: m_services (services), m_service (0), m_transient_selection (transient)
{
if (! m_services.empty ()) {
if (m_transient_selection) {
m_iter = m_services [m_service]->transient_selection ().begin ();
m_end = m_services [m_service]->transient_selection ().end ();
} else {
m_iter = m_services [m_service]->selection ().begin ();
m_end = m_services [m_service]->selection ().end ();
}
next ();
}
}
bool
EditableSelectionIterator::at_end () const
{
return (m_service >= m_services.size ());
}
EditableSelectionIterator &
EditableSelectionIterator::operator++ ()
{
++m_iter;
next ();
return *this;
}
const EditableSelectionIterator::value_type &
EditableSelectionIterator::operator* () const
{
return *m_iter;
}
void
EditableSelectionIterator::next ()
{
while (m_iter == m_end) {
++m_service;
if (m_service < m_services.size ()) {
if (m_transient_selection) {
m_iter = m_services [m_service]->transient_selection ().begin ();
m_end = m_services [m_service]->transient_selection ().end ();
} else {
m_iter = m_services [m_service]->selection ().begin ();
m_end = m_services [m_service]->selection ().end ();
}
} else {
break;
}
}
}
// -------------------------------------------------------------
// Selection utilities implementation
/**
* @brief Gets the combined selections over all editor services in the layout view
*/
std::vector<edt::Service::objects::value_type> object_selection (const lay::LayoutViewBase *view)
{
std::vector<edt::Service::objects::value_type> result;
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
std::vector<edt::Service::objects::value_type> sel;
(*s)->get_selection (sel);
result.insert (result.end (), sel.begin (), sel.end ());
}
return result;
}
/**
* @brief Distributes the combined selection over all editor services in the layout view
*/
void set_object_selection (const lay::LayoutViewBase *view, const std::vector<edt::Service::objects::value_type> &all_selected)
{
std::vector<edt::Service::objects::value_type> sel;
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
sel.clear ();
for (std::vector<edt::Service::objects::value_type>::const_iterator o = all_selected.begin (); o != all_selected.end (); ++o) {
if ((*s)->selection_applies (*o)) {
sel.push_back (*o);
}
}
(*s)->set_selection (sel.begin (), sel.end ());
}
}
/**
* @brief Gets a value indicating whether any editor service in the view has a selection
*/
bool has_object_selection (const lay::LayoutViewBase *view)
{
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
if ((*s)->has_selection ()) {
return true;
}
}
return false;
}
/**
* @brief Clears the selection of all editor services in the view
*/
void clear_object_selection (const lay::LayoutViewBase *view)
{
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
(*s)->clear_selection ();
}
}
/**
* @brief Selects a specific object in the appropriate editor service of the view
*/
void select_object (const lay::LayoutViewBase *view, const edt::Service::objects::value_type &object)
{
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
if ((*s)->selection_applies (object)) {
(*s)->add_selection (object);
break;
}
}
}
/**
* @brief Unselects a specific object in the appropriate editor service of the view
*/
void unselect_object (const lay::LayoutViewBase *view, const edt::Service::objects::value_type &object)
{
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
if ((*s)->selection_applies (object)) {
(*s)->remove_selection (object);
break;
}
}
}
/**
* @brief Gets a value indicating whether any editor service in the view has a transient selection
*/
bool has_transient_object_selection (const lay::LayoutViewBase *view)
{
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
if ((*s)->has_transient_selection ()) {
return true;
}
}
return false;
}
/**
* @brief Iterates over all selected object of all editor services
*/
EditableSelectionIterator begin_objects_selected (const lay::LayoutViewBase *view)
{
return EditableSelectionIterator (view->get_plugins <edt::Service> (), false);
}
/**
* @brief Iterates over all transiently selected object of all editor services
*/
EditableSelectionIterator begin_objects_selected_transient (const lay::LayoutViewBase *view)
{
return EditableSelectionIterator (view->get_plugins <edt::Service> (), true);
}
} // namespace edt

View File

@ -688,6 +688,80 @@ private:
void update_vector_snapped_marker (const lay::InstanceMarker *sm, const db::DTrans &trans, db::DVector &vr, bool &result_set, size_t &count) const;
};
/**
* @brief A utility class to implement a selection iterator across all editor services
*/
class EditableSelectionIterator
{
public:
typedef edt::Service::objects::value_type value_type;
typedef edt::Service::objects::const_iterator iterator_type;
typedef void pointer;
typedef const value_type &reference;
typedef std::forward_iterator_tag iterator_category;
typedef void difference_type;
EditableSelectionIterator (const std::vector<edt::Service *> &services, bool transient);
bool at_end () const;
EditableSelectionIterator &operator++ ();
const value_type &operator* () const;
private:
std::vector<edt::Service *> m_services;
unsigned int m_service;
bool m_transient_selection;
iterator_type m_iter, m_end;
void next ();
};
/**
* @brief Gets the combined selections over all editor services in the layout view
*/
EDT_PUBLIC std::vector<edt::Service::objects::value_type> object_selection (const lay::LayoutViewBase *view);
/**
* @brief Distributes the combined selection over all editor services in the layout view
*/
EDT_PUBLIC void set_object_selection (const lay::LayoutViewBase *view, const std::vector<edt::Service::objects::value_type> &all_selected);
/**
* @brief Gets a value indicating whether any editor service in the view has a selection
*/
EDT_PUBLIC bool has_object_selection (const lay::LayoutViewBase *view);
/**
* @brief Clears the selection of all editor services in the view
*/
EDT_PUBLIC void clear_object_selection (const lay::LayoutViewBase *view);
/**
* @brief Selects a specific object in the appropriate editor service of the view
*/
EDT_PUBLIC void select_object (const lay::LayoutViewBase *view, const edt::Service::objects::value_type &object);
/**
* @brief Unselects a specific object in the appropriate editor service of the view
*/
EDT_PUBLIC void unselect_object (const lay::LayoutViewBase *view, const edt::Service::objects::value_type &object);
/**
* @brief Gets a value indicating whether any editor service in the view has a transient selection
*/
EDT_PUBLIC bool has_transient_object_selection (const lay::LayoutViewBase *view);
/**
* @brief Iterates over all selected object of all editor services
*/
EDT_PUBLIC EditableSelectionIterator begin_objects_selected (const lay::LayoutViewBase *view);
/**
* @brief Iterates over all transiently selected object of all editor services
*/
EDT_PUBLIC EditableSelectionIterator begin_objects_selected_transient (const lay::LayoutViewBase *view);
}
#endif

View File

@ -185,7 +185,7 @@ gsi::Class<lay::ObjectInstPath> decl_ObjectInstPath ("lay", "ObjectInstPath",
"\n"
"The top cell is identical to the current cell provided by the cell view.\n"
"It is the cell from which is instantiation path originates and the container cell "
"if not instantiation path is set.\n"
"if no instantiation path is set.\n"
"\n"
"This method has been introduced in version 0.24."
) +
@ -425,175 +425,12 @@ gsi::Class<lay::ObjectInstPath> decl_ObjectInstPath ("lay", "ObjectInstPath",
"in the way shown above will help avoiding this issue.\n"
);
class EditableSelectionIterator
{
public:
typedef edt::Service::objects::value_type value_type;
typedef edt::Service::objects::const_iterator iterator_type;
typedef void pointer;
typedef const value_type &reference;
typedef std::forward_iterator_tag iterator_category;
typedef void difference_type;
EditableSelectionIterator (const std::vector<edt::Service *> &services, bool transient)
: m_services (services), m_service (0), m_transient_selection (transient)
{
if (! m_services.empty ()) {
if (m_transient_selection) {
m_iter = m_services [m_service]->transient_selection ().begin ();
m_end = m_services [m_service]->transient_selection ().end ();
} else {
m_iter = m_services [m_service]->selection ().begin ();
m_end = m_services [m_service]->selection ().end ();
}
next ();
}
}
bool at_end () const
{
return (m_service >= m_services.size ());
}
EditableSelectionIterator &operator++ ()
{
++m_iter;
next ();
return *this;
}
const value_type &operator* () const
{
return *m_iter;
}
private:
std::vector<edt::Service *> m_services;
unsigned int m_service;
bool m_transient_selection;
iterator_type m_iter, m_end;
void next ()
{
while (m_iter == m_end) {
++m_service;
if (m_service < m_services.size ()) {
if (m_transient_selection) {
m_iter = m_services [m_service]->transient_selection ().begin ();
m_end = m_services [m_service]->transient_selection ().end ();
} else {
m_iter = m_services [m_service]->selection ().begin ();
m_end = m_services [m_service]->selection ().end ();
}
} else {
break;
}
}
}
};
// extend the layout view by "edtService" specific methods
static std::vector<edt::Service::objects::value_type> object_selection (const lay::LayoutViewBase *view)
{
std::vector<edt::Service::objects::value_type> result;
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
std::vector<edt::Service::objects::value_type> sel;
(*s)->get_selection (sel);
result.insert (result.end (), sel.begin (), sel.end ());
}
return result;
}
static void set_object_selection (const lay::LayoutViewBase *view, const std::vector<edt::Service::objects::value_type> &all_selected)
{
std::vector<edt::Service::objects::value_type> sel;
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
sel.clear ();
for (std::vector<edt::Service::objects::value_type>::const_iterator o = all_selected.begin (); o != all_selected.end (); ++o) {
if ((*s)->selection_applies (*o)) {
sel.push_back (*o);
}
}
(*s)->set_selection (sel.begin (), sel.end ());
}
}
static bool has_object_selection (const lay::LayoutViewBase *view)
{
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
if ((*s)->has_selection ()) {
return true;
}
}
return false;
}
static void clear_object_selection (const lay::LayoutViewBase *view)
{
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
(*s)->clear_selection ();
}
}
static void select_object (const lay::LayoutViewBase *view, const edt::Service::objects::value_type &object)
{
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
if ((*s)->selection_applies (object)) {
(*s)->add_selection (object);
break;
}
}
}
static void unselect_object (const lay::LayoutViewBase *view, const edt::Service::objects::value_type &object)
{
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
if ((*s)->selection_applies (object)) {
(*s)->remove_selection (object);
break;
}
}
}
static bool has_transient_object_selection (const lay::LayoutViewBase *view)
{
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
if ((*s)->has_transient_selection ()) {
return true;
}
}
return false;
}
static EditableSelectionIterator begin_objects_selected (const lay::LayoutViewBase *view)
{
return EditableSelectionIterator (view->get_plugins <edt::Service> (), false);
}
static EditableSelectionIterator begin_objects_selected_transient (const lay::LayoutViewBase *view)
{
return EditableSelectionIterator (view->get_plugins <edt::Service> (), true);
}
static
gsi::ClassExt<lay::LayoutViewBase> layout_view_decl (
gsi::method_ext ("has_object_selection?", &has_object_selection,
gsi::method_ext ("has_object_selection?", &edt::has_object_selection,
"@brief Returns true, if geometrical objects (shapes or cell instances) are selected in this view"
) +
gsi::method_ext ("object_selection", &object_selection,
gsi::method_ext ("object_selection", &edt::object_selection,
"@brief Returns a list of selected objects\n"
"This method will deliver an array of \\ObjectInstPath objects listing the selected geometrical "
"objects. Other selected objects such as annotations and images will not be contained in that "
@ -607,7 +444,7 @@ gsi::ClassExt<lay::LayoutViewBase> layout_view_decl (
"\n"
"This method has been introduced in version 0.24.\n"
) +
gsi::method_ext ("object_selection=", &set_object_selection, gsi::arg ("sel"),
gsi::method_ext ("object_selection=", &edt::set_object_selection, gsi::arg ("sel"),
"@brief Sets the list of selected objects\n"
"\n"
"This method will set the selection of geometrical objects such as shapes and instances. "
@ -617,13 +454,13 @@ gsi::ClassExt<lay::LayoutViewBase> layout_view_decl (
"\n"
"This method has been introduced in version 0.24.\n"
) +
gsi::method_ext ("clear_object_selection", &clear_object_selection,
gsi::method_ext ("clear_object_selection", &edt::clear_object_selection,
"@brief Clears the selection of geometrical objects (shapes or cell instances)\n"
"The selection of other objects (such as annotations and images) will not be affected.\n"
"\n"
"This method has been introduced in version 0.24\n"
) +
gsi::method_ext ("select_object", &select_object, gsi::arg ("obj"),
gsi::method_ext ("select_object", &edt::select_object, gsi::arg ("obj"),
"@brief Adds the given selection to the list of selected objects\n"
"\n"
"The selection provided by the \\ObjectInstPath descriptor is added to the list of selected objects.\n"
@ -635,7 +472,7 @@ gsi::ClassExt<lay::LayoutViewBase> layout_view_decl (
"\n"
"This method has been introduced in version 0.24\n"
) +
gsi::method_ext ("unselect_object", &unselect_object, gsi::arg ("obj"),
gsi::method_ext ("unselect_object", &edt::unselect_object, gsi::arg ("obj"),
"@brief Removes the given selection from the list of selected objects\n"
"\n"
"The selection provided by the \\ObjectInstPath descriptor is removed from the list of selected objects.\n"
@ -644,7 +481,7 @@ gsi::ClassExt<lay::LayoutViewBase> layout_view_decl (
"\n"
"This method has been introduced in version 0.24\n"
) +
gsi::iterator_ext ("each_object_selected", &begin_objects_selected,
gsi::iterator_ext ("each_object_selected", &edt::begin_objects_selected,
"@brief Iterates over each selected geometrical object, yielding a \\ObjectInstPath object for each of them\n"
"\n"
"This iterator will deliver const objects - they cannot be modified. In order to modify the selection, "
@ -653,7 +490,7 @@ gsi::ClassExt<lay::LayoutViewBase> layout_view_decl (
"\n"
"Another way of obtaining the selection is \\object_selection, which returns an array of \\ObjectInstPath objects.\n"
) +
gsi::method_ext ("has_transient_object_selection?", &has_transient_object_selection,
gsi::method_ext ("has_transient_object_selection?", &edt::has_transient_object_selection,
"@brief Returns true, if geometrical objects (shapes or cell instances) are selected in this view in the transient selection\n"
"\n"
"The transient selection represents the objects selected when the mouse hovers over the "
@ -662,7 +499,7 @@ gsi::ClassExt<lay::LayoutViewBase> layout_view_decl (
"\n"
"This method was introduced in version 0.18."
) +
gsi::iterator_ext ("each_object_selected_transient", &begin_objects_selected_transient,
gsi::iterator_ext ("each_object_selected_transient", &edt::begin_objects_selected_transient,
"@brief Iterates over each geometrical objects in the transient selection, yielding a \\ObjectInstPath object for each of them\n"
"\n"
"This method was introduced in version 0.18."

View File

@ -39,6 +39,7 @@
#include "tlProgress.h"
#include "tlTimer.h"
#include "rdbUtils.h"
#include "edtService.h"
#include <QInputDialog>
#include <QHeaderView>
@ -457,6 +458,73 @@ escape_csv (const std::string &s)
}
}
void
SearchReplaceResults::select_items (lay::LayoutViewBase *view, int cv_index)
{
const lay::CellView &cv = view->cellview (cv_index);
const db::Layout &layout = cv->layout ();
std::vector<edt::Service::objects::value_type> sel;
int n_rows = int (size ());
for (int r = 0; r < n_rows; ++r) {
if (r < int (shapes ().size ())) {
const SearchReplaceResults::QueryShapeResult &sr = shapes () [r];
if (! sr.shape.is_null () && layout.is_valid_cell_index (sr.initial_cell_index) && layout.is_valid_cell_index (sr.cell_index)) {
sel.push_back (edt::Service::objects::value_type ());
sel.back ().set_cv_index (cv_index);
sel.back ().set_layer (sr.layer_index);
sel.back ().set_shape (sr.shape);
sel.back ().set_topcell (sr.initial_cell_index);
if (sr.inst_elements.has_value ()) {
sel.back ().assign_path (sr.inst_elements->begin (), sr.inst_elements->end ());
} else {
std::vector<db::InstElement> path;
if (db::find_path (layout, sr.cell_index, sr.initial_cell_index, path)) {
sel.back ().assign_path (path.begin (), path.end ());
} else {
sel.pop_back ();
}
}
}
} else if (r < int (instances ().size ())) {
const SearchReplaceResults::QueryInstResult &ir = instances () [r];
if (! ir.inst.is_null () && layout.is_valid_cell_index (ir.initial_cell_index) && layout.is_valid_cell_index (ir.cell_index)) {
sel.push_back (edt::Service::objects::value_type ());
sel.back ().set_cv_index (cv_index);
sel.back ().set_topcell (ir.initial_cell_index);
if (ir.inst_elements.has_value ()) {
sel.back ().assign_path (ir.inst_elements->begin (), ir.inst_elements->end ());
sel.back ().add_path (db::InstElement (ir.inst));
} else {
std::vector<db::InstElement> path;
if (db::find_path (layout, ir.cell_index, ir.initial_cell_index, path)) {
sel.back ().assign_path (path.begin (), path.end ());
// TODO: specific array instance?
sel.back ().add_path (db::InstElement (ir.inst));
} else {
sel.pop_back ();
}
}
}
}
}
edt::set_object_selection (view, sel);
}
void
SearchReplaceResults::export_csv (const std::string &file)
{
@ -751,6 +819,7 @@ SearchReplaceDialog::SearchReplaceDialog (lay::Dispatcher *root, LayoutViewBase
menu->addAction (QObject::tr ("To CSV file"), this, SLOT (export_csv ()));
menu->addAction (QObject::tr ("To report database"), this, SLOT (export_rdb ()));
menu->addAction (QObject::tr ("To layout"), this, SLOT (export_layout ()));
menu->addAction (QObject::tr ("Select items"), this, SLOT (select_items ()));
export_b->setMenu (menu);
bool editable = view->is_editable ();
@ -933,6 +1002,38 @@ SearchReplaceDialog::save_state ()
}
}
void
SearchReplaceDialog::select_items ()
{
BEGIN_PROTECTED
int cv_index = m_last_query_cv_index;
const lay::CellView &cv = mp_view->cellview (cv_index);
if (! cv.is_valid ()) {
return;
}
db::LayoutQuery lq (m_last_query);
tl::AbsoluteProgress progress (tl::to_string (QObject::tr ("Running query")));
progress.set_unit (100000);
progress.set_format ("Processing ..");
db::LayoutQueryIterator iq (lq, &cv->layout (), 0, &progress);
if (tl::verbosity () >= 10) {
tl::log << tl::to_string (QObject::tr ("Running query: ")) << m_last_query;
}
SearchReplaceResults model;
model.begin_changes (& cv->layout ());
query_to_model (model, lq, iq, std::numeric_limits<size_t>::max (), true, true /*with paths*/);
model.end_changes ();
model.select_items (view (), cv_index);
END_PROTECTED
}
void
SearchReplaceDialog::export_csv ()
{
@ -1434,7 +1535,7 @@ SearchReplaceDialog::update_results (const std::string &q)
}
try {
fill_model (lq, iq, &cv->layout (), true);
fill_model (lq, iq, &cv->layout (), true, false);
attach_layout (&cv->layout ());
} catch (...) {
attach_layout (&cv->layout ());
@ -1445,7 +1546,7 @@ SearchReplaceDialog::update_results (const std::string &q)
}
bool
SearchReplaceDialog::query_to_model (SearchReplaceResults &model, const db::LayoutQuery &lq, db::LayoutQueryIterator &iq, size_t max_item_count, bool all)
SearchReplaceDialog::query_to_model (SearchReplaceResults &model, const db::LayoutQuery &lq, db::LayoutQueryIterator &iq, size_t max_item_count, bool all, bool with_path)
{
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (QObject::tr ("Query run")));
@ -1456,6 +1557,7 @@ SearchReplaceDialog::query_to_model (SearchReplaceResults &model, const db::Layo
int shape_prop_id = lq.has_property ("shape") ? int (lq.property_by_name ("shape")) : -1;
int layer_index_prop_id = lq.has_property ("layer_index") ? int (lq.property_by_name ("layer_index")) : -1;
int instance_prop_id = lq.has_property ("inst") ? int (lq.property_by_name ("inst")) : -1;
int inst_elements_prop_id = with_path && lq.has_property ("inst_elements") ? int (lq.property_by_name ("inst_elements")) : -1;
int path_trans_prop_id = lq.has_property ("path_trans") ? int (lq.property_by_name ("path_trans")) : -1;
int trans_prop_id = lq.has_property ("trans") ? int (lq.property_by_name ("trans")) : -1;
int cell_index_prop_id = lq.has_property ("cell_index") ? int (lq.property_by_name ("cell_index")) : -1;
@ -1503,6 +1605,18 @@ SearchReplaceDialog::query_to_model (SearchReplaceResults &model, const db::Layo
model.push_back (SearchReplaceResults::QueryShapeResult (shape, layer_index, trans, cell_index, initial_cell_index));
if (inst_elements_prop_id >= 0 && iq.get (inst_elements_prop_id, v) && v.is_list ()) {
try {
std::vector<db::InstElement> inst_elements;
for (auto i = v.begin (); i != v.end (); ++i) {
inst_elements.push_back (i->to_user<db::InstElement> ());
}
model.shapes ().back ().inst_elements = std::move (inst_elements);
} catch (...) {
// ignore conversion errors
}
}
} else if (instance_prop_id >= 0) {
db::Instance instance;
@ -1529,6 +1643,18 @@ SearchReplaceDialog::query_to_model (SearchReplaceResults &model, const db::Layo
model.push_back (SearchReplaceResults::QueryInstResult (instance, trans, cell_index, initial_cell_index));
if (inst_elements_prop_id >= 0 && iq.get (inst_elements_prop_id, v) && v.is_list ()) {
try {
std::vector<db::InstElement> inst_elements;
for (auto i = v.begin (); i != v.end (); ++i) {
inst_elements.push_back (i->to_user<db::InstElement> ());
}
model.instances ().back ().inst_elements = std::move (inst_elements);
} catch (...) {
// ignore conversion errors
}
}
} else if (cell_index_prop_id >= 0) {
db::cell_index_type cell_index = std::numeric_limits<db::cell_index_type>::max ();
@ -1559,7 +1685,7 @@ SearchReplaceDialog::query_to_model (SearchReplaceResults &model, const db::Layo
}
bool
SearchReplaceDialog::fill_model (const db::LayoutQuery &lq, db::LayoutQueryIterator &iq, const db::Layout *layout, bool all)
SearchReplaceDialog::fill_model (const db::LayoutQuery &lq, db::LayoutQueryIterator &iq, const db::Layout *layout, bool all, bool with_paths)
{
bool res = false;
@ -1568,7 +1694,7 @@ SearchReplaceDialog::fill_model (const db::LayoutQuery &lq, db::LayoutQueryItera
m_model.begin_changes (layout);
m_model.clear ();
res = query_to_model (m_model, lq, iq, m_max_item_count, all);
res = query_to_model (m_model, lq, iq, m_max_item_count, all, with_paths);
m_model.end_changes ();
results_stack->setCurrentIndex (0);

View File

@ -32,6 +32,8 @@
#include "dbLayout.h"
#include "dbShape.h"
#include "dbInstances.h"
#include "dbInstElement.h"
#include "tlOptional.h"
#include <QAbstractItemModel>
@ -67,6 +69,7 @@ public:
db::ICplxTrans trans;
db::cell_index_type cell_index;
db::cell_index_type initial_cell_index;
tl::optional<std::vector<db::InstElement> > inst_elements;
};
struct QueryInstResult
@ -79,6 +82,7 @@ public:
db::ICplxTrans trans;
db::cell_index_type cell_index;
db::cell_index_type initial_cell_index;
tl::optional<std::vector<db::InstElement> > inst_elements;
};
struct QueryCellResult
@ -106,21 +110,41 @@ public:
return m_data_result;
}
std::vector<tl::Variant> &data ()
{
return m_data_result;
}
const std::vector<QueryShapeResult> &shapes () const
{
return m_shape_result;
}
std::vector<QueryShapeResult> &shapes ()
{
return m_shape_result;
}
const std::vector<QueryInstResult> &instances () const
{
return m_inst_result;
}
std::vector<QueryInstResult> &instances ()
{
return m_inst_result;
}
const std::vector<QueryCellResult> &cells () const
{
return m_cell_result;
}
std::vector<QueryCellResult> &cells ()
{
return m_cell_result;
}
int columnCount (const QModelIndex &parent) const;
QVariant data (const QModelIndex &index, int role) const;
Qt::ItemFlags flags (const QModelIndex &index) const;
@ -135,6 +159,7 @@ public:
void export_csv (const std::string &file);
void export_layout (db::Layout &layout);
void export_rdb (rdb::Database &rdb, double dbu);
void select_items (LayoutViewBase *view, int cv_index);
private:
std::vector<tl::Variant> m_data_result;
@ -212,6 +237,7 @@ private slots:
void header_columns_changed (int from, int to);
void cancel ();
void cancel_exec ();
void select_items ();
void export_csv ();
void export_rdb ();
void export_layout ();
@ -227,8 +253,8 @@ private:
void issue_query (const std::string &q, const std::set<size_t> *selected_items, bool with_results);
void update_results (const std::string &q);
void remove_markers ();
bool fill_model (const db::LayoutQuery &lq, db::LayoutQueryIterator &iq, const db::Layout *layout, bool all);
bool query_to_model (SearchReplaceResults &model, const db::LayoutQuery &lq, db::LayoutQueryIterator &iq, size_t max_item_count, bool all);
bool fill_model (const db::LayoutQuery &lq, db::LayoutQueryIterator &iq, const db::Layout *layout, bool all, bool with_paths);
bool query_to_model (SearchReplaceResults &model, const db::LayoutQuery &lq, db::LayoutQueryIterator &iq, size_t max_item_count, bool all, bool with_path = false);
void attach_layout (db::Layout *layout);
void layout_changed ();

View File

@ -53,11 +53,30 @@ public:
m_is_valid (false)
{}
optional (const T &value) :
explicit optional (const T &value) :
m_value (value),
m_is_valid (true)
{}
explicit optional (T &&value) :
m_value (value),
m_is_valid (true)
{}
optional &operator= (const T &value)
{
m_value = value;
m_is_valid = true;
return *this;
}
optional &operator= (T &&value)
{
m_value = value;
m_is_valid = true;
return *this;
}
void reset ()
{
m_is_valid = false;