Merge pull request #865 from KLayout/issue-864

Fixed #864 (Shapes#copy_shapes does not support undo/redo)
This commit is contained in:
Matthias Köfferlein 2021-07-17 13:44:15 +02:00 committed by GitHub
commit 054bfa3be4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 523 additions and 122 deletions

View File

@ -333,21 +333,13 @@ void
Cell::copy (unsigned int src, unsigned int dest)
{
if (src != dest) {
db::Shapes &dest_shapes = shapes (dest);
db::Cell::shape_iterator src_shape = begin (src, db::Shapes::shape_iterator::All);
while (! src_shape.at_end ()) {
dest_shapes.insert (*src_shape);
++src_shape;
}
shapes (dest).insert (shapes (src));
} else {
// When duplicating the layer, first create a copy to avoid problems with non-stable containers
// Hint: using the assignment and not the copy ctor does not copy the db::Manager association.
db::Shapes shape_copy;
shape_copy = shapes (src);
db::Shapes &dest_shapes = shapes (dest);
for (db::Cell::shape_iterator src_shape = shape_copy.begin (db::Shapes::shape_iterator::All); ! src_shape.at_end (); ++src_shape) {
dest_shapes.insert (*src_shape);
}
shapes (dest).insert (shape_copy);
}
}

View File

@ -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 ()));

View File

@ -131,6 +131,50 @@ 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;
} else if ((*l)->is_same_type (mp_layer)) {
delete (*l);
*l = mp_layer;
m_owns_layer = false;
shapes->invalidate_state ();
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 +199,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 +225,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 +997,22 @@ 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;
for (tl::vector<LayerBase *>::const_iterator l = m_layers.end (); l != m_layers.begin (); ) {
// because the undo stack will do a push, we need to remove layers from the back (this is the last undo
// element to be executed)
--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 +1172,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 +1192,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 +1260,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 +1285,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 +1306,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 +1315,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 ()));
}

View File

@ -486,8 +486,8 @@ 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 bool is_same_type (const LayerBase *other) 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 +682,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 +723,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 +764,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 +812,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 +856,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 +894,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 +915,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 +1011,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 +1075,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 +1102,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 +1493,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 +1625,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 +1640,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 +1766,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

View File

@ -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);
}
}

View File

@ -141,8 +141,12 @@ public:
m_layer.sort ();
}
virtual void clear (Shapes *target, db::Manager *manager);
virtual LayerBase *clone (Shapes *target, db::Manager *manager) const;
virtual bool is_same_type (const LayerBase *other) const
{
return dynamic_cast<const layer_class<Sh, StableTag> *> (other);
}
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;

View File

@ -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!

View File

@ -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)

View File

@ -557,9 +557,13 @@ TEST(5)
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 1 0 {0 0} {100 200}\nend_cell\nend_lib\n");
// switch to another LIBCELL, this time using layer 2/0
m.transaction ("switch_to_b");
l.set_technology_name ("B");
m.commit ();
if (l.is_editable ()) {
m.transaction ("switch_to_b");
l.set_technology_name ("B");
m.commit ();
} else {
l.set_technology_name ("B");
}
EXPECT_EQ (l.technology_name (), "B");
cell = &l.cell (l.cell_by_name ("LIBCELL").second);
@ -609,9 +613,13 @@ TEST(6)
info.pcell_parameters ["npoints"] = tl::Variant (8);
info.pcell_parameters ["layer"] = tl::Variant (db::LayerProperties (1, 0));
m.transaction ("import");
if (l.is_editable ()) {
m.transaction ("import");
}
cell = l.recover_proxy (info);
m.commit ();
if (l.is_editable ()) {
m.commit ();
}
EXPECT_EQ (cell->get_qualified_name (), "Basic.CIRCLE");
EXPECT_EQ (cell->get_basic_name (), "CIRCLE");
EXPECT_EQ (cell->get_display_name (), "Basic.CIRCLE(l=1/0,r=10,n=8)");
@ -622,10 +630,14 @@ TEST(6)
l.get_context_info (cell->cell_index (), info2);
info2.pcell_parameters ["actual_radius"] = tl::Variant (5.0);
m.transaction ("modify");
if (l.is_editable ()) {
m.transaction ("modify");
}
db::cell_index_type ci = cell->cell_index ();
l.recover_proxy_as (ci, info2);
m.commit ();
if (l.is_editable ()) {
m.commit ();
}
cell = &l.cell (ci);
EXPECT_EQ (cell->get_qualified_name (), "Basic.CIRCLE");
EXPECT_EQ (cell->get_basic_name (), "CIRCLE");

View File

@ -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);
}

View File

@ -901,103 +901,98 @@ class DBLayout_TestClass < TestBase
assert_equal(dump_layer(lll, 0, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (1200,0;2200,1100); (1200,0;2200,1100); (-1200,0;-100,1000); (-1200,0;-100,1000)")
assert_equal(dump_layer(lll, 1, "c0"), "(0,100;1000,1200); (100,0;1100,1100)")
# TODO: undo tests crashes in non-editable mode! Should be checked properly.
if lll.is_editable?
assert_equal(m.has_undo?, true)
assert_equal(m.has_redo?, false)
assert_equal(m.transaction_for_undo, "9")
assert_equal(m.has_undo?, true)
assert_equal(m.has_redo?, false)
assert_equal(m.transaction_for_undo, "9")
m.undo
assert_equal(m.has_undo?, true)
assert_equal(m.has_redo?, true)
assert_equal(m.transaction_for_undo, "8")
m.undo
assert_equal(m.has_undo?, true)
assert_equal(m.has_redo?, true)
assert_equal(m.transaction_for_undo, "8")
assert_equal(dump_layer(l, 0, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (1200,0;2200,1100); (1200,0;2200,1100); (-1200,0;-100,1000); (-1200,0;-100,1000)")
assert_equal(dump_layer(l, 1, "c0"), "(0,100;1000,1200); (100,0;1100,1100)")
assert_equal(dump_layer(l, 0, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (1200,0;2200,1100); (1200,0;2200,1100); (-1200,0;-100,1000); (-1200,0;-100,1000)")
assert_equal(dump_layer(l, 1, "c0"), "(0,100;1000,1200); (100,0;1100,1100)")
m.undo
assert_equal(m.has_undo?, true)
assert_equal(m.has_redo?, true)
assert_equal(m.transaction_for_undo, "7")
m.undo
assert_equal(m.has_undo?, true)
assert_equal(m.has_redo?, true)
assert_equal(m.transaction_for_undo, "7")
assert_equal(dump_layer(l, 0, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (1200,0;2200,1100); (-1200,0;-100,1000)")
assert_equal(dump_layer(l, 1, "c0"), "(0,100;1000,1200); (100,0;1100,1100)")
assert_equal(dump_layer(l, 0, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (1200,0;2200,1100); (-1200,0;-100,1000)")
assert_equal(dump_layer(l, 1, "c0"), "(0,100;1000,1200); (100,0;1100,1100)")
m.undo
assert_equal(m.has_undo?, true)
assert_equal(m.has_redo?, true)
assert_equal(m.transaction_for_undo, "6")
m.undo
assert_equal(m.has_undo?, true)
assert_equal(m.has_redo?, true)
assert_equal(m.transaction_for_undo, "6")
assert_equal(dump_layer(l, 0, "c0"), "(0,100;1000,1200); (1200,0;2200,1100); (-1200,0;-100,1000)")
assert_equal(dump_layer(l, 1, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (100,0;1100,1100)")
assert_equal(dump_layer(l, 0, "c0"), "(0,100;1000,1200); (1200,0;2200,1100); (-1200,0;-100,1000)")
assert_equal(dump_layer(l, 1, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (100,0;1100,1100)")
m.undo
assert_equal(m.has_undo?, true)
assert_equal(m.has_redo?, true)
assert_equal(m.transaction_for_undo, "5")
m.undo
assert_equal(m.has_undo?, true)
assert_equal(m.has_redo?, true)
assert_equal(m.transaction_for_undo, "5")
assert_equal(dump_layer(l, 0, "c0"), "(1200,0;2200,1100); (-1200,0;-100,1000)")
assert_equal(dump_layer(l, 1, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (100,0;1100,1100)")
assert_equal(dump_layer(l, 0, "c0"), "(1200,0;2200,1100); (-1200,0;-100,1000)")
assert_equal(dump_layer(l, 1, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (100,0;1100,1100)")
m.undo
assert_equal(m.has_undo?, true)
assert_equal(m.has_redo?, true)
assert_equal(m.transaction_for_undo, "4")
m.undo
assert_equal(m.has_undo?, true)
assert_equal(m.has_redo?, true)
assert_equal(m.transaction_for_undo, "4")
assert_equal(dump_layer(l, 0, "c0"), "")
assert_equal(dump_layer(l, 1, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (100,0;1100,1100); (1200,0;2200,1100); (-1200,0;-100,1000)")
assert_equal(dump_layer(l, 0, "c0"), "")
assert_equal(dump_layer(l, 1, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (100,0;1100,1100); (1200,0;2200,1100); (-1200,0;-100,1000)")
m.undo
assert_equal(m.has_undo?, true)
assert_equal(m.has_redo?, true)
assert_equal(m.transaction_for_undo, "3")
m.undo
assert_equal(m.has_undo?, true)
assert_equal(m.has_redo?, true)
assert_equal(m.transaction_for_undo, "3")
assert_equal(dump_layer(l, 1, "c0"), "")
assert_equal(dump_layer(l, 0, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (100,0;1100,1100); (1200,0;2200,1100); (-1200,0;-100,1000)")
assert_equal(dump_layer(l, 1, "c0"), "")
assert_equal(dump_layer(l, 0, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (100,0;1100,1100); (1200,0;2200,1100); (-1200,0;-100,1000)")
m.undo
assert_equal(m.has_undo?, true)
assert_equal(m.has_redo?, true)
assert_equal(m.transaction_for_undo, "2")
m.undo
assert_equal(m.has_undo?, true)
assert_equal(m.has_redo?, true)
assert_equal(m.transaction_for_undo, "2")
assert_equal(dump_layer(l, 1, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (100,0;1100,1100); (1200,0;2200,1100); (-1200,0;-100,1000)")
assert_equal(dump_layer(l, 0, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (100,0;1100,1100); (1200,0;2200,1100); (-1200,0;-100,1000)")
assert_equal(dump_layer(l, 1, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (100,0;1100,1100); (1200,0;2200,1100); (-1200,0;-100,1000)")
assert_equal(dump_layer(l, 0, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (100,0;1100,1100); (1200,0;2200,1100); (-1200,0;-100,1000)")
m.undo
assert_equal(m.has_undo?, true)
assert_equal(m.has_redo?, true)
assert_equal(m.transaction_for_undo, "1")
m.undo
assert_equal(m.has_undo?, true)
assert_equal(m.has_redo?, true)
assert_equal(m.transaction_for_undo, "1")
assert_equal(dump_layer(l, 0, "c0"), "")
assert_equal(dump_layer(l, 1, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (100,0;1100,1100); (1200,0;2200,1100); (-1200,0;-100,1000)")
assert_equal(dump_layer(l, 0, "c0"), "")
assert_equal(dump_layer(l, 1, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (100,0;1100,1100); (1200,0;2200,1100); (-1200,0;-100,1000)")
m.undo
assert_equal(m.has_undo?, false)
assert_equal(m.has_redo?, true)
assert_equal(m.transaction_for_redo, "1")
m.undo
assert_equal(m.has_undo?, false)
assert_equal(m.has_redo?, true)
assert_equal(m.transaction_for_redo, "1")
assert_equal(dump_layer(l, 0, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (100,0;1100,1100); (1200,0;2200,1100); (-1200,0;-100,1000)")
assert_equal(dump_layer(l, 1, "c0"), "")
assert_equal(dump_layer(l, 0, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (100,0;1100,1100); (1200,0;2200,1100); (-1200,0;-100,1000)")
assert_equal(dump_layer(l, 1, "c0"), "")
m.redo
assert_equal(m.has_undo?, true)
assert_equal(m.has_redo?, true)
assert_equal(m.transaction_for_redo, "2")
m.redo
assert_equal(m.has_undo?, true)
assert_equal(m.has_redo?, true)
assert_equal(m.transaction_for_redo, "2")
assert_equal(dump_layer(l, 0, "c0"), "")
assert_equal(dump_layer(l, 1, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (100,0;1100,1100); (1200,0;2200,1100); (-1200,0;-100,1000)")
assert_equal(dump_layer(l, 0, "c0"), "")
assert_equal(dump_layer(l, 1, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (100,0;1100,1100); (1200,0;2200,1100); (-1200,0;-100,1000)")
assert_equal(dump_layer(ll, 0, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (1200,0;2200,1100); (1200,0;2200,1100); (-1200,0;-100,1000); (-1200,0;-100,1000)")
assert_equal(dump_layer(ll, 1, "c0"), "(0,100;1000,1200); (100,0;1100,1100)")
assert_equal(dump_layer(ll, 0, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (1200,0;2200,1100); (1200,0;2200,1100); (-1200,0;-100,1000); (-1200,0;-100,1000)")
assert_equal(dump_layer(ll, 1, "c0"), "(0,100;1000,1200); (100,0;1100,1100)")
l.destroy
m.destroy
l.destroy
m.destroy
assert_equal(dump_layer(lll, 0, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (1200,0;2200,1100); (1200,0;2200,1100); (-1200,0;-100,1000); (-1200,0;-100,1000)")
assert_equal(dump_layer(lll, 1, "c0"), "(0,100;1000,1200); (100,0;1100,1100)")
end
assert_equal(dump_layer(lll, 0, "c0"), "(0,100;1000,1200); (0,100;1000,1200); (1200,0;2200,1100); (1200,0;2200,1100); (-1200,0;-100,1000); (-1200,0;-100,1000)")
assert_equal(dump_layer(lll, 1, "c0"), "(0,100;1000,1200); (100,0;1100,1100)")
end