#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() ); }