diff --git a/src/db/db/dbManager.cc b/src/db/db/dbManager.cc index 51dec8ab9..b7f842394 100644 --- a/src/db/db/dbManager.cc +++ b/src/db/db/dbManager.cc @@ -143,6 +143,22 @@ Manager::last_transaction_id () const return m_transactions.empty () ? 0 : reinterpret_cast (& m_transactions.back ()); } +void +Manager::cancel () +{ + if (db::transactions_enabled ()) { + + // commit and undo - revert changes done so far + commit (); + undo (); + + // delete all following transactions + erase_transactions (m_current, m_transactions.end ()); + m_current = m_transactions.end (); + + } +} + void Manager::commit () { diff --git a/src/db/db/dbManager.h b/src/db/db/dbManager.h index 014fb49c4..5dfa2fb02 100644 --- a/src/db/db/dbManager.h +++ b/src/db/db/dbManager.h @@ -140,6 +140,14 @@ public: */ void commit (); + /** + * @brief Cancels a transaction + * + * If called instead of commit, this method will undo all operations of the pending + * transaction. + */ + void cancel (); + /** * @brief Undo the current transaction * @@ -256,13 +264,20 @@ private: * * This object controls a transaction through it's lifetime. On construction, the * transaction is started, on destruction, the transaction is committed. + * + * "cancel" can be used to cancel the operation. This will undo all operations collected + * so far and delete the transaction. + * + * "close" temporarily disable the collection of operations. + * "open" will enable operation collection again and continue + * collection at the point when it was stopped with "close". */ class DB_PUBLIC Transaction { public: Transaction (db::Manager *manager, const std::string &desc) - : mp_manager (manager), m_transaction_id (0) + : mp_manager (manager), m_transaction_id (0), m_description (desc) { if (mp_manager) { m_transaction_id = mp_manager->transaction (desc); @@ -270,7 +285,7 @@ public: } Transaction (db::Manager *manager, const std::string &desc, db::Manager::transaction_id_t join_with) - : mp_manager (manager), m_transaction_id (0) + : mp_manager (manager), m_transaction_id (0), m_description (desc) { if (mp_manager) { m_transaction_id = mp_manager->transaction (desc, join_with); @@ -280,11 +295,36 @@ public: ~Transaction () { if (mp_manager) { - mp_manager->commit (); + if (mp_manager->transacting ()) { + mp_manager->commit (); + } mp_manager = 0; } } + void cancel () + { + if (mp_manager) { + open (); + mp_manager->cancel (); + mp_manager = 0; + } + } + + void close () + { + if (mp_manager->transacting ()) { + mp_manager->commit (); + } + } + + void open () + { + if (! mp_manager->transacting ()) { + mp_manager->transaction (m_description, m_transaction_id); + } + } + db::Manager::transaction_id_t id () const { return m_transaction_id; @@ -293,6 +333,7 @@ public: private: db::Manager *mp_manager; db::Manager::transaction_id_t m_transaction_id; + std::string m_description; // no copying. Transaction (const Transaction &); diff --git a/src/db/unit_tests/dbObject.cc b/src/db/unit_tests/dbObject.cc index 036bee571..aa7c434ed 100644 --- a/src/db/unit_tests/dbObject.cc +++ b/src/db/unit_tests/dbObject.cc @@ -151,6 +151,8 @@ struct B : public db::Object { if (transacting ()) { manager ()->queue (this, new BO (d)); + } else { + x += d; } } @@ -230,3 +232,84 @@ TEST(2) EXPECT_EQ (BO::inst_count (), 0); } +TEST(3) +{ + db::Manager *man = new db::Manager (); + { + EXPECT_EQ (man->available_undo ().first, false); + EXPECT_EQ (man->available_redo ().first, false); + + B b (man); + man->transaction ("add 1"); + b.add (1); + man->commit (); + + EXPECT_EQ (b.x, 1); + EXPECT_EQ (man->available_undo ().first, true); + EXPECT_EQ (man->available_undo ().second, "add 1"); + + man->transaction ("add 1,2"); + b.add (1); + b.add (2); + man->cancel (); + EXPECT_EQ (b.x, 1); + EXPECT_EQ (man->available_undo ().first, true); + EXPECT_EQ (man->available_redo ().first, false); + + man->undo (); + EXPECT_EQ (b.x, 0); + EXPECT_EQ (man->available_undo ().first, false); + EXPECT_EQ (man->available_redo ().first, true); + } + + delete man; + EXPECT_EQ (BO::inst_count (), 0); +} + +TEST(4) +{ + db::Manager *man = new db::Manager (); + { + EXPECT_EQ (man->available_undo ().first, false); + EXPECT_EQ (man->available_redo ().first, false); + + B b (man); + { + db::Transaction t (man, "add 1"); + b.add (1); + } + + EXPECT_EQ (b.x, 1); + EXPECT_EQ (man->available_undo ().first, true); + EXPECT_EQ (man->available_undo ().second, "add 1"); + + { + db::Transaction t (man, "add 1,2"); + b.add (1); + EXPECT_EQ (b.x, 2); + EXPECT_EQ (man->transacting (), true); + t.close (); + EXPECT_EQ (man->transacting (), false); + b.add (1); // after close -> not undone! + EXPECT_EQ (b.x, 3); + t.open (); + EXPECT_EQ (man->transacting (), true); + b.add (2); + EXPECT_EQ (b.x, 5); + t.cancel (); + } + + EXPECT_EQ (b.x, 2); + EXPECT_EQ (man->available_undo ().first, true); + EXPECT_EQ (man->available_redo ().first, false); + + man->undo (); + EXPECT_EQ (b.x, 1); + EXPECT_EQ (man->available_undo ().first, false); + EXPECT_EQ (man->available_redo ().first, true); + } + + delete man; + EXPECT_EQ (BO::inst_count (), 0); +} + diff --git a/src/lay/lay/layMainConfigPages.cc b/src/lay/lay/layMainConfigPages.cc index 5b95b0229..ceb7aabc0 100644 --- a/src/lay/lay/layMainConfigPages.cc +++ b/src/lay/lay/layMainConfigPages.cc @@ -434,9 +434,10 @@ CustomizeMenuConfigPage::apply (const std::vector top_level_menus; top_level_menus.insert (std::make_pair (std::string (), tl::to_string (QObject::tr ("Main Menu")))); + top_level_menus.insert (std::make_pair (std::string ("secrets"), tl::to_string (QObject::tr ("Key Binding Targets")))); top_level_menus.insert (std::make_pair (std::string ("lcp_context_menu"), tl::to_string (QObject::tr ("Layer Panel Context Menu")))); top_level_menus.insert (std::make_pair (std::string ("hcp_context_menu"), tl::to_string (QObject::tr ("Cell List Context Menu")))); - + // fill the bindings list mp_ui->bindings_list->clear (); diff --git a/src/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc index 6694793cb..99695696c 100644 --- a/src/lay/lay/layMainWindow.cc +++ b/src/lay/lay/layMainWindow.cc @@ -742,6 +742,13 @@ MainWindow::init_menu () { // default menu layout + MenuLayoutEntry secret_menu [] = { + MenuLayoutEntry ("paste_interactive:edit", tl::to_string (QObject::tr ("Paste Interactive")), SLOT (cm_paste_interactive ())), + MenuLayoutEntry ("duplicate_interactive:edit", tl::to_string (QObject::tr ("Duplicate Interactive")), SLOT (cm_duplicate_interactive ())), + MenuLayoutEntry ("sel_move_interactive", tl::to_string (QObject::tr ("Move Interactive")), SLOT (cm_sel_move_interactive ())), + MenuLayoutEntry::last () + }; + MenuLayoutEntry empty_menu [] = { MenuLayoutEntry::last () }; @@ -995,6 +1002,7 @@ MainWindow::init_menu () MenuLayoutEntry ("macros_menu", tl::to_string (QObject::tr ("&Macros")), macros_menu), MenuLayoutEntry::separator ("help_group"), MenuLayoutEntry ("help_menu", tl::to_string (QObject::tr ("&Help")), help_menu), + MenuLayoutEntry ("@secrets", tl::to_string (QObject::tr ("Secret Features")), secret_menu), MenuLayoutEntry ("@toolbar", "", toolbar_entries), MenuLayoutEntry::last () }; @@ -2233,7 +2241,7 @@ MainWindow::cm_cell_copy () } void -MainWindow::cm_duplicate () +MainWindow::do_cm_duplicate (bool interactive) { BEGIN_PROTECTED @@ -2248,7 +2256,11 @@ MainWindow::cm_duplicate () current_view ()->copy (); current_view ()->clear_selection (); current_view ()->cancel (); - current_view ()->paste (); + if (interactive) { + current_view ()->paste_interactive (); + } else { + current_view ()->paste (); + } db::Clipboard::instance ().swap (saved_clipboard); } catch (...) { db::Clipboard::instance ().swap (saved_clipboard); @@ -2260,6 +2272,26 @@ MainWindow::cm_duplicate () END_PROTECTED } +void +MainWindow::cm_duplicate () +{ + BEGIN_PROTECTED + + do_cm_duplicate (false); + + END_PROTECTED +} + +void +MainWindow::cm_duplicate_interactive () +{ + BEGIN_PROTECTED + + do_cm_duplicate (true); + + END_PROTECTED +} + void MainWindow::cm_copy () { @@ -2274,19 +2306,35 @@ MainWindow::cm_copy () } void -MainWindow::cm_paste () +MainWindow::do_cm_paste (bool interactive) { BEGIN_PROTECTED if (current_view () && ! db::Clipboard::instance ().empty ()) { current_view ()->cancel (); current_view ()->clear_selection (); - current_view ()->paste (); + if (interactive) { + current_view ()->paste_interactive (); + } else { + current_view ()->paste (); + } } END_PROTECTED } +void +MainWindow::cm_paste () +{ + do_cm_paste (false); +} + +void +MainWindow::cm_paste_interactive () +{ + do_cm_paste (true); +} + void MainWindow::cm_cut () { @@ -3568,6 +3616,12 @@ MainWindow::cm_sel_move_to () call_on_current_view (&lay::LayoutView::cm_sel_move_to, tl::to_string (QObject::tr ("move selection to position"))); } +void +MainWindow::cm_sel_move_interactive () +{ + call_on_current_view (&lay::LayoutView::cm_sel_move_interactive, tl::to_string (QObject::tr ("move selection interactively"))); +} + void MainWindow::cm_sel_scale () { @@ -3685,19 +3739,7 @@ MainWindow::clone_current_view () // create a new view view = new lay::LayoutView (current_view (), &m_manager, lay::ApplicationBase::instance ()->is_editable (), plugin_root (), mp_view_stack); - connect (view, SIGNAL (title_changed ()), this, SLOT (view_title_changed ())); - connect (view, SIGNAL (dirty_changed ()), this, SLOT (view_title_changed ())); - connect (view, SIGNAL (edits_enabled_changed ()), this, SLOT (edits_enabled_changed ())); - connect (view, SIGNAL (menu_needs_update ()), this, SLOT (menu_needs_update ())); - connect (view, SIGNAL (show_message (const std::string &, int)), this, SLOT (message (const std::string &, int))); - connect (view, SIGNAL (current_pos_changed (double, double, bool)), this, SLOT (current_pos (double, double, bool))); - connect (view, SIGNAL (clear_current_pos ()), this, SLOT (clear_current_pos ())); - mp_views.push_back (view); - - // we must resize the widget here to set the geometry properly. - // This is required to make zoom_fit work. - view->setGeometry (0, 0, mp_view_stack->width (), mp_view_stack->height ()); - view->show (); + add_view (view); // set initial attributes view->set_hier_levels (curr->get_hier_levels ()); @@ -4291,12 +4333,9 @@ MainWindow::create_layout (const std::string &technology, int mode) return create_or_load_layout (0, 0, technology, mode); } -int -MainWindow::do_create_view () +void +MainWindow::add_view (lay::LayoutView *view) { - // create a new view - lay::LayoutView *view = new lay::LayoutView (&m_manager, lay::ApplicationBase::instance ()->is_editable (), plugin_root (), mp_view_stack); - connect (view, SIGNAL (title_changed ()), this, SLOT (view_title_changed ())); connect (view, SIGNAL (dirty_changed ()), this, SLOT (view_title_changed ())); connect (view, SIGNAL (edits_enabled_changed ()), this, SLOT (edits_enabled_changed ())); @@ -4304,6 +4343,7 @@ MainWindow::do_create_view () connect (view, SIGNAL (show_message (const std::string &, int)), this, SLOT (message (const std::string &, int))); connect (view, SIGNAL (current_pos_changed (double, double, bool)), this, SLOT (current_pos (double, double, bool))); connect (view, SIGNAL (clear_current_pos ()), this, SLOT (clear_current_pos ())); + connect (view, SIGNAL (mode_change (int)), this, SLOT (select_mode (int))); mp_views.push_back (view); @@ -4311,6 +4351,14 @@ MainWindow::do_create_view () // This is required to make zoom_fit work. view->setGeometry (0, 0, mp_view_stack->width (), mp_view_stack->height ()); view->show (); +} + +int +MainWindow::do_create_view () +{ + // create a new view + lay::LayoutView *view = new lay::LayoutView (&m_manager, lay::ApplicationBase::instance ()->is_editable (), plugin_root (), mp_view_stack); + add_view (view); // set initial attributes view->set_synchronous (synchronous ()); diff --git a/src/lay/lay/layMainWindow.h b/src/lay/lay/layMainWindow.h index de4ef64ec..dc79128c4 100644 --- a/src/lay/lay/layMainWindow.h +++ b/src/lay/lay/layMainWindow.h @@ -504,13 +504,6 @@ public: */ void select_view (int index); - /** - * @brief Select the given mode - * - * @param The index of the mode to select - */ - void select_mode (int m); - /** * @brief Get the instance of the assistant */ @@ -645,17 +638,17 @@ signals: public slots: /** - * @brief Display the current position + * @brief Displays the current position */ void current_pos (double x, double y, bool dbu_units); /** - * @brief Clear the current position + * @brief Clears the current position */ void clear_current_pos (); /** - * @brief Display a status message next to the coordinates + * @brief Displays a status message next to the coordinates */ void message (const std::string &s, int ms); @@ -664,6 +657,13 @@ public slots: */ void clear_message (); + /** + * @brief Selects the given mode + * + * @param The index of the mode to select + */ + void select_mode (int m); + /** * @brief Called when one of the built-in modes (i.e. select, move) is selected */ @@ -691,7 +691,9 @@ public slots: void cm_show_properties (); void cm_copy (); void cm_paste (); + void cm_paste_interactive (); void cm_duplicate (); + void cm_duplicate_interactive (); void cm_cut (); void cm_zoom_fit_sel (); void cm_zoom_fit (); @@ -772,6 +774,7 @@ public slots: void cm_sel_scale (); void cm_sel_move (); void cm_sel_move_to (); + void cm_sel_move_interactive (); void cm_show_assistant (); // forwarded to the current view: layer list context menu @@ -946,6 +949,9 @@ private: void closeEvent (QCloseEvent *event); void resizeEvent (QResizeEvent *event); + void do_cm_paste (bool interactive); + void do_cm_duplicate (bool interactive); + void format_message (); int dirty_files (std::string &dirty_files); @@ -956,6 +962,7 @@ private: void current_view_changed (); void update_window_title (); void update_tab_title (int i); + void add_view (LayoutView *view); bool can_close (); lay::CellViewRef create_or_load_layout (const std::string *filename, const db::LoadLayoutOptions *options, const std::string &tech, const int mode); diff --git a/src/laybasic/laybasic/layEditable.cc b/src/laybasic/laybasic/layEditable.cc index d2dff0e4f..e85c67087 100644 --- a/src/laybasic/laybasic/layEditable.cc +++ b/src/laybasic/laybasic/layEditable.cc @@ -28,6 +28,7 @@ #include "layPropertiesDialog.h" #include +#include namespace lay { @@ -82,25 +83,30 @@ Editables::~Editables () } void -Editables::del () +Editables::del (db::Transaction *transaction) { + std::auto_ptr trans_holder (transaction ? transaction : new db::Transaction (manager (), tl::to_string (QObject::tr ("Delete")))); + if (selection_size () > 0) { - cancel_edits (); + try { - // begin the transaction - tl_assert (! manager ()->transacting ()); - manager ()->transaction (tl::to_string (QObject::tr ("Delete"))); - // this dummy operation will update the screen: - manager ()->queue (this, new db::Op ()); + trans_holder->open (); - for (iterator e = begin (); e != end (); ++e) { - e->del (); + cancel_edits (); + + // this dummy operation will update the screen: + manager ()->queue (this, new db::Op ()); + + for (iterator e = begin (); e != end (); ++e) { + e->del (); + } + + } catch (...) { + trans_holder->cancel (); + throw; } - // end the transaction - manager ()->commit (); - } } @@ -155,14 +161,16 @@ Editables::selection_catch_bbox () } void -Editables::transform (const db::DCplxTrans &tr) +Editables::transform (const db::DCplxTrans &tr, db::Transaction *transaction) { + std::auto_ptr trans_holder (transaction ? transaction : new db::Transaction (manager (), tl::to_string (QObject::tr ("Transform")))); + if (selection_size () > 0) { try { - tl_assert (! manager ()->transacting ()); - manager ()->transaction (tl::to_string (QObject::tr ("Transform"))); + trans_holder->open (); + // this dummy operation will update the screen: manager ()->queue (this, new db::Op ()); @@ -170,11 +178,8 @@ Editables::transform (const db::DCplxTrans &tr) e->transform (tr); } - // end the transaction - manager ()->commit (); - } catch (...) { - manager ()->clear (); + trans_holder->cancel (); throw; } @@ -525,13 +530,14 @@ Editables::move_transform (const db::DPoint &p, db::DFTrans t, lay::angle_constr } void -Editables::end_move (const db::DPoint &p, lay::angle_constraint_type ac) +Editables::end_move (const db::DPoint &p, lay::angle_constraint_type ac, db::Transaction *transaction) { + std::auto_ptr trans_holder (transaction ? transaction : new db::Transaction (manager (), tl::to_string (QObject::tr ("Move")))); + if (m_any_move_operation) { - // begin the transaction - tl_assert (! manager ()->transacting ()); - manager ()->transaction (tl::to_string (QObject::tr ("Move"))); + trans_holder->open (); + // this dummy operation will update the screen: manager ()->queue (this, new db::Op ()); @@ -539,9 +545,6 @@ Editables::end_move (const db::DPoint &p, lay::angle_constraint_type ac) e->end_move (p, ac); } - // end the transaction - manager ()->commit (); - // clear the selection that was set previously if (m_move_selection) { clear_selection (); @@ -549,6 +552,8 @@ Editables::end_move (const db::DPoint &p, lay::angle_constraint_type ac) } else { + trans_holder->cancel (); + // if nothing was moved, treat the end_move as a select which makes the move sticky or // replaces a complex selection by a simple one edit_cancel (); diff --git a/src/laybasic/laybasic/layEditable.h b/src/laybasic/laybasic/layEditable.h index 61f3e4995..6fd58531c 100644 --- a/src/laybasic/laybasic/layEditable.h +++ b/src/laybasic/laybasic/layEditable.h @@ -32,6 +32,7 @@ #include "dbPoint.h" #include "dbBox.h" #include "dbObject.h" +#include "dbManager.h" #include #include @@ -386,8 +387,11 @@ public: /** * @brief The delete operation + * + * If a transaction is given, the operation will be appended to this pending transaction + * The Editables object takes ownership over the Transaction object. */ - void del (); + void del (db::Transaction *transaction = 0); /** * @brief "cut" operation @@ -419,8 +423,11 @@ public: * @brief transform the selection * * The transformation is given in micron units. + * + * If a transaction is given, the operation will be appended to this pending transaction. + * The Editables object takes ownership over the Transaction object. */ - void transform (const db::DCplxTrans &tr); + void transform (const db::DCplxTrans &tr, db::Transaction *transaction = 0); /** * @brief Enable or disable a certain editable @@ -494,8 +501,11 @@ public: /** * @brief End "move" operation + * + * If a transaction is given, the operation will be appended to this pending transaction + * The Editables object takes ownership over the Transaction object. */ - void end_move (const db::DPoint &p, lay::angle_constraint_type ac); + void end_move (const db::DPoint &p, lay::angle_constraint_type ac, db::Transaction *transaction = 0); /** * @brief Tell how many objects are selected. diff --git a/src/laybasic/laybasic/layLayoutView.cc b/src/laybasic/laybasic/layLayoutView.cc index 531a604ca..31e7709a8 100644 --- a/src/laybasic/laybasic/layLayoutView.cc +++ b/src/laybasic/laybasic/layLayoutView.cc @@ -5085,6 +5085,33 @@ LayoutView::paste () } } +void +LayoutView::paste_interactive () +{ + clear_selection (); + + std::auto_ptr trans (new db::Transaction (manager (), tl::to_string (QObject::tr ("Paste and move")))); + + { + // let the receivers sort out who is pasting what .. + if (mp_hierarchy_panel) { + mp_hierarchy_panel->paste (); + } + if (mp_control_panel) { + mp_control_panel->paste (); + } + lay::Editables::paste (); + } + + // temporarily close the transaction and pass to the move service for appending it's own + // operations. + trans->close (); + + if (mp_move_service->begin_move (trans.release ())) { + switch_mode (-1); // move mode + } +} + void LayoutView::copy () { @@ -6763,6 +6790,23 @@ LayoutView::cm_sel_scale () } } +void +LayoutView::cm_sel_move_interactive () +{ + if (mp_move_service->begin_move ()) { + switch_mode (-1); // move mode + } +} + +void +LayoutView::switch_mode (int m) +{ + if (m_mode != m) { + mode (m); + emit mode_change (m); + } +} + void LayoutView::cm_sel_move_to () { diff --git a/src/laybasic/laybasic/layLayoutView.h b/src/laybasic/laybasic/layLayoutView.h index d562d74ca..6d9da0bde 100644 --- a/src/laybasic/laybasic/layLayoutView.h +++ b/src/laybasic/laybasic/layLayoutView.h @@ -254,6 +254,11 @@ public: */ void paste (); + /** + * @brief Pastes from clipboard and initiates a move + */ + void paste_interactive (); + /** * @brief Copies to clipboard * @@ -1617,6 +1622,14 @@ public: */ void mode (int m); + /** + * @brief Switches the application's mode + * + * Switches the mode on application level. Use this method to initiate + * a mode switch from the view. + */ + void switch_mode (int m); + /** * @brief Test, if the view is currently in move mode. */ @@ -2582,6 +2595,7 @@ public slots: void cm_sel_scale (); void cm_sel_move (); void cm_sel_move_to (); + void cm_sel_move_interactive (); // forwarded to the layer control panel void cm_new_tab (); @@ -2698,6 +2712,11 @@ signals: */ void menu_needs_update (); + /** + * @brief The view initiated a mode change + */ + void mode_change (int m); + protected: /** * @brief Establish the view operations diff --git a/src/laybasic/laybasic/layMove.cc b/src/laybasic/laybasic/layMove.cc index deb9d5e56..8e366293c 100644 --- a/src/laybasic/laybasic/layMove.cc +++ b/src/laybasic/laybasic/layMove.cc @@ -163,7 +163,7 @@ MoveService::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool return true; } if (prio && (buttons & lay::LeftButton) != 0) { - if (handle_dragging (p, buttons)) { + if (handle_dragging (p, buttons, 0)) { return true; } } @@ -216,7 +216,7 @@ bool MoveService::mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio) { if (prio && (buttons & lay::LeftButton) != 0) { - if (handle_dragging (p, buttons)) { + if (handle_dragging (p, buttons, 0)) { return true; } } @@ -229,12 +229,34 @@ MoveService::mouse_press_event (const db::DPoint &p, unsigned int buttons, bool return false; } +bool +MoveService::begin_move (db::Transaction *transaction) +{ + std::auto_ptr trans_holder (transaction); + + drag_cancel (); + + db::DBox bbox = mp_editables->selection_bbox (); + if (bbox.empty ()) { + // nothing selected + return false; + } + + set_cursor (lay::Cursor::size_all); + + // emulate a "begin move" at the center of the selection bbox - this will become the reference point + return handle_dragging (bbox.center (), 0, trans_holder.release ()); +} bool -MoveService::handle_dragging (const db::DPoint &p, unsigned int buttons) +MoveService::handle_dragging (const db::DPoint &p, unsigned int buttons, db::Transaction *transaction) { + std::auto_ptr trans_holder (transaction); + if (! m_dragging) { + mp_transaction.reset (trans_holder.release ()); + if (mp_editables->begin_move (p, ac_from_buttons (buttons))) { lay::SelectionService *selector = mp_view->selection_service (); @@ -257,7 +279,7 @@ MoveService::handle_dragging (const db::DPoint &p, unsigned int buttons) m_dragging = false; widget ()->ungrab_mouse (this); - mp_editables->end_move (p, ac_from_buttons (buttons)); + mp_editables->end_move (p, ac_from_buttons (buttons), mp_transaction.release ()); return true; } @@ -269,9 +291,17 @@ MoveService::drag_cancel () { m_shift = db::DPoint (); if (m_dragging) { + mp_editables->edit_cancel (); widget ()->ungrab_mouse (this); + m_dragging = false; + + if (mp_transaction.get ()) { + mp_transaction->cancel (); + } + mp_transaction.reset (0); + } } diff --git a/src/laybasic/laybasic/layMove.h b/src/laybasic/laybasic/layMove.h index 84ff6c7dd..b3bf39b2e 100644 --- a/src/laybasic/laybasic/layMove.h +++ b/src/laybasic/laybasic/layMove.h @@ -25,11 +25,14 @@ #ifndef HDR_layMove #define HDR_layMove +#include "dbManager.h" #include "layViewObject.h" #include #include +#include + namespace lay { class Editables; @@ -46,6 +49,7 @@ public: ~MoveService (); virtual bool configure (const std::string &name, const std::string &value); + bool begin_move (db::Transaction *transaction = 0); private: virtual bool mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio); @@ -58,13 +62,14 @@ private: virtual void drag_cancel (); virtual void deactivated (); - bool handle_dragging (const db::DPoint &p, unsigned int buttons); + bool handle_dragging (const db::DPoint &p, unsigned int buttons, db::Transaction *transaction); bool m_dragging; lay::Editables *mp_editables; lay::LayoutView *mp_view; double m_global_grid; db::DPoint m_shift; + std::auto_ptr mp_transaction; }; }