From d24f813f3f2a05c112e803e4256b53535895fc98 Mon Sep 17 00:00:00 2001 From: Jedidiah Barber Date: Wed, 14 Jul 2021 11:49:10 +1200 Subject: Initial mirror commit --- src/main-view/UndoCommands.cpp | 322 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 322 insertions(+) create mode 100644 src/main-view/UndoCommands.cpp (limited to 'src/main-view/UndoCommands.cpp') diff --git a/src/main-view/UndoCommands.cpp b/src/main-view/UndoCommands.cpp new file mode 100644 index 0000000..349b2a7 --- /dev/null +++ b/src/main-view/UndoCommands.cpp @@ -0,0 +1,322 @@ +#include "UndoCommands.h" +#include "DictTableModel.h" +#include "DictTableView.h" +#include "../dictionary/Dictionary.h" +#include "../dictionary/DicRecord.h" +#include "../main-view/MainWindow.h" +#include "../main-view/CardFilterModel.h" + +UndoRecordCmd::UndoRecordCmd( const MainWindow* aMainWin ): + m_mainWindow( aMainWin ) + { + } + +const DictTableView* UndoRecordCmd::getCurView() + { + if( !m_mainWindow ) + return NULL; + const DictTableView* dictView = m_mainWindow->getCurDictView(); // May be proxy view + return dictView; + } + +CardFilterModel* UndoRecordCmd::getProxyModel( const DictTableView* aCurDictView ) + { + CardFilterModel* proxyModel = qobject_cast( aCurDictView->model() ); + return proxyModel; + } + +void UndoRecordCmd::insertRows( QList aRowNumbers ) + { + const DictTableView* dictView = getCurView(); + CardFilterModel* proxyModel = getProxyModel( dictView ); + + // Insert rows by positions in the direct order + foreach( int row, aRowNumbers ) + { + if( proxyModel ) + proxyModel->addFilterRow( row ); + m_dictModel->insertRows( row, 1 ); + } + } + +void UndoRecordCmd::setRecords( QMap aRecords ) + { + Dictionary* dict = const_cast( m_dictModel->dictionary() ); + dict->disableRecordUpdates(); + + // Init rows by positions in the direct order + foreach( int row, aRecords.keys() ) + { + QModelIndex index = m_dictModel->index( row, 0 ); + DicRecord* record = aRecords.value( row ); + m_dictModel->setData( index, QVariant::fromValue( *record ), DictTableModel::DicRecordRole ); + } + dict->enableRecordUpdates(); + } + +void UndoRecordCmd::removeRows( QList aRowNumbers ) + { + const DictTableView* dictView = m_mainWindow->getCurDictView(); // May be proxy view + CardFilterModel* proxyModel = getProxyModel( dictView ); + Dictionary* dict = const_cast( m_dictModel->dictionary() ); + dict->disableRecordUpdates(); + + // Remove records by ranges from back + QListIterator i( aRowNumbers ); + i.toBack(); + while( i.hasPrevious() ) + { + int pos = i.previous(); + if( proxyModel ) + proxyModel->removeFilterRow( pos ); + m_dictModel->removeRows( pos, 1 ); + } + dict->enableRecordUpdates(); + } + + +/** Selects rows in the list. + * Sets the first row in the list as current. + */ +void UndoRecordCmd::selectRows( QList aRowNumbers ) + { + const DictTableView* dictView = m_mainWindow->getCurDictView(); // May be proxy view + CardFilterModel* proxyModel = getProxyModel( dictView ); + int topRow = aRowNumbers.first(); + if( topRow > m_dictModel->rowCount() - 1 ) // don't go beyond table boundaries + topRow = m_dictModel->rowCount() - 1; + QModelIndex topIndex = m_dictModel->index( topRow, 0, QModelIndex() ); + QItemSelectionModel* selectionModel = dictView->selectionModel(); + selectionModel->clear(); + foreach( int row, aRowNumbers ) + { + if( row > m_dictModel->rowCount() - 1 ) // don't go beyond table boundaries + row = m_dictModel->rowCount() - 1; + QModelIndex index = m_dictModel->index( row, 0, QModelIndex() ); + if( proxyModel ) + { + index = proxyModel->mapFromSource( index ); + if( !index.isValid() ) + continue; + } + selectionModel->setCurrentIndex( index, QItemSelectionModel::Select | QItemSelectionModel::Rows ); + } + if( proxyModel ) + topIndex = proxyModel->mapFromSource( topIndex ); + if( topIndex.isValid() ) + selectionModel->setCurrentIndex( topIndex, QItemSelectionModel::Current ); + } + +void UndoRecordCmd::selectRow( int aRow ) + { + QList list; + list << aRow; + selectRows( list ); + } + +//============================================================================================================== + +InsertRecordsCmd::InsertRecordsCmd( const MainWindow* aMainWin): + UndoRecordCmd( aMainWin ) + { + const DictTableView* dictView = getCurView(); + m_dictModel = dictView->dicTableModel(); // Always original model + + // If no selection, insert 1 row in the end + int pos = m_dictModel->rowCount(); + int rowsNum = 1; + QModelIndexList selectedRows = dictView->selectionModel()->selectedRows(); + if( !selectedRows.isEmpty() ) + // Insert number of rows equal to the selected rows + { + QAbstractProxyModel* proxyModel = qobject_cast( dictView->model() ); + if( proxyModel ) + { // convert selection to source indexes + QModelIndexList list; + foreach( QModelIndex index, selectedRows ) + list << proxyModel->mapToSource( index ); + selectedRows = list; + } + + qSort( selectedRows ); // to find the top row + pos = selectedRows.first().row(); + rowsNum = selectedRows.size(); + } + for( int r = pos; r < pos + rowsNum; r++ ) + m_rowNumbers << r; + + updateText(); + } + +void InsertRecordsCmd::updateText() + { + setText(QObject::tr("Insert %n record(s)", "Undo action of inserting records", m_rowNumbers.size() )); + } + +void InsertRecordsCmd::redo() + { + insertRows( m_rowNumbers ); + selectRows( m_rowNumbers ); + } + +void InsertRecordsCmd::undo() + { + removeRows( m_rowNumbers ); + selectRow( m_rowNumbers.first() ); + } + +bool InsertRecordsCmd::mergeWith( const QUndoCommand* command ) + { + const InsertRecordsCmd* otherInsertCmd = static_cast( command ); + if( !otherInsertCmd ) + return false; + if( otherInsertCmd->m_dictModel != m_dictModel ) + return false; + + // Find where to insert the other row numbers + int otherFirstRow = otherInsertCmd->m_rowNumbers.first(); + int otherRowsNum = otherInsertCmd->m_rowNumbers.size(); + int i = 0; + for( i = 0; i < m_rowNumbers.size(); i++ ) + if( otherFirstRow <= m_rowNumbers[i] ) + break; + int insertPos = i; + // Increment this row numbers by the number of other rows, after the insertion point + for( int i = insertPos; i < m_rowNumbers.size(); i++ ) + m_rowNumbers[i] += otherRowsNum; + // Do the insertion of other rows + for( int i = 0; i < otherRowsNum; i++ ) + m_rowNumbers.insert( insertPos + i, otherInsertCmd->m_rowNumbers[i] ); + + updateText(); + return true; + } + +//============================================================================================================== + +RemoveRecordsCmd::RemoveRecordsCmd( const MainWindow* aMainWin ): + UndoRecordCmd( aMainWin ) + { + const DictTableView* dictView = getCurView(); + m_dictModel = dictView->dicTableModel(); // Always original model + + int recordsNum = 0; + QModelIndexList selectedRows = dictView->selectionModel()->selectedRows(); + QAbstractProxyModel* proxyModel = qobject_cast( dictView->model() ); + if( proxyModel ) + { // convert selection to source indexes + QModelIndexList list; + foreach( QModelIndex index, selectedRows ) + list << proxyModel->mapToSource( index ); + selectedRows = list; + } + + foreach( QModelIndex index, selectedRows ) + { + int row = index.row(); + DicRecord record = index.data( DictTableModel::DicRecordRole ).value(); + Q_ASSERT( !index.data( DictTableModel::DicRecordRole ).isNull() ); + m_records.insert( row, new DicRecord( record ) ); + recordsNum++; + } + setText(QObject::tr( "Remove %n record(s)", "Undo action of removing records", recordsNum )); + } + +RemoveRecordsCmd::~RemoveRecordsCmd() + { + qDeleteAll( m_records ); + } + +void RemoveRecordsCmd::redo() + { + removeRows( m_records.keys() ); + selectRow( m_records.keys().first() ); + } + +void RemoveRecordsCmd::undo() + { + insertRows( m_records.keys() ); + setRecords( m_records ); + selectRows( m_records.keys() ); + } + +//============================================================================================================== + +EditRecordCmd::EditRecordCmd( QAbstractItemModel* aTableModel, const QModelIndex& aIndex, const QVariant& aValue ): + m_dictModel( aTableModel ), m_insertedRow( -1 ) + { + m_row = aIndex.row(); + m_col = aIndex.column(); + m_oldStr = aIndex.data( Qt::EditRole ).toString(); + m_newStr = aValue.toString(); + if( m_row == m_dictModel->rowCount() - 1 && m_col == m_dictModel->columnCount() - 1 ) + m_insertedRow = m_dictModel->rowCount(); + QString editStr = m_newStr; + if( editStr.length() > MaxMenuEditStrLen ) + editStr = editStr.left( MaxMenuEditStrLen ) + QChar( 8230 ); + setText( QObject::tr( "Edit \"%1\"", "Undo action of editing a record").arg( editStr ) ); + } + +void EditRecordCmd::redo() + { + QModelIndex index = m_dictModel->index( m_row, m_col ); + m_dictModel->setData( index, m_newStr, Qt::EditRole ); + if( m_insertedRow > -1 ) + m_dictModel->insertRows( m_insertedRow, 1 ); + } + +void EditRecordCmd::undo() + { + if( m_insertedRow > -1 ) + m_dictModel->removeRows( m_insertedRow, 1 ); + QModelIndex index = m_dictModel->index( m_row, m_col ); + m_dictModel->setData( index, m_oldStr, Qt::EditRole ); + } + +//============================================================================================================== + +PasteRecordsCmd::PasteRecordsCmd( QList aRecords, const MainWindow* aMainWin ): + UndoRecordCmd( aMainWin ) + { + const DictTableView* dictView = getCurView(); + m_dictModel = dictView->dicTableModel(); // Always original model + + // Find position where to insert records + // Paste above selection. If no selection -> paste in the end of dictionary + QModelIndexList selectedRows = dictView->selectionModel()->selectedRows(); + int pastePos = m_dictModel->rowCount(); + if( !selectedRows.isEmpty() ) + { + qSort( selectedRows ); + QModelIndex posIndex = selectedRows.first(); + + // If proxy view, convert position to source index + QAbstractProxyModel* proxyModel = qobject_cast( dictView->model() ); + if( proxyModel ) + posIndex = proxyModel->mapToSource( posIndex ); + + pastePos = posIndex.row(); + } + for( int i = 0; i < aRecords.size(); i++ ) + m_records.insert( pastePos + i, aRecords.value( i ) ); + + setText(QObject::tr("Paste %n record(s)", "Undo action of pasting records", m_records.size() )); + } + +PasteRecordsCmd::~PasteRecordsCmd() + { + qDeleteAll( m_records.values() ); + } + +void PasteRecordsCmd::redo() + { + insertRows( m_records.keys() ); + setRecords( m_records ); + selectRows( m_records.keys() ); + } + +void PasteRecordsCmd::undo() + { + removeRows( m_records.keys() ); + selectRow( m_records.keys().first() ); + } -- cgit