Fixing issue #1864 (Copy & paste allows creating a recursive hierarchy)

This commit is contained in:
Matthias Koefferlein 2024-09-20 23:07:09 +02:00
parent ff708186ec
commit 5ece4d74ae
2 changed files with 33 additions and 13 deletions

View File

@ -156,6 +156,11 @@ ClipboardData::add (const db::Layout &layout, const db::Cell &cell, unsigned int
std::vector<unsigned int>
ClipboardData::do_insert (db::Layout &layout, const db::ICplxTrans *trans, db::Cell *cell, std::vector<db::cell_index_type> *new_tops, ClipboardDataInsertReceiver *insert_receiver) const
{
// identify the cells our target is eventually called from, including itself
std::set<db::cell_index_type> callers;
cell->collect_caller_cells (callers);
callers.insert (cell->cell_index ());
std::vector <unsigned int> new_layers;
PropertyMapper prop_id_map (&layout, &m_layout);
@ -279,14 +284,21 @@ ClipboardData::do_insert (db::Layout &layout, const db::ICplxTrans *trans, db::C
for (db::Cell::const_iterator inst = c->begin (); ! inst.at_end (); ++inst) {
tl::const_map<db::cell_index_type> im (cell_map.find (inst->cell_index ())->second);
db::Instance new_inst = t.insert (*inst, im, prop_id_map);
if (trans) {
new_inst = t.transform (new_inst, *trans);
}
db::cell_index_type inst_cell = cell_map.find (inst->cell_index ())->second;
if (callers.find (inst_cell) == callers.end ()) {
if (insert_receiver) {
insert_receiver->instance_inserted (cp->second, new_inst);
tl::const_map<db::cell_index_type> im (inst_cell);
db::Instance new_inst = t.insert (*inst, im, prop_id_map);
if (trans) {
new_inst = t.transform (new_inst, *trans);
}
if (insert_receiver) {
insert_receiver->instance_inserted (cp->second, new_inst);
}
} else {
tl::warn << tl::sprintf (tl::to_string (tr ("Refusing to paste an instance for cell %s, as this would create a recursive hierarchy")), layout.cell_name (inst_cell));
}
}

View File

@ -2667,8 +2667,22 @@ MainService::paste ()
{
if (view ()->is_editable ()) {
// skip, if there is nothing to insert
bool any = false;
for (db::Clipboard::iterator c = db::Clipboard::instance ().begin (); c != db::Clipboard::instance ().end () && ! any; ++c) {
const db::ClipboardValue<edt::ClipboardData> *value = dynamic_cast<const db::ClipboardValue<edt::ClipboardData> *> (*c);
any = (value != 0);
}
if (! any) {
return;
}
int cv_index = view ()->active_cellview_index ();
const lay::CellView &cv = view ()->cellview (cv_index);
if (! cv.is_valid ()) {
throw tl::Exception (tl::to_string (tr ("No cell selected to paste something into")));
}
NewObjectsSelection insert_notification (cv_index, cv.cell_index (), view ());
@ -2678,14 +2692,8 @@ MainService::paste ()
for (db::Clipboard::iterator c = db::Clipboard::instance ().begin (); c != db::Clipboard::instance ().end (); ++c) {
const db::ClipboardValue<edt::ClipboardData> *value = dynamic_cast<const db::ClipboardValue<edt::ClipboardData> *> (*c);
if (value) {
if (! cv.is_valid ()) {
throw tl::Exception (tl::to_string (tr ("No cell selected to paste something into")));
}
std::vector<unsigned int> nl = value->get ().insert (cv->layout (), cv.context_trans ().inverted (), &cv->layout ().cell (cv.cell_index ()), 0 /*new_tops*/, &insert_notification);
new_layers.insert (new_layers.end (), nl.begin (), nl.end ());
}
}