First draft for fix of issue #1776 (undo/redo by list)

This commit is contained in:
Matthias Koefferlein 2024-07-29 00:15:22 +02:00
parent d3921844d6
commit c6928d234c
10 changed files with 390 additions and 1 deletions

View File

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

View File

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

View File

@ -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",

View File

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

View File

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

View File

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

View File

@ -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 &current)
{
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

View File

@ -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 &current);
private:
Ui::UndoRedoListForm *mp_ui;
bool m_for_undo;
db::Manager *mp_manager;
int m_steps;
};
}
#endif

View File

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

View File

@ -60,6 +60,7 @@ FORMS = \
SaveLayoutAsOptionsDialog.ui \
SelectStippleForm.ui \
TipDialog.ui \
UndoRedoListForm.ui \
UserPropertiesForm.ui \
UserPropertiesEditForm.ui \
SpecificLoadLayoutOptionsDialog.ui \