mirror of https://github.com/KLayout/klayout.git
First draft for fix of issue #1776 (undo/redo by list)
This commit is contained in:
parent
d3921844d6
commit
c6928d234c
|
|
@ -283,7 +283,7 @@ Manager::redo ()
|
|||
}
|
||||
}
|
||||
|
||||
std::pair<bool, std::string>
|
||||
std::pair<bool, std::string>
|
||||
Manager::available_undo () const
|
||||
{
|
||||
if (m_opened || m_current == m_transactions.begin ()) {
|
||||
|
|
@ -305,6 +305,71 @@ Manager::available_redo () const
|
|||
}
|
||||
}
|
||||
|
||||
int
|
||||
Manager::available_undo_items ()
|
||||
{
|
||||
if (m_opened) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int n = 0;
|
||||
for (auto i = m_current; i != m_transactions.begin (); --i) {
|
||||
++n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
Manager::available_redo_items ()
|
||||
{
|
||||
if (m_opened) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int n = 0;
|
||||
for (auto i = m_current; i != m_transactions.end (); ++i) {
|
||||
++n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
std::string
|
||||
Manager::undo_or_redo_item (int delta) const
|
||||
{
|
||||
if (delta < 0) {
|
||||
|
||||
auto i = m_current;
|
||||
while (delta < 0) {
|
||||
if (i == m_transactions.begin ()) {
|
||||
return std::string ();
|
||||
}
|
||||
++delta;
|
||||
--i;
|
||||
}
|
||||
|
||||
return i->second;
|
||||
|
||||
} else {
|
||||
|
||||
auto i = m_current;
|
||||
while (delta > 0) {
|
||||
if (i == m_transactions.end ()) {
|
||||
return std::string ();
|
||||
}
|
||||
--delta;
|
||||
++i;
|
||||
}
|
||||
|
||||
if (i == m_transactions.end ()) {
|
||||
return std::string ();
|
||||
} else {
|
||||
return i->second;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
db::Op *
|
||||
Manager::last_queued (db::Object *object)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -202,6 +202,29 @@ public:
|
|||
*/
|
||||
std::pair<bool, std::string> available_redo () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the number of available undo items
|
||||
*/
|
||||
int available_undo_items ();
|
||||
|
||||
/**
|
||||
* @brief Gets the number of available redo items
|
||||
*/
|
||||
int available_redo_items ();
|
||||
|
||||
/**
|
||||
* @brief Gets an item from the list
|
||||
*
|
||||
* @param delta A positive value or 0 for the nth redo item, A negative value for the nth undo item
|
||||
*
|
||||
* A delta of "0" will give you the next redo item, a delta of "1" the second next one.
|
||||
* A delta of "-1" will give you the first undo item.
|
||||
* delta must be less than "available_redo_items" and larger or equal than "-available_undo_items".
|
||||
*
|
||||
* @return The description of the transaction
|
||||
*/
|
||||
std::string undo_or_redo_item (int delta) const;
|
||||
|
||||
/**
|
||||
* @brief Queue a operation for undo
|
||||
*
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ static const char *cm_symbols[] = {
|
|||
"cm_unselect_all",
|
||||
"cm_undo",
|
||||
"cm_redo",
|
||||
"cm_undo_list",
|
||||
"cm_redo_list",
|
||||
"cm_delete",
|
||||
"cm_show_properties",
|
||||
"cm_copy",
|
||||
|
|
|
|||
|
|
@ -1707,6 +1707,27 @@ MainWindow::cm_undo ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::cm_undo_list ()
|
||||
{
|
||||
if (current_view () && m_manager.available_undo ().first) {
|
||||
|
||||
std::unique_ptr<lay::UndoRedoListForm> dialog (new lay::UndoRedoListForm (this, &m_manager, true));
|
||||
|
||||
int steps = 0;
|
||||
if (dialog->exec (steps)) {
|
||||
for (std::vector <lay::LayoutViewWidget *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->view ()->clear_selection ();
|
||||
(*vp)->view ()->cancel ();
|
||||
}
|
||||
while (steps-- > 0) {
|
||||
m_manager.undo ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::cm_redo ()
|
||||
{
|
||||
|
|
@ -1719,6 +1740,27 @@ MainWindow::cm_redo ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::cm_redo_list ()
|
||||
{
|
||||
if (current_view () && m_manager.available_redo ().first) {
|
||||
|
||||
std::unique_ptr<lay::UndoRedoListForm> dialog (new lay::UndoRedoListForm (this, &m_manager, false));
|
||||
|
||||
int steps = 0;
|
||||
if (dialog->exec (steps)) {
|
||||
for (std::vector <lay::LayoutViewWidget *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->view ()->clear_selection ();
|
||||
(*vp)->view ()->cancel ();
|
||||
}
|
||||
while (steps-- > 0) {
|
||||
m_manager.redo ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::cm_goto_position ()
|
||||
{
|
||||
|
|
@ -1847,6 +1889,11 @@ MainWindow::update_action_states ()
|
|||
undo_action->set_title (undo_txt);
|
||||
undo_action->set_enabled (undo_enable && edits_enabled ());
|
||||
|
||||
if (menu ()->is_valid ("edit_menu.undo_list")) {
|
||||
Action *undo_list_action = menu ()->action ("edit_menu.undo_list");
|
||||
undo_list_action->set_enabled (undo_enable && edits_enabled ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (menu ()->is_valid ("edit_menu.redo")) {
|
||||
|
|
@ -1862,6 +1909,11 @@ MainWindow::update_action_states ()
|
|||
redo_action->set_title (redo_txt);
|
||||
redo_action->set_enabled (redo_enable && edits_enabled ());
|
||||
|
||||
if (menu ()->is_valid ("edit_menu.redo_list")) {
|
||||
Action *redo_list_action = menu ()->action ("edit_menu.redo_list");
|
||||
redo_list_action->set_enabled (redo_enable && edits_enabled ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (menu ()->is_valid ("edit_menu.paste")) {
|
||||
|
|
@ -3922,6 +3974,10 @@ MainWindow::menu_activated (const std::string &symbol)
|
|||
cm_undo ();
|
||||
} else if (symbol == "cm_redo") {
|
||||
cm_redo ();
|
||||
} else if (symbol == "cm_undo_list") {
|
||||
cm_undo_list ();
|
||||
} else if (symbol == "cm_redo_list") {
|
||||
cm_redo_list ();
|
||||
} else if (symbol == "cm_goto_position") {
|
||||
cm_goto_position ();
|
||||
} else if (symbol == "cm_manage_bookmarks") {
|
||||
|
|
|
|||
|
|
@ -800,6 +800,8 @@ private:
|
|||
void cm_reset_window_state ();
|
||||
void cm_undo ();
|
||||
void cm_redo ();
|
||||
void cm_undo_list ();
|
||||
void cm_redo_list ();
|
||||
void cm_goto_position ();
|
||||
void cm_manage_bookmarks ();
|
||||
void cm_bookmark_view ();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>UndoRedoListForm</class>
|
||||
<widget class="QDialog" name="UndoRedoListForm">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>307</width>
|
||||
<height>320</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Undo / Redo by List</string>
|
||||
</property>
|
||||
<layout class="QGridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="title_lbl">
|
||||
<property name="text">
|
||||
<string>(tbd)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QListView" name="items">
|
||||
<property name="uniformItemSizes">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<tabstops>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>UndoRedoListForm</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>211</x>
|
||||
<y>282</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>211</x>
|
||||
<y>152</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>UndoRedoListForm</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>211</x>
|
||||
<y>282</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>211</x>
|
||||
<y>152</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
|
@ -55,6 +55,7 @@
|
|||
#include "ui_FlattenInstOptionsDialog.h"
|
||||
#include "ui_UserPropertiesForm.h"
|
||||
#include "ui_UserPropertiesEditForm.h"
|
||||
#include "ui_UndoRedoListForm.h"
|
||||
|
||||
#include <QResource>
|
||||
#include <QBuffer>
|
||||
|
|
@ -1446,6 +1447,121 @@ BEGIN_PROTECTED
|
|||
END_PROTECTED
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// UndoRedoListForm implementation
|
||||
|
||||
namespace {
|
||||
|
||||
class UndoRedoListViewModel
|
||||
: public QAbstractListModel
|
||||
{
|
||||
public:
|
||||
UndoRedoListViewModel (QObject *parent, db::Manager *manager, bool for_undo)
|
||||
: QAbstractListModel (parent), mp_manager (manager), m_for_undo (for_undo)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
int columnCount (const QModelIndex &) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
QVariant data (const QModelIndex &index, int role) const
|
||||
{
|
||||
if (role == Qt::DisplayRole) {
|
||||
int delta;
|
||||
if (m_for_undo) {
|
||||
delta = -(index.row () + 1);
|
||||
} else {
|
||||
delta = index.row ();
|
||||
}
|
||||
return QVariant (tl::to_qstring (mp_manager->undo_or_redo_item (delta)));
|
||||
} else {
|
||||
return QVariant ();
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex index (int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid ()) {
|
||||
return QModelIndex ();
|
||||
} else {
|
||||
return createIndex (row, column);
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex parent(const QModelIndex &) const
|
||||
{
|
||||
return QModelIndex ();
|
||||
}
|
||||
|
||||
virtual int rowCount (const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid ()) {
|
||||
return 0;
|
||||
} else {
|
||||
return m_for_undo ? mp_manager->available_undo_items () : mp_manager->available_redo_items ();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
db::Manager *mp_manager;
|
||||
bool m_for_undo;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
UndoRedoListForm::UndoRedoListForm (QWidget *parent, db::Manager *manager, bool for_undo)
|
||||
: QDialog (parent), m_for_undo (for_undo), mp_manager (manager)
|
||||
{
|
||||
setObjectName (QString::fromUtf8 ("undo_redo_list_form"));
|
||||
|
||||
mp_ui = new Ui::UndoRedoListForm ();
|
||||
mp_ui->setupUi (this);
|
||||
|
||||
setWindowTitle (for_undo ? tr ("Undo By List") : tr ("Redo By List"));
|
||||
|
||||
mp_ui->items->setModel (new UndoRedoListViewModel (mp_ui->items, manager, for_undo));
|
||||
|
||||
connect (mp_ui->items->selectionModel (), SIGNAL (currentChanged(const QModelIndex &, const QModelIndex &)), this, SLOT (selection_changed(const QModelIndex &)));
|
||||
selection_changed (QModelIndex ());
|
||||
}
|
||||
|
||||
UndoRedoListForm::~UndoRedoListForm ()
|
||||
{
|
||||
delete mp_ui;
|
||||
mp_ui = 0;
|
||||
}
|
||||
|
||||
void
|
||||
UndoRedoListForm::selection_changed (const QModelIndex ¤t)
|
||||
{
|
||||
if (! current.isValid () || current.row () < 0) {
|
||||
mp_ui->title_lbl->setText (m_for_undo ? tr ("Undo to step (select one)") : tr ("Redo to step (select one)"));
|
||||
m_steps = -1;
|
||||
} else {
|
||||
m_steps = current.row () + 1;
|
||||
if (m_steps == 1) {
|
||||
mp_ui->title_lbl->setText (m_for_undo ? tr ("Undo one step") : tr ("Redo one step"));
|
||||
} else {
|
||||
mp_ui->title_lbl->setText ((m_for_undo ? tr ("Undo %1 steps") : tr ("Redo %1 steps")).arg (m_steps));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
UndoRedoListForm::exec (int &steps)
|
||||
{
|
||||
if (QDialog::exec ()) {
|
||||
steps = m_steps;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ namespace Ui
|
|||
class FlattenInstOptionsDialog;
|
||||
class UserPropertiesForm;
|
||||
class UserPropertiesEditForm;
|
||||
class UndoRedoListForm;
|
||||
}
|
||||
|
||||
namespace lay
|
||||
|
|
@ -460,6 +461,30 @@ public:
|
|||
Ui::UserPropertiesEditForm *mp_ui;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The undo/redo list form
|
||||
*/
|
||||
class LAYUI_PUBLIC UndoRedoListForm
|
||||
: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UndoRedoListForm (QWidget *parent, db::Manager *manager, bool for_undo);
|
||||
virtual ~UndoRedoListForm ();
|
||||
|
||||
bool exec (int &steps);
|
||||
|
||||
private slots:
|
||||
void selection_changed (const QModelIndex ¤t);
|
||||
|
||||
private:
|
||||
Ui::UndoRedoListForm *mp_ui;
|
||||
bool m_for_undo;
|
||||
db::Manager *mp_manager;
|
||||
int m_steps;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -2113,6 +2113,8 @@ public:
|
|||
at = "edit_menu.edit_options_group";
|
||||
menu_entries.push_back (lay::menu_item ("cm_undo", "undo:edit", at, tl::to_string (tr ("Undo(Ctrl+Z)"))));
|
||||
menu_entries.push_back (lay::menu_item ("cm_redo", "redo:edit", at, tl::to_string (tr ("Redo(Ctrl+Y)"))));
|
||||
menu_entries.push_back (lay::menu_item ("cm_undo_list", "undo_list:edit", at, tl::to_string (tr ("Undo by List"))));
|
||||
menu_entries.push_back (lay::menu_item ("cm_redo_list", "redo_list:edit", at, tl::to_string (tr ("Redo by List"))));
|
||||
|
||||
menu_entries.push_back (lay::separator ("basic_group", at));
|
||||
menu_entries.push_back (lay::submenu ("layout_menu:edit:edit_mode", at, tl::to_string (tr ("Layout"))));
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ FORMS = \
|
|||
SaveLayoutAsOptionsDialog.ui \
|
||||
SelectStippleForm.ui \
|
||||
TipDialog.ui \
|
||||
UndoRedoListForm.ui \
|
||||
UserPropertiesForm.ui \
|
||||
UserPropertiesEditForm.ui \
|
||||
SpecificLoadLayoutOptionsDialog.ui \
|
||||
|
|
|
|||
Loading…
Reference in New Issue