mirror of https://github.com/KLayout/klayout.git
Fixed #864 (Shapes#copy_shapes does not support undo/redo)
While doing so changed the following things too: - Instance and Shapes methods raise an exception if not in editable mode and with undo/redo - Faster and leaner undo/redo on Shapes#clear
This commit is contained in:
parent
bad3232415
commit
d14892382c
|
|
@ -837,6 +837,14 @@ Instance::bbox () const
|
|||
// -------------------------------------------------------------------------------------
|
||||
// Instances implementation
|
||||
|
||||
static void
|
||||
check_is_editable_for_undo_redo (const Instances *instances)
|
||||
{
|
||||
if (! instances->is_editable ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("No undo/redo support on non-editable instance lists")));
|
||||
}
|
||||
}
|
||||
|
||||
Instances::Instances (cell_type *cell)
|
||||
: mp_cell (cell)
|
||||
{
|
||||
|
|
@ -957,6 +965,10 @@ Instances::erase_positions (Tag tag, ET editable_tag, I first, I last)
|
|||
if (mp_cell) {
|
||||
mp_cell->invalidate_insts (); // HINT: must come before the change is done!
|
||||
if (mp_cell->manager () && mp_cell->manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo (this);
|
||||
if (! is_editable ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("No undo/redo support for non-editable instance lists in 'erase_positions'")));
|
||||
}
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<typename Tag::object_type, ET> (false /*not insert*/, first, last, true /*dummy*/));
|
||||
}
|
||||
}
|
||||
|
|
@ -973,6 +985,7 @@ Instances::insert (const InstArray &inst)
|
|||
|
||||
if (mp_cell) {
|
||||
if (mp_cell->manager () && mp_cell->manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo (this);
|
||||
if (editable) {
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<InstArray, InstancesEditableTag> (true /*insert*/, inst));
|
||||
} else {
|
||||
|
|
@ -999,6 +1012,7 @@ Instances::insert (I from, I to)
|
|||
|
||||
if (mp_cell) {
|
||||
if (mp_cell->manager () && mp_cell->manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo (this);
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<typename it_traits::value_type, ET> (true /*insert*/, from, to));
|
||||
}
|
||||
mp_cell->invalidate_insts ();
|
||||
|
|
@ -1049,6 +1063,7 @@ Instances::replace (const InstArray *replace, const InstArray &with)
|
|||
{
|
||||
if (mp_cell) {
|
||||
if (mp_cell->manager () && mp_cell->manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo (this);
|
||||
if (is_editable ()) {
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<InstArray, InstancesEditableTag> (false /*not insert*/, *replace));
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<InstArray, InstancesEditableTag> (true /*insert*/, with));
|
||||
|
|
@ -1138,6 +1153,7 @@ Instances::erase_inst_by_iter (Tag tag, ET editable_tag, I iter)
|
|||
if (mp_cell) {
|
||||
mp_cell->invalidate_insts ();
|
||||
if (mp_cell->manager () && mp_cell->manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo (this);
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<typename Tag::object_type, ET> (false /*not insert*/, *iter));
|
||||
}
|
||||
}
|
||||
|
|
@ -1152,6 +1168,7 @@ Instances::erase_inst_by_tag (Tag tag, ET editable_tag, const typename Tag::obje
|
|||
if (mp_cell) {
|
||||
mp_cell->invalidate_insts ();
|
||||
if (mp_cell->manager () && mp_cell->manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo (this);
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<typename Tag::object_type, ET> (false /*not insert*/, obj));
|
||||
}
|
||||
}
|
||||
|
|
@ -1183,6 +1200,7 @@ Instances::clear_insts (ET editable_tag)
|
|||
if (mp_cell) {
|
||||
mp_cell->invalidate_insts ();
|
||||
if (mp_cell->manager () && mp_cell->manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo (this);
|
||||
const Instances *const_this = this;
|
||||
if (! const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).empty ()) {
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<cell_inst_array_type, ET> (false /*not insert*/, const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).end ()));
|
||||
|
|
@ -1588,6 +1606,7 @@ void Instances::apply_op (const Op &op, ET editable_tag)
|
|||
if (mp_cell) {
|
||||
mp_cell->invalidate_insts ();
|
||||
if (mp_cell->manager () && mp_cell->manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo (this);
|
||||
transacting = true;
|
||||
if (has_insts) {
|
||||
mp_cell->manager ()->queue (mp_cell, new db::InstOp<cell_inst_array_type, ET> (false /*not insert*/, const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).begin (), const_this->inst_tree (cell_inst_array_type::tag (), editable_tag).end ()));
|
||||
|
|
|
|||
|
|
@ -131,6 +131,36 @@ layer_op<Sh, StableTag>::erase (Shapes *shapes)
|
|||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// FullLayerOp implementation
|
||||
|
||||
void
|
||||
FullLayerOp::insert (Shapes *shapes)
|
||||
{
|
||||
for (tl::vector<LayerBase *>::iterator l = shapes->get_layers ().end (); l != shapes->get_layers ().begin (); ) {
|
||||
--l;
|
||||
if (*l == mp_layer) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
shapes->get_layers ().push_back (mp_layer);
|
||||
shapes->invalidate_state ();
|
||||
m_owns_layer = false;
|
||||
}
|
||||
|
||||
void
|
||||
FullLayerOp::erase (Shapes *shapes)
|
||||
{
|
||||
for (tl::vector<LayerBase *>::iterator l = shapes->get_layers ().begin (); l != shapes->get_layers ().end (); ++l) {
|
||||
if (*l == mp_layer) {
|
||||
shapes->get_layers ().erase (l);
|
||||
shapes->invalidate_state ();
|
||||
m_owns_layer = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Shapes implementation
|
||||
|
||||
|
|
@ -155,11 +185,17 @@ Shapes::layout () const
|
|||
return c ? c->layout () : 0;
|
||||
}
|
||||
|
||||
void
|
||||
Shapes::check_is_editable_for_undo_redo () const
|
||||
{
|
||||
if (! is_editable ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("No undo/redo support on non-editable shape lists")));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Shapes::insert (const Shapes &d)
|
||||
{
|
||||
// no undo support for this currently
|
||||
tl_assert (! manager () || ! manager ()->transacting ());
|
||||
do_insert (d);
|
||||
}
|
||||
|
||||
|
|
@ -175,10 +211,18 @@ Shapes::do_insert (const Shapes &d)
|
|||
|
||||
// both shape containers reside in the same repository space - simply copy
|
||||
if (m_layers.empty ()) {
|
||||
|
||||
m_layers.reserve (d.m_layers.size ());
|
||||
for (tl::vector<LayerBase *>::const_iterator l = d.m_layers.begin (); l != d.m_layers.end (); ++l) {
|
||||
m_layers.push_back ((*l)->clone (this, manager ()));
|
||||
m_layers.push_back ((*l)->clone ());
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
manager ()->queue (this, new FullLayerOp (true, m_layers.back ()));
|
||||
}
|
||||
}
|
||||
|
||||
invalidate_state ();
|
||||
|
||||
} else {
|
||||
for (tl::vector<LayerBase *>::const_iterator l = d.m_layers.begin (); l != d.m_layers.end (); ++l) {
|
||||
(*l)->insert_into (this);
|
||||
|
|
@ -939,12 +983,19 @@ void
|
|||
Shapes::clear ()
|
||||
{
|
||||
if (!m_layers.empty ()) {
|
||||
|
||||
for (tl::vector<LayerBase *>::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) {
|
||||
(*l)->clear (this, manager ());
|
||||
delete *l;
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
manager ()->queue (this, new FullLayerOp (false, (*l)));
|
||||
} else {
|
||||
delete *l;
|
||||
}
|
||||
}
|
||||
|
||||
invalidate_state (); // HINT: must come before the change is done!
|
||||
m_layers.clear ();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1104,6 +1155,7 @@ Shapes::replace_prop_id (const Sh *pos, db::properties_id_type prop_id)
|
|||
throw tl::Exception (tl::to_string (tr ("Function 'replace' is permitted only in editable mode")));
|
||||
}
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
db::layer_op<Sh, db::stable_layer_tag>::queue_or_append (manager (), this, false /*not insert*/, *pos);
|
||||
}
|
||||
invalidate_state (); // HINT: must come before the change is done!
|
||||
|
|
@ -1123,6 +1175,7 @@ Shapes::replace_prop_id_iter (typename db::object_tag<Sh>, const Iter &iter, db:
|
|||
}
|
||||
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
db::layer_op<Sh, db::stable_layer_tag>::queue_or_append (manager (), this, false /*not insert*/, *iter);
|
||||
}
|
||||
db::object_with_properties <Sh> wp (*iter, prop_id);
|
||||
|
|
@ -1190,6 +1243,7 @@ Shapes::replace_member_with_props (typename db::object_tag<Sh> tag, const shape_
|
|||
// simple replace case
|
||||
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
db::layer_op<Sh, db::stable_layer_tag>::queue_or_append (manager (), this, false /*not insert*/, *ref.basic_ptr (tag));
|
||||
}
|
||||
|
||||
|
|
@ -1214,6 +1268,7 @@ Shapes::replace_member_with_props (typename db::object_tag<Sh> tag, const shape_
|
|||
if (! ref.with_props ()) {
|
||||
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
db::layer_op<Sh, db::stable_layer_tag>::queue_or_append (manager (), this, false /*not insert*/, *ref.basic_ptr (tag));
|
||||
}
|
||||
|
||||
|
|
@ -1234,6 +1289,7 @@ Shapes::replace_member_with_props (typename db::object_tag<Sh> tag, const shape_
|
|||
get_layer<Sh, db::stable_layer_tag> ().replace (ref.basic_iter (tag), sh);
|
||||
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
db::layer_op<Sh, db::stable_layer_tag>::queue_or_append (manager (), this, true /*insert*/, sh);
|
||||
}
|
||||
|
||||
|
|
@ -1242,6 +1298,7 @@ Shapes::replace_member_with_props (typename db::object_tag<Sh> tag, const shape_
|
|||
} else {
|
||||
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
db::layer_op<db::object_with_properties<Sh>, db::stable_layer_tag>::queue_or_append (manager (), this, false /*not insert*/, *ref.basic_ptr (typename db::object_with_properties<Sh>::tag ()));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -486,8 +486,7 @@ public:
|
|||
virtual size_t size () const = 0;
|
||||
virtual bool empty () const = 0;
|
||||
virtual void sort () = 0;
|
||||
virtual void clear (Shapes *target, db::Manager *manager) = 0;
|
||||
virtual LayerBase *clone (Shapes *target, db::Manager *manager) const = 0;
|
||||
virtual LayerBase *clone () const = 0;
|
||||
virtual void translate_into (Shapes *target, GenericRepository &rep, ArrayRepository &array_rep) const = 0;
|
||||
virtual void translate_into (Shapes *target, GenericRepository &rep, ArrayRepository &array_rep, pm_delegate_type &pm) const = 0;
|
||||
virtual void transform_into (Shapes *target, const Trans &trans, GenericRepository &rep, ArrayRepository &array_rep) const = 0;
|
||||
|
|
@ -682,6 +681,8 @@ public:
|
|||
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
|
||||
check_is_editable_for_undo_redo ();
|
||||
|
||||
tl::ident_map<db::properties_id_type> pm;
|
||||
|
||||
// for undo support iterate over the elements
|
||||
|
|
@ -721,6 +722,8 @@ public:
|
|||
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
|
||||
check_is_editable_for_undo_redo ();
|
||||
|
||||
// for undo support iterate over the elements
|
||||
for (ShapeIterator s = d.begin (ShapeIterator::All); ! s.at_end (); ++s) {
|
||||
insert (*s, trans, pm);
|
||||
|
|
@ -760,6 +763,8 @@ public:
|
|||
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
|
||||
check_is_editable_for_undo_redo ();
|
||||
|
||||
// for undo support iterate over the elements
|
||||
for (ShapeIterator s = d.begin (ShapeIterator::All); ! s.at_end (); ++s) {
|
||||
insert (*s, pm);
|
||||
|
|
@ -806,6 +811,7 @@ public:
|
|||
shape_type insert (const Sh &sh)
|
||||
{
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
if (is_editable ()) {
|
||||
db::layer_op<Sh, db::stable_layer_tag>::queue_or_append (manager (), this, true /*insert*/, sh);
|
||||
} else {
|
||||
|
|
@ -849,6 +855,7 @@ public:
|
|||
|
||||
// insert the array as a whole in non-editable mode
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
db::layer_op<db::array<Obj, Trans>, db::unstable_layer_tag>::queue_or_append (manager (), this, true /*insert*/, arr);
|
||||
}
|
||||
invalidate_state (); // HINT: must come before the change is done!
|
||||
|
|
@ -886,6 +893,7 @@ public:
|
|||
|
||||
// insert the array as a whole in non-editable mode
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
db::layer_op< db::object_with_properties< db::array<Obj, Trans> >, db::unstable_layer_tag>::queue_or_append (manager (), this, true /*insert*/, arr);
|
||||
}
|
||||
invalidate_state (); // HINT: must come before the change is done!
|
||||
|
|
@ -906,6 +914,7 @@ public:
|
|||
{
|
||||
typedef typename std::iterator_traits <Iter>::value_type value_type;
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
if (is_editable ()) {
|
||||
db::layer_op<value_type, db::stable_layer_tag>::queue_or_append (manager (), this, true /*insert*/, from, to);
|
||||
} else {
|
||||
|
|
@ -1001,6 +1010,7 @@ public:
|
|||
throw tl::Exception (tl::to_string (tr ("Function 'erase' is permitted only in editable mode")));
|
||||
}
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
db::layer_op<typename Tag::object_type, StableTag>::queue_or_append (manager (), this, false /*not insert*/, *pos);
|
||||
}
|
||||
invalidate_state (); // HINT: must come before the change is done!
|
||||
|
|
@ -1064,6 +1074,7 @@ public:
|
|||
throw tl::Exception (tl::to_string (tr ("Function 'erase' is permitted only in editable mode")));
|
||||
}
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
db::layer_op<typename Tag::object_type, StableTag>::queue_or_append (manager (), this, false /*not insert*/, from, to);
|
||||
}
|
||||
invalidate_state (); // HINT: must come before the change is done!
|
||||
|
|
@ -1090,6 +1101,7 @@ public:
|
|||
throw tl::Exception (tl::to_string (tr ("Function 'erase' is permitted only in editable mode")));
|
||||
}
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
db::layer_op<typename Tag::object_type, StableTag>::queue_or_append (manager (), this, false /*not insert*/, first, last, true /*dummy*/);
|
||||
}
|
||||
invalidate_state (); // HINT: must come before the change is done!
|
||||
|
|
@ -1480,12 +1492,20 @@ public:
|
|||
|
||||
private:
|
||||
friend class ShapeIterator;
|
||||
friend class FullLayerOp;
|
||||
|
||||
tl::vector<LayerBase *> m_layers;
|
||||
db::Cell *mp_cell; // HINT: contains "dirty" in bit 0 and "editable" in bit 1
|
||||
|
||||
void invalidate_state ();
|
||||
void do_insert (const Shapes &d);
|
||||
void check_is_editable_for_undo_redo () const;
|
||||
|
||||
// gets the layers array
|
||||
tl::vector<LayerBase *> &get_layers ()
|
||||
{
|
||||
return m_layers;
|
||||
}
|
||||
|
||||
// extract dirty flag from mp_cell
|
||||
bool is_dirty () const
|
||||
|
|
@ -1604,6 +1624,7 @@ private:
|
|||
for (typename Array::iterator a = arr.begin (); ! a.at_end (); ++a) {
|
||||
res_wp_type obj_wp (*a * arr.object (), arr.properties_id ());
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
db::layer_op<res_wp_type, db::stable_layer_tag>::queue_or_append (manager (), this, true /*insert*/, obj_wp);
|
||||
}
|
||||
l.insert (obj_wp);
|
||||
|
|
@ -1618,6 +1639,7 @@ private:
|
|||
db::layer<ResType, db::stable_layer_tag> &l = get_layer<ResType, db::stable_layer_tag> ();
|
||||
for (typename Array::iterator a = arr.begin (); ! a.at_end (); ++a) {
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
db::layer_op<ResType, db::stable_layer_tag>::queue_or_append (manager (), this, true /*insert*/, *a * arr.object ());
|
||||
}
|
||||
l.insert (*a * arr.object ());
|
||||
|
|
@ -1743,6 +1765,51 @@ private:
|
|||
void erase (Shapes *shapes);
|
||||
};
|
||||
|
||||
class FullLayerOp
|
||||
: public LayerOpBase
|
||||
{
|
||||
public:
|
||||
FullLayerOp (bool insert, LayerBase *layer)
|
||||
: m_insert (insert), mp_layer (layer), m_owns_layer (! insert)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
~FullLayerOp ()
|
||||
{
|
||||
if (m_owns_layer) {
|
||||
delete mp_layer;
|
||||
mp_layer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void undo (Shapes *shapes)
|
||||
{
|
||||
if (m_insert) {
|
||||
erase (shapes);
|
||||
} else {
|
||||
insert (shapes);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void redo (Shapes *shapes)
|
||||
{
|
||||
if (m_insert) {
|
||||
insert (shapes);
|
||||
} else {
|
||||
erase (shapes);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_insert;
|
||||
LayerBase *mp_layer;
|
||||
bool m_owns_layer;
|
||||
|
||||
void insert (Shapes *shapes);
|
||||
void erase (Shapes *shapes);
|
||||
};
|
||||
|
||||
} // namespace db
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -752,24 +752,11 @@ inline unsigned int iterator_type_mask (db::object_tag< db::object_with_properti
|
|||
return iterator_type_mask (typename Sh::tag ());
|
||||
}
|
||||
|
||||
template <class Sh, class StableTag>
|
||||
void
|
||||
layer_class<Sh, StableTag>::clear (Shapes *target, db::Manager *manager)
|
||||
{
|
||||
if (manager && manager->transacting ()) {
|
||||
manager->queue (target, new db::layer_op<Sh, StableTag> (false /*not insert*/, m_layer.begin (), m_layer.end ()));
|
||||
}
|
||||
m_layer.clear ();
|
||||
}
|
||||
|
||||
template <class Sh, class StableTag>
|
||||
LayerBase *
|
||||
layer_class<Sh, StableTag>::clone (Shapes *target, db::Manager *manager) const
|
||||
layer_class<Sh, StableTag>::clone () const
|
||||
{
|
||||
layer_class<Sh, StableTag> *r = new layer_class<Sh, StableTag> ();
|
||||
if (manager && manager->transacting ()) {
|
||||
manager->queue (target, new db::layer_op<Sh, StableTag> (true /*insert*/, m_layer.begin (), m_layer.end ()));
|
||||
}
|
||||
r->m_layer = m_layer;
|
||||
return r;
|
||||
}
|
||||
|
|
@ -877,7 +864,6 @@ layer_class<Sh, StableTag>::deref_and_transform_into (Shapes *target, const Tran
|
|||
{
|
||||
deref_and_transform_into_shapes deref_op (target);
|
||||
for (typename layer_type::iterator s = m_layer.begin (); s != m_layer.end (); ++s) {
|
||||
|
||||
deref_op (*s, trans, pm);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,8 +141,7 @@ public:
|
|||
m_layer.sort ();
|
||||
}
|
||||
|
||||
virtual void clear (Shapes *target, db::Manager *manager);
|
||||
virtual LayerBase *clone (Shapes *target, db::Manager *manager) const;
|
||||
virtual LayerBase *clone () const;
|
||||
virtual void translate_into (Shapes *target, GenericRepository &rep, ArrayRepository &array_rep) const;
|
||||
virtual void translate_into (Shapes *target, GenericRepository &rep, ArrayRepository &array_rep, pm_delegate_type &pm) const;
|
||||
virtual void transform_into (Shapes *target, const Trans &trans, GenericRepository &rep, ArrayRepository &array_rep) const;
|
||||
|
|
|
|||
|
|
@ -344,6 +344,7 @@ Shapes::erase_shape_by_tag_ws (Tag /*tag*/, StableTag /*stable_tag*/, const shap
|
|||
db::layer<typename Tag::object_type, StableTag> &l = get_layer<typename Tag::object_type, StableTag> ();
|
||||
typename db::layer<typename Tag::object_type, StableTag>::iterator i = iterator_from_shape (l, shape);
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
db::layer_op<typename Tag::object_type, StableTag>::queue_or_append (manager (), this, false /*not insert*/, *i);
|
||||
}
|
||||
invalidate_state (); // HINT: must come before the change is done!
|
||||
|
|
@ -356,6 +357,7 @@ Shapes::erase_shape_by_tag_ws (Tag /*tag*/, StableTag /*stable_tag*/, const shap
|
|||
db::layer<swp_type, StableTag> &l = get_layer<swp_type, StableTag> ();
|
||||
typename db::layer<swp_type, StableTag>::iterator i = iterator_from_shape (l, shape);
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
db::layer_op<swp_type, StableTag>::queue_or_append (manager (), this, false /*not insert*/, *i);
|
||||
}
|
||||
invalidate_state (); // HINT: must come before the change is done!
|
||||
|
|
|
|||
|
|
@ -246,12 +246,7 @@ static void insert_iter_with_trans (db::Shapes *sh, const db::RecursiveShapeIter
|
|||
|
||||
static void insert_shapes (db::Shapes *sh, const db::Shapes &s)
|
||||
{
|
||||
// NOTE: if the source (r) is from the same layout than the shapes live in, we better
|
||||
// lock the layout against updates while inserting
|
||||
db::LayoutLocker locker (sh->layout ());
|
||||
for (db::Shapes::shape_iterator i = s.begin (db::ShapeIterator::All); !i.at_end(); ++i) {
|
||||
sh->insert (*i);
|
||||
}
|
||||
sh->insert (s);
|
||||
}
|
||||
|
||||
static void insert_shapes_with_flags (db::Shapes *sh, const db::Shapes &s, unsigned int flags)
|
||||
|
|
|
|||
|
|
@ -3235,6 +3235,193 @@ TEST(23)
|
|||
EXPECT_EQ (shapes_to_string_norm (_this, s2), "edge_pair (0,0;1,1)/(10,10;11,11) #17\n");
|
||||
}
|
||||
|
||||
// Shape insert and clear and undo/redo
|
||||
TEST(24a)
|
||||
{
|
||||
db::Manager m;
|
||||
db::Shapes s1 (&m, 0, true), s2;
|
||||
|
||||
s2.insert (db::Edge (db::Point (0, 0), db::Point (100, 200)));
|
||||
s2.insert (db::Box (db::Point (0, 0), db::Point (100, 200)));
|
||||
|
||||
m.transaction ("test");
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "");
|
||||
s1.insert (s2);
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nedge (0,0;100,200) #0\n");
|
||||
m.commit ();
|
||||
|
||||
m.undo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "");
|
||||
|
||||
m.redo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nedge (0,0;100,200) #0\n");
|
||||
|
||||
m.undo ();
|
||||
s1.insert (db::Box (db::Point (1, 1), db::Point (101, 201)));
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (1,1;101,201) #0\n");
|
||||
|
||||
m.clear ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (1,1;101,201) #0\n");
|
||||
|
||||
m.transaction ("test");
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (1,1;101,201) #0\n");
|
||||
s1.insert (s2);
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nbox (1,1;101,201) #0\nedge (0,0;100,200) #0\n");
|
||||
m.commit ();
|
||||
|
||||
m.undo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (1,1;101,201) #0\n");
|
||||
|
||||
m.redo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nbox (1,1;101,201) #0\nedge (0,0;100,200) #0\n");
|
||||
|
||||
m.clear ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nbox (1,1;101,201) #0\nedge (0,0;100,200) #0\n");
|
||||
|
||||
m.transaction ("test");
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nbox (1,1;101,201) #0\nedge (0,0;100,200) #0\n");
|
||||
s1.clear ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "");
|
||||
m.commit ();
|
||||
|
||||
m.undo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nbox (1,1;101,201) #0\nedge (0,0;100,200) #0\n");
|
||||
|
||||
m.redo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "");
|
||||
|
||||
m.clear ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "");
|
||||
}
|
||||
|
||||
// Shape insert and clear and undo/redo - different layers, same layout
|
||||
TEST(24b)
|
||||
{
|
||||
db::Manager m;
|
||||
db::Layout l (true, &m);
|
||||
db::Cell &cell = l.cell (l.add_cell ("top"));
|
||||
l.insert_layer (1);
|
||||
l.insert_layer (2);
|
||||
db::Shapes &s1 = cell.shapes (1);
|
||||
db::Shapes &s2 = cell.shapes (2);
|
||||
|
||||
s2.insert (db::Edge (db::Point (0, 0), db::Point (100, 200)));
|
||||
s2.insert (db::Box (db::Point (0, 0), db::Point (100, 200)));
|
||||
|
||||
m.transaction ("test");
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "");
|
||||
s1.insert (s2);
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nedge (0,0;100,200) #0\n");
|
||||
m.commit ();
|
||||
|
||||
m.undo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "");
|
||||
|
||||
m.redo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nedge (0,0;100,200) #0\n");
|
||||
|
||||
m.undo ();
|
||||
s1.insert (db::Box (db::Point (1, 1), db::Point (101, 201)));
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (1,1;101,201) #0\n");
|
||||
|
||||
m.clear ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (1,1;101,201) #0\n");
|
||||
|
||||
m.transaction ("test");
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (1,1;101,201) #0\n");
|
||||
s1.insert (s2);
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nbox (1,1;101,201) #0\nedge (0,0;100,200) #0\n");
|
||||
m.commit ();
|
||||
|
||||
m.undo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (1,1;101,201) #0\n");
|
||||
|
||||
m.redo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nbox (1,1;101,201) #0\nedge (0,0;100,200) #0\n");
|
||||
|
||||
m.clear ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nbox (1,1;101,201) #0\nedge (0,0;100,200) #0\n");
|
||||
|
||||
m.transaction ("test");
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nbox (1,1;101,201) #0\nedge (0,0;100,200) #0\n");
|
||||
s1.clear ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "");
|
||||
m.commit ();
|
||||
|
||||
m.undo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nbox (1,1;101,201) #0\nedge (0,0;100,200) #0\n");
|
||||
|
||||
m.redo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "");
|
||||
|
||||
m.clear ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "");
|
||||
}
|
||||
|
||||
// Shape insert and clear and undo/redo - no layout on target
|
||||
TEST(24c)
|
||||
{
|
||||
db::Manager m;
|
||||
db::Layout l;
|
||||
db::Cell &cell = l.cell (l.add_cell ("top"));
|
||||
l.insert_layer (1);
|
||||
l.insert_layer (2);
|
||||
db::Shapes s1 (&m, 0, true);
|
||||
db::Shapes &s2 = cell.shapes (2);
|
||||
|
||||
s2.insert (db::Edge (db::Point (0, 0), db::Point (100, 200)));
|
||||
s2.insert (db::Box (db::Point (0, 0), db::Point (100, 200)));
|
||||
|
||||
m.transaction ("test");
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "");
|
||||
s1.insert (s2);
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nedge (0,0;100,200) #0\n");
|
||||
m.commit ();
|
||||
|
||||
m.undo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "");
|
||||
|
||||
m.redo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nedge (0,0;100,200) #0\n");
|
||||
|
||||
m.undo ();
|
||||
s1.insert (db::Box (db::Point (1, 1), db::Point (101, 201)));
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (1,1;101,201) #0\n");
|
||||
|
||||
m.clear ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (1,1;101,201) #0\n");
|
||||
|
||||
m.transaction ("test");
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (1,1;101,201) #0\n");
|
||||
s1.insert (s2);
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nbox (1,1;101,201) #0\nedge (0,0;100,200) #0\n");
|
||||
m.commit ();
|
||||
|
||||
m.undo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (1,1;101,201) #0\n");
|
||||
|
||||
m.redo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nbox (1,1;101,201) #0\nedge (0,0;100,200) #0\n");
|
||||
|
||||
m.clear ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nbox (1,1;101,201) #0\nedge (0,0;100,200) #0\n");
|
||||
|
||||
m.transaction ("test");
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nbox (1,1;101,201) #0\nedge (0,0;100,200) #0\n");
|
||||
s1.clear ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "");
|
||||
m.commit ();
|
||||
|
||||
m.undo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nbox (1,1;101,201) #0\nedge (0,0;100,200) #0\n");
|
||||
|
||||
m.redo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "");
|
||||
|
||||
m.clear ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "");
|
||||
}
|
||||
|
||||
// Bug #107
|
||||
TEST(100)
|
||||
{
|
||||
|
|
@ -3262,6 +3449,72 @@ TEST(100)
|
|||
);
|
||||
}
|
||||
|
||||
// Shape insert and clear and undo/redo - different layouts
|
||||
TEST(24d)
|
||||
{
|
||||
db::Manager m;
|
||||
db::Layout l1 (true, &m);
|
||||
db::Cell &cell1 = l1.cell (l1.add_cell ("top"));
|
||||
l1.insert_layer (1);
|
||||
db::Layout l2 (true, &m);
|
||||
db::Cell &cell2 = l2.cell (l2.add_cell ("top"));
|
||||
l2.insert_layer (2);
|
||||
db::Shapes &s1 = cell1.shapes (1);
|
||||
db::Shapes &s2 = cell2.shapes (2);
|
||||
|
||||
s2.insert (db::Edge (db::Point (0, 0), db::Point (100, 200)));
|
||||
s2.insert (db::Box (db::Point (0, 0), db::Point (100, 200)));
|
||||
|
||||
m.transaction ("test");
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "");
|
||||
s1.insert (s2);
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nedge (0,0;100,200) #0\n");
|
||||
m.commit ();
|
||||
|
||||
m.undo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "");
|
||||
|
||||
m.redo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nedge (0,0;100,200) #0\n");
|
||||
|
||||
m.undo ();
|
||||
s1.insert (db::Box (db::Point (1, 1), db::Point (101, 201)));
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (1,1;101,201) #0\n");
|
||||
|
||||
m.clear ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (1,1;101,201) #0\n");
|
||||
|
||||
m.transaction ("test");
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (1,1;101,201) #0\n");
|
||||
s1.insert (s2);
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nbox (1,1;101,201) #0\nedge (0,0;100,200) #0\n");
|
||||
m.commit ();
|
||||
|
||||
m.undo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (1,1;101,201) #0\n");
|
||||
|
||||
m.redo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nbox (1,1;101,201) #0\nedge (0,0;100,200) #0\n");
|
||||
|
||||
m.clear ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nbox (1,1;101,201) #0\nedge (0,0;100,200) #0\n");
|
||||
|
||||
m.transaction ("test");
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nbox (1,1;101,201) #0\nedge (0,0;100,200) #0\n");
|
||||
s1.clear ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "");
|
||||
m.commit ();
|
||||
|
||||
m.undo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "box (0,0;100,200) #0\nbox (1,1;101,201) #0\nedge (0,0;100,200) #0\n");
|
||||
|
||||
m.redo ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "");
|
||||
|
||||
m.clear ();
|
||||
EXPECT_EQ (shapes_to_string_norm (_this, s1), "");
|
||||
}
|
||||
|
||||
// Bug #835
|
||||
TEST(101)
|
||||
{
|
||||
|
|
@ -3322,3 +3575,4 @@ TEST(101)
|
|||
const db::Path &qr2_obj = *b.shape_repository ().repository (db::Path::tag ()).begin ();
|
||||
EXPECT_EQ (& qr2.obj () == &qr2_obj, true);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue