mirror of https://github.com/KLayout/klayout.git
Merge pull request #1727 from KLayout/feature/issue-1721
Feature/issue 1721
This commit is contained in:
commit
910f0824e0
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ()) {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "dbLibraryProxy.h"
|
||||
#include "dbTextWriter.h"
|
||||
#include "dbCellMapping.h"
|
||||
#include "dbInstElement.h"
|
||||
#include "tlString.h"
|
||||
#include "tlUnitTest.h"
|
||||
|
||||
|
|
@ -467,17 +468,15 @@ TEST(4)
|
|||
g.rename_cell (top, "TAP");
|
||||
EXPECT_EQ (el.cell_name_dirty, true); // but this is
|
||||
|
||||
db::properties_id_type prop_id;
|
||||
|
||||
db::PropertiesRepository::properties_set ps;
|
||||
ps.insert (std::make_pair (g.properties_repository ().prop_name_id (tl::Variant (1)), tl::Variant ("XYZ")));
|
||||
prop_id = g.properties_repository ().properties_id (ps);
|
||||
g.properties_repository ().properties_id (ps);
|
||||
EXPECT_EQ (el.property_ids_dirty, true);
|
||||
el.reset ();
|
||||
|
||||
ps.clear ();
|
||||
ps.insert (std::make_pair (g.properties_repository ().prop_name_id (tl::Variant (1)), tl::Variant ("XXX")));
|
||||
prop_id = g.properties_repository ().properties_id (ps);
|
||||
g.properties_repository ().properties_id (ps);
|
||||
EXPECT_EQ (el.property_ids_dirty, true);
|
||||
|
||||
el.layer_properties_dirty = false;
|
||||
|
|
@ -845,3 +844,30 @@ TEST(10_TranslateStringRefs)
|
|||
// after deleting the tmp layout, l is still valid
|
||||
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {TOP}\ntext 1 0 0 0 {0 0} {TEXT_NEW}\ntext 1 0 0 0 {0 0} {TEXT_NEW}\nend_cell\nend_lib\n");
|
||||
}
|
||||
|
||||
TEST(11_FindPath)
|
||||
{
|
||||
db::Manager m;
|
||||
db::Layout l (&m);
|
||||
db::Cell &top = l.cell (l.add_cell ("TOP"));
|
||||
db::Cell &a = l.cell (l.add_cell ("A"));
|
||||
db::Cell &b = l.cell (l.add_cell ("B"));
|
||||
db::Cell &c = l.cell (l.add_cell ("C"));
|
||||
l.insert_layer (db::LayerProperties (1, 0));
|
||||
|
||||
top.insert (db::CellInstArray (a.cell_index (), db::Trans (1, db::Vector ())));
|
||||
a.insert (db::CellInstArray (b.cell_index (), db::Trans (0, db::Vector (100, 200))));
|
||||
|
||||
std::vector<db::InstElement> path;
|
||||
EXPECT_EQ (db::find_path (l, c.cell_index (), top.cell_index (), path), false);
|
||||
EXPECT_EQ (path.size (), size_t (0));
|
||||
|
||||
EXPECT_EQ (db::find_path (l, top.cell_index (), top.cell_index (), path), true);
|
||||
EXPECT_EQ (path.size (), size_t (0));
|
||||
|
||||
EXPECT_EQ (db::find_path (l, b.cell_index (), top.cell_index (), path), true);
|
||||
EXPECT_EQ (path.size (), size_t (2));
|
||||
|
||||
std::string d = tl::join (path.begin (), path.end (), ";");
|
||||
EXPECT_EQ (d, "cell_index=1 r90 *1 0,0;cell_index=2 r0 *1 100,200");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include "tlProgress.h"
|
||||
#include "tlTimer.h"
|
||||
#include "rdbUtils.h"
|
||||
#include "edtService.h"
|
||||
|
||||
#include <QInputDialog>
|
||||
#include <QHeaderView>
|
||||
|
|
@ -457,8 +458,72 @@ escape_csv (const std::string &s)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
SearchReplaceResults::select_items (lay::LayoutViewBase *view, int cv_index, const std::set<int> *rows)
|
||||
{
|
||||
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 (rows && rows->find (r) == rows->end ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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)) {
|
||||
|
||||
std::vector<db::InstElement> path;
|
||||
if (db::find_path (layout, sr.initial_cell_index, cv.cell_index (), path)) {
|
||||
|
||||
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 (cv.cell_index ());
|
||||
sel.back ().assign_path (path.begin (), path.end ());
|
||||
if (sr.inst_elements.has_value ()) {
|
||||
sel.back ().add_path (sr.inst_elements->begin (), sr.inst_elements->end ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} 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)) {
|
||||
|
||||
std::vector<db::InstElement> path;
|
||||
if (db::find_path (layout, ir.initial_cell_index, cv.cell_index (), path)) {
|
||||
|
||||
sel.push_back (edt::Service::objects::value_type ());
|
||||
sel.back ().set_cv_index (cv_index);
|
||||
sel.back ().set_topcell (cv.cell_index ());
|
||||
sel.back ().assign_path (path.begin (), path.end ());
|
||||
if (ir.inst_elements.has_value ()) {
|
||||
sel.back ().add_path (ir.inst_elements->begin (), ir.inst_elements->end ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
edt::set_object_selection (view, sel);
|
||||
}
|
||||
|
||||
void
|
||||
SearchReplaceResults::export_csv (const std::string &file)
|
||||
SearchReplaceResults::export_csv (const std::string &file, const std::set<int> *rows)
|
||||
{
|
||||
std::ofstream output (file.c_str ());
|
||||
|
||||
|
|
@ -477,21 +542,25 @@ SearchReplaceResults::export_csv (const std::string &file)
|
|||
|
||||
for (size_t r = 0; r < n_rows; ++r) {
|
||||
|
||||
for (size_t c = 0; c < n_columns; ++c) {
|
||||
if (c) {
|
||||
output << ",";
|
||||
}
|
||||
// TODO: optimize
|
||||
output << escape_csv (tl::to_string (data (index (int (r), int (c), parent), Qt::DisplayRole).toString ()));
|
||||
}
|
||||
if (! rows || rows->find (r) != rows->end ()) {
|
||||
|
||||
output << std::endl;
|
||||
for (size_t c = 0; c < n_columns; ++c) {
|
||||
if (c) {
|
||||
output << ",";
|
||||
}
|
||||
// TODO: optimize
|
||||
output << escape_csv (tl::to_string (data (index (int (r), int (c), parent), Qt::DisplayRole).toString ()));
|
||||
}
|
||||
|
||||
output << std::endl;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SearchReplaceResults::export_layout (db::Layout &layout)
|
||||
SearchReplaceResults::export_layout (db::Layout &layout, const std::set<int> *rows)
|
||||
{
|
||||
if (! m_data_result.empty () || ! m_cell_result.empty () || ! m_inst_result.empty ()) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Query produces something other than shapes - such results cannot be converted to layout currently.")));
|
||||
|
|
@ -500,7 +569,12 @@ SearchReplaceResults::export_layout (db::Layout &layout)
|
|||
db::Cell &top_cell = layout.cell (layout.add_cell ("RESULTS"));
|
||||
db::LayerMap insert_lm;
|
||||
|
||||
for (std::vector<QueryShapeResult>::const_iterator s = m_shape_result.begin (); s != m_shape_result.end (); ++s) {
|
||||
int r = 0;
|
||||
for (std::vector<QueryShapeResult>::const_iterator s = m_shape_result.begin (); s != m_shape_result.end (); ++s, ++r) {
|
||||
|
||||
if (rows && rows->find (r) == rows->end ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int layer = s->layer_index;
|
||||
std::map<unsigned int, db::LayerProperties>::const_iterator lm = m_lp_map.find (layer);
|
||||
|
|
@ -523,7 +597,7 @@ SearchReplaceResults::export_layout (db::Layout &layout)
|
|||
}
|
||||
|
||||
void
|
||||
SearchReplaceResults::export_rdb (rdb::Database &rdb, double dbu)
|
||||
SearchReplaceResults::export_rdb (rdb::Database &rdb, double dbu, const std::set<int> *rows)
|
||||
{
|
||||
if (! m_cell_result.empty ()) {
|
||||
|
||||
|
|
@ -534,7 +608,12 @@ SearchReplaceResults::export_rdb (rdb::Database &rdb, double dbu)
|
|||
rdb::Category *cat = rdb.create_category ("data");
|
||||
rdb::Cell *cell = rdb.create_cell (rdb.top_cell_name ());
|
||||
|
||||
for (std::vector<tl::Variant>::const_iterator v = m_data_result.begin (); v != m_data_result.end (); ++v) {
|
||||
int r = 0;
|
||||
for (std::vector<tl::Variant>::const_iterator v = m_data_result.begin (); v != m_data_result.end (); ++v, ++r) {
|
||||
|
||||
if (rows && rows->find (r) == rows->end ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rdb::Item *item = rdb.create_item (cell->id (), cat->id ());
|
||||
|
||||
|
|
@ -560,7 +639,12 @@ SearchReplaceResults::export_rdb (rdb::Database &rdb, double dbu)
|
|||
}
|
||||
}
|
||||
|
||||
for (std::vector<QueryInstResult>::const_iterator i = m_inst_result.begin (); i != m_inst_result.end (); ++i) {
|
||||
int r = 0;
|
||||
for (std::vector<QueryInstResult>::const_iterator i = m_inst_result.begin (); i != m_inst_result.end (); ++i, ++r) {
|
||||
|
||||
if (rows && rows->find (r) == rows->end ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::map<std::pair<db::cell_index_type, db::CplxTrans>, rdb::Cell *>::const_iterator v = cells_by_variant.find (std::make_pair (i->cell_index, db::CplxTrans (i->trans)));
|
||||
if (v == cells_by_variant.end ()) {
|
||||
|
|
@ -588,7 +672,13 @@ SearchReplaceResults::export_rdb (rdb::Database &rdb, double dbu)
|
|||
|
||||
// create categories
|
||||
std::map<unsigned int, rdb::Category *> categories;
|
||||
for (std::vector<QueryShapeResult>::const_iterator s = m_shape_result.begin (); s != m_shape_result.end (); ++s) {
|
||||
|
||||
int r = 0;
|
||||
for (std::vector<QueryShapeResult>::const_iterator s = m_shape_result.begin (); s != m_shape_result.end (); ++s, ++r) {
|
||||
|
||||
if (rows && rows->find (r) == rows->end ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int layer = s->layer_index;
|
||||
std::map<unsigned int, db::LayerProperties>::const_iterator lm = m_lp_map.find (layer);
|
||||
|
|
@ -609,7 +699,12 @@ SearchReplaceResults::export_rdb (rdb::Database &rdb, double dbu)
|
|||
}
|
||||
}
|
||||
|
||||
for (std::vector<QueryShapeResult>::const_iterator s = m_shape_result.begin (); s != m_shape_result.end (); ++s) {
|
||||
r = 0;
|
||||
for (std::vector<QueryShapeResult>::const_iterator s = m_shape_result.begin (); s != m_shape_result.end (); ++s, ++r) {
|
||||
|
||||
if (rows && rows->find (r) == rows->end ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int layer = s->layer_index;
|
||||
std::map<unsigned int, rdb::Category *>::const_iterator cm = categories.find (layer);
|
||||
|
|
@ -751,8 +846,29 @@ 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 ("To selection"), this, SLOT (select_items ()));
|
||||
export_b->setMenu (menu);
|
||||
|
||||
QAction *action;
|
||||
|
||||
action = new QAction (QObject::tr ("Export to CSV file"), results);
|
||||
connect (action, SIGNAL (triggered ()), this, SLOT (sel_export_csv ()));
|
||||
results->addAction (action);
|
||||
|
||||
action = new QAction (QObject::tr ("Export to report database"), results);
|
||||
connect (action, SIGNAL (triggered ()), this, SLOT (sel_export_rdb ()));
|
||||
results->addAction (action);
|
||||
|
||||
action = new QAction (QObject::tr ("Export to layout"), results);
|
||||
connect (action, SIGNAL (triggered ()), this, SLOT (sel_export_layout ()));
|
||||
results->addAction (action);
|
||||
|
||||
action = new QAction (QObject::tr ("Export to selection"), results);
|
||||
connect (action, SIGNAL (triggered ()), this, SLOT (sel_select_items ()));
|
||||
results->addAction (action);
|
||||
|
||||
results->setContextMenuPolicy (Qt::ActionsContextMenu);
|
||||
|
||||
bool editable = view->is_editable ();
|
||||
mode_tab->setTabEnabled (replace_mode_index, editable);
|
||||
mode_tab->setTabEnabled (delete_mode_index, editable);
|
||||
|
|
@ -933,6 +1049,83 @@ SearchReplaceDialog::save_state ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
SearchReplaceDialog::sel_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;
|
||||
}
|
||||
|
||||
std::set<int> rows;
|
||||
QModelIndexList sel = results->selectionModel ()->selectedRows (0);
|
||||
for (auto s = sel.begin (); s != sel.end (); ++s) {
|
||||
rows.insert (s->row ());
|
||||
}
|
||||
|
||||
m_model.select_items (view (), cv_index, &rows);
|
||||
|
||||
END_PROTECTED
|
||||
}
|
||||
|
||||
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::sel_export_csv ()
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
|
||||
std::set<int> rows;
|
||||
QModelIndexList sel = results->selectionModel ()->selectedRows (0);
|
||||
for (auto s = sel.begin (); s != sel.end (); ++s) {
|
||||
rows.insert (s->row ());
|
||||
}
|
||||
|
||||
std::string fn;
|
||||
|
||||
lay::FileDialog file_dialog (this, tl::to_string (QObject::tr ("Export CSV")), tl::to_string (QObject::tr ("CSV Files (*.csv);;All Files (*)")), "csv");
|
||||
if (! file_dialog.get_save (fn)) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_model.export_csv (fn, &rows);
|
||||
|
||||
END_PROTECTED
|
||||
}
|
||||
|
||||
void
|
||||
SearchReplaceDialog::export_csv ()
|
||||
{
|
||||
|
|
@ -972,6 +1165,38 @@ BEGIN_PROTECTED
|
|||
END_PROTECTED
|
||||
}
|
||||
|
||||
void
|
||||
SearchReplaceDialog::sel_export_rdb ()
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
|
||||
int cv_index = m_last_query_cv_index;
|
||||
const lay::CellView &cv = mp_view->cellview (cv_index);
|
||||
if (! cv.is_valid ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::set<int> rows;
|
||||
QModelIndexList sel = results->selectionModel ()->selectedRows (0);
|
||||
for (auto s = sel.begin (); s != sel.end (); ++s) {
|
||||
rows.insert (s->row ());
|
||||
}
|
||||
|
||||
std::unique_ptr<rdb::Database> rdb (new rdb::Database ());
|
||||
|
||||
rdb->set_description (tl::to_string (QObject::tr ("Query results: ")) + m_last_query);
|
||||
rdb->set_name ("query_results");
|
||||
rdb->set_generator ("query: " + m_last_query);
|
||||
rdb->set_top_cell_name (cv->layout ().cell_name (cv.cell_index ()));
|
||||
|
||||
m_model.export_rdb (*rdb, cv->layout ().dbu (), &rows);
|
||||
|
||||
int rdb_index = mp_view->add_rdb (rdb.release ());
|
||||
mp_view->open_rdb_browser (rdb_index, cv_index);
|
||||
|
||||
END_PROTECTED
|
||||
}
|
||||
|
||||
void
|
||||
SearchReplaceDialog::export_rdb ()
|
||||
{
|
||||
|
|
@ -1014,6 +1239,25 @@ BEGIN_PROTECTED
|
|||
END_PROTECTED
|
||||
}
|
||||
|
||||
void
|
||||
SearchReplaceDialog::sel_export_layout ()
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
|
||||
std::set<int> rows;
|
||||
QModelIndexList sel = results->selectionModel ()->selectedRows (0);
|
||||
for (auto s = sel.begin (); s != sel.end (); ++s) {
|
||||
rows.insert (s->row ());
|
||||
}
|
||||
|
||||
std::unique_ptr <lay::LayoutHandle> handle (new lay::LayoutHandle (new db::Layout (mp_view->manager ()), std::string ()));
|
||||
handle->rename ("query_results");
|
||||
m_model.export_layout (handle->layout (), &rows);
|
||||
mp_view->add_layout (handle.release (), true);
|
||||
|
||||
END_PROTECTED
|
||||
}
|
||||
|
||||
void
|
||||
SearchReplaceDialog::export_layout ()
|
||||
{
|
||||
|
|
@ -1434,7 +1678,7 @@ SearchReplaceDialog::update_results (const std::string &q)
|
|||
}
|
||||
|
||||
try {
|
||||
fill_model (lq, iq, &cv->layout (), true);
|
||||
fill_model (lq, iq, &cv->layout (), true, true);
|
||||
attach_layout (&cv->layout ());
|
||||
} catch (...) {
|
||||
attach_layout (&cv->layout ());
|
||||
|
|
@ -1445,7 +1689,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 +1700,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 +1748,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 +1786,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 +1828,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 +1837,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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -132,9 +156,10 @@ public:
|
|||
int rowCount (const QModelIndex &parent) const;
|
||||
void has_more (bool hm);
|
||||
|
||||
void export_csv (const std::string &file);
|
||||
void export_layout (db::Layout &layout);
|
||||
void export_rdb (rdb::Database &rdb, double dbu);
|
||||
void export_csv (const std::string &file, const std::set<int> *rows = 0);
|
||||
void export_layout (db::Layout &layout, const std::set<int> *rows = 0);
|
||||
void export_rdb (rdb::Database &rdb, double dbu, const std::set<int> *rows = 0);
|
||||
void select_items (LayoutViewBase *view, int cv_index, const std::set<int> *rows = 0);
|
||||
|
||||
private:
|
||||
std::vector<tl::Variant> m_data_result;
|
||||
|
|
@ -212,9 +237,14 @@ 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 ();
|
||||
void sel_select_items ();
|
||||
void sel_export_csv ();
|
||||
void sel_export_rdb ();
|
||||
void sel_export_layout ();
|
||||
|
||||
private:
|
||||
std::string build_find_expression (QStackedWidget *prop_page, QComboBox *context);
|
||||
|
|
@ -227,8 +257,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 ();
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue