Port X/26 list editing operations to UndoCommands

This commit is contained in:
G.K.MacGregor
2020-12-13 14:34:29 +00:00
parent f9ce912e79
commit 81b3534a09
9 changed files with 369 additions and 105 deletions

View File

@@ -26,8 +26,6 @@ Spacing attributes are only accessible through an "Insert" menu. A toolbar to in
There is no visible widget for switching between subpages, use the `PageUp` and `PageDown` keys for this. There is no visible widget for switching between subpages, use the `PageUp` and `PageDown` keys for this.
Undo only undoes keypresses, insertion of spacing attributes and CLUT changes. Other changes (most notably triplet editing) can't be undone, nor will they cause the "unsaved page" dialog to appear if the editor window is closed.
Keymapping between ASCII and Teletext character sets is not yet implemented e.g. in English pressing the hash key will type a pound sign instead, and in other languages the square and curly brackets keys need to be pressed to obtain the accented characters. Keymapping between ASCII and Teletext character sets is not yet implemented e.g. in English pressing the hash key will type a pound sign instead, and in other languages the square and curly brackets keys need to be pressed to obtain the accented characters.
The following X/26 enhancement triplets are not rendered by the editor, although the list is fully aware of them. The following X/26 enhancement triplets are not rendered by the editor, although the list is fully aware of them.

View File

@@ -86,6 +86,8 @@ signals:
void subPageSelected(); void subPageSelected();
void refreshNeeded(); void refreshNeeded();
void tripletCommandHighlight(int);
private: private:
QString m_description; QString m_description;
int m_pageNumber, m_currentSubPageIndex; int m_pageNumber, m_currentSubPageIndex;

View File

@@ -12,6 +12,7 @@ HEADERS = document.h \
pageoptionsdockwidget.h \ pageoptionsdockwidget.h \
palettedockwidget.h \ palettedockwidget.h \
render.h \ render.h \
x26commands.h \
x26dockwidget.h \ x26dockwidget.h \
x26model.h \ x26model.h \
x26triplets.h x26triplets.h
@@ -27,6 +28,7 @@ SOURCES = document.cpp \
pageoptionsdockwidget.cpp \ pageoptionsdockwidget.cpp \
palettedockwidget.cpp \ palettedockwidget.cpp \
render.cpp \ render.cpp \
x26commands.cpp \
x26dockwidget.cpp \ x26dockwidget.cpp \
x26model.cpp \ x26model.cpp \
x26triplets.cpp x26triplets.cpp

196
x26commands.cpp Normal file
View File

@@ -0,0 +1,196 @@
/*
* Copyright (C) 2020 Gavin MacGregor
*
* This file is part of QTeletextMaker.
*
* QTeletextMaker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* QTeletextMaker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with QTeletextMaker. If not, see <https://www.gnu.org/licenses/>.
*/
#include "x26commands.h"
#include <QUndoCommand>
#include "document.h"
#include "x26model.h"
#include "x26triplets.h"
InsertTripletCommand::InsertTripletCommand(TeletextDocument *teletextDocument, X26Model *x26Model, int row, int count, X26Triplet newTriplet, QUndoCommand *parent) : QUndoCommand(parent)
{
m_teletextDocument = teletextDocument;
m_subPageIndex = teletextDocument->currentSubPageIndex();
m_x26Model = x26Model;
m_row = row;
m_count = count;
m_insertedTriplet = newTriplet;
setText(QString("insert triplet d%1 t%2").arg(m_row / 13).arg(m_row % 13));;
m_firstDo = true;
}
void InsertTripletCommand::redo()
{
bool changingSubPage = (m_teletextDocument->currentSubPageIndex() != m_subPageIndex);
if (changingSubPage) {
m_teletextDocument->emit aboutToChangeSubPage();
m_teletextDocument->selectSubPageIndex(m_subPageIndex);
} else
m_x26Model->beginInsertRows(QModelIndex(), m_row, m_row+m_count-1);
for (int i=0; i<m_count; i++)
m_teletextDocument->currentSubPage()->localEnhance.insert(m_row+i, m_insertedTriplet);
if (changingSubPage)
m_teletextDocument->emit subPageSelected();
else {
m_x26Model->endInsertRows();
m_teletextDocument->emit refreshNeeded();
}
if (m_firstDo)
m_firstDo = false;
else
m_teletextDocument->emit tripletCommandHighlight(m_row+1);
}
void InsertTripletCommand::undo()
{
bool changingSubPage = (m_teletextDocument->currentSubPageIndex() != m_subPageIndex);
if (changingSubPage) {
m_teletextDocument->emit aboutToChangeSubPage();
m_teletextDocument->selectSubPageIndex(m_subPageIndex);
} else
m_x26Model->beginRemoveRows(QModelIndex(), m_row, m_row+m_count-1);
for (int i=0; i<m_count; i++)
m_teletextDocument->currentSubPage()->localEnhance.removeAt(m_row);
if (changingSubPage)
m_teletextDocument->emit subPageSelected();
else {
m_x26Model->endRemoveRows();
m_teletextDocument->emit refreshNeeded();
}
}
DeleteTripletCommand::DeleteTripletCommand(TeletextDocument *teletextDocument, X26Model *x26Model, int row, int count, QUndoCommand *parent) : QUndoCommand(parent)
{
m_teletextDocument = teletextDocument;
m_subPageIndex = teletextDocument->currentSubPageIndex();
m_x26Model = x26Model;
m_row = row;
m_count = count;
m_deletedTriplet = m_teletextDocument->subPage(m_subPageIndex)->localEnhance.at(m_row);
setText(QString("delete triplet d%1 t%2").arg(m_row / 13).arg(m_row % 13));;
// BUG we only store one of the deleted triplets
if (m_count > 1)
qDebug("More than one triplet row deleted, undo won't put the lost triplets back!");
}
void DeleteTripletCommand::redo()
{
m_teletextDocument->emit aboutToChangeSubPage();
m_teletextDocument->selectSubPageIndex(m_subPageIndex);
m_x26Model->beginRemoveRows(QModelIndex(), m_row, m_row+m_count-1);
for (int i=0; i<m_count; i++)
m_teletextDocument->currentSubPage()->localEnhance.removeAt(m_row);
m_x26Model->endRemoveRows();
m_teletextDocument->emit subPageSelected();
}
void DeleteTripletCommand::undo()
{
bool changingSubPage = (m_teletextDocument->currentSubPageIndex() != m_subPageIndex);
if (changingSubPage) {
m_teletextDocument->emit aboutToChangeSubPage();
m_teletextDocument->selectSubPageIndex(m_subPageIndex);
} else
m_x26Model->beginInsertRows(QModelIndex(), m_row, m_row+m_count-1);
for (int i=0; i<m_count; i++)
m_teletextDocument->currentSubPage()->localEnhance.insert(m_row+i, m_deletedTriplet);
if (changingSubPage)
m_teletextDocument->emit subPageSelected();
else {
m_x26Model->endInsertRows();
m_teletextDocument->emit refreshNeeded();
}
m_teletextDocument->emit tripletCommandHighlight(m_row);
}
EditTripletCommand::EditTripletCommand(TeletextDocument *teletextDocument, X26Model *x26Model, int row, int tripletPart, int bitsToKeep, int newValue, int role, QUndoCommand *parent) : QUndoCommand(parent)
{
m_teletextDocument = teletextDocument;
m_subPageIndex = teletextDocument->currentSubPageIndex();
m_x26Model = x26Model;
m_row = row;
m_role = role;
m_oldTriplet = m_newTriplet = teletextDocument->currentSubPage()->localEnhance.at(m_row);
setText(QString("edit triplet d%1 t%2").arg(m_row / 13).arg(m_row % 13));;
switch (tripletPart) {
case ETaddress:
m_newTriplet.setAddress((m_newTriplet.address() & bitsToKeep) | newValue);
break;
case ETmode:
m_newTriplet.setMode((m_newTriplet.mode() & bitsToKeep) | newValue);
break;
case ETdata:
m_newTriplet.setData((m_newTriplet.data() & bitsToKeep) | newValue);
break;
};
m_firstDo = true;
}
void EditTripletCommand::redo()
{
if (m_teletextDocument->currentSubPageIndex() != m_subPageIndex)
m_teletextDocument->selectSubPageIndex(m_subPageIndex, true);
m_teletextDocument->currentSubPage()->localEnhance[m_row] = m_newTriplet;
m_x26Model->emit dataChanged(m_x26Model->createIndex(m_row, 0), m_x26Model->createIndex(m_row, 3), {m_role});
m_teletextDocument->emit refreshNeeded();
if (m_firstDo)
m_firstDo = false;
else
m_teletextDocument->emit tripletCommandHighlight(m_row);
}
void EditTripletCommand::undo()
{
if (m_teletextDocument->currentSubPageIndex() != m_subPageIndex)
m_teletextDocument->selectSubPageIndex(m_subPageIndex, true);
m_teletextDocument->currentSubPage()->localEnhance[m_row] = m_oldTriplet;
m_x26Model->emit dataChanged(m_x26Model->createIndex(m_row, 0), m_x26Model->createIndex(m_row, 3), {m_role});
m_teletextDocument->emit refreshNeeded();
m_teletextDocument->emit tripletCommandHighlight(m_row);
}
bool EditTripletCommand::mergeWith(const QUndoCommand *command)
{
const EditTripletCommand *previousCommand = static_cast<const EditTripletCommand *>(command);
if (m_row != previousCommand->m_row)
return false;
m_newTriplet = previousCommand->m_newTriplet;
return true;
}

81
x26commands.h Normal file
View File

@@ -0,0 +1,81 @@
/*
* Copyright (C) 2020 Gavin MacGregor
*
* This file is part of QTeletextMaker.
*
* QTeletextMaker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* QTeletextMaker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with QTeletextMaker. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef X26COMMANDS_H
#define X26COMMANDS_H
#include <QUndoCommand>
#include "document.h"
#include "x26model.h"
#include "x26triplets.h"
class InsertTripletCommand : public QUndoCommand
{
public:
InsertTripletCommand(TeletextDocument *, X26Model *, int, int, const X26Triplet, QUndoCommand *parent = 0);
void redo() override;
void undo() override;
private:
TeletextDocument *m_teletextDocument;
X26Model *m_x26Model;
int m_subPageIndex, m_row, m_count;
X26Triplet m_insertedTriplet;
bool m_firstDo;
};
class DeleteTripletCommand : public QUndoCommand
{
public:
DeleteTripletCommand(TeletextDocument *, X26Model *, int, int, QUndoCommand *parent = 0);
void redo() override;
void undo() override;
private:
TeletextDocument *m_teletextDocument;
X26Model *m_x26Model;
int m_subPageIndex, m_row, m_count;
X26Triplet m_deletedTriplet;
};
class EditTripletCommand : public QUndoCommand
{
public:
enum { Id = 1 };
enum EditTripletEnum { ETaddress, ETmode, ETdata };
EditTripletCommand(TeletextDocument *, X26Model *, int, int, int, int, int, QUndoCommand *parent = 0);
void redo() override;
void undo() override;
bool mergeWith(const QUndoCommand *) override;
int id() const override { return Id; }
private:
TeletextDocument *m_teletextDocument;
X26Model *m_x26Model;
int m_subPageIndex, m_row, m_role;
X26Triplet m_oldTriplet, m_newTriplet;
bool m_firstDo;
};
#endif

View File

@@ -51,12 +51,15 @@ X26DockWidget::X26DockWidget(TeletextWidget *parent): QDockWidget(parent)
m_x26View->setModel(m_x26Model); m_x26View->setModel(m_x26Model);
m_x26View->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); m_x26View->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
m_x26View->setSelectionBehavior(QAbstractItemView::SelectRows); m_x26View->setSelectionBehavior(QAbstractItemView::SelectRows);
m_x26View->setSelectionMode(QAbstractItemView::SingleSelection);
m_x26View->setColumnWidth(0, 50); m_x26View->setColumnWidth(0, 50);
m_x26View->setColumnWidth(1, 50); m_x26View->setColumnWidth(1, 50);
m_x26View->setColumnWidth(2, 200); m_x26View->setColumnWidth(2, 200);
m_x26View->setColumnWidth(3, 200); m_x26View->setColumnWidth(3, 200);
x26Layout->addWidget(m_x26View); x26Layout->addWidget(m_x26View);
connect(m_parentMainWidget->document(), &TeletextDocument::tripletCommandHighlight, this, &X26DockWidget::selectX26ListRow);
// Triplet type and mode selection, with row and column spinboxes // Triplet type and mode selection, with row and column spinboxes
QHBoxLayout *tripletSelectLayout = new QHBoxLayout; QHBoxLayout *tripletSelectLayout = new QHBoxLayout;
@@ -469,6 +472,17 @@ X26DockWidget::X26DockWidget(TeletextWidget *parent): QDockWidget(parent)
connect(deleteShortcut, &QShortcut::activated, this, &X26DockWidget::deleteTriplet); connect(deleteShortcut, &QShortcut::activated, this, &X26DockWidget::deleteTriplet);
} }
void X26DockWidget::selectX26ListRow(int row)
{
if (m_x26Model->rowCount() <= 0)
return;
if (row >= m_x26Model->rowCount())
row = m_x26Model->rowCount() - 1;
m_x26View->selectRow(row);
rowClicked(m_x26View->currentIndex());
}
void X26DockWidget::loadX26List() void X26DockWidget::loadX26List()
{ {
m_x26Model->setX26ListLoaded(true); m_x26Model->setX26ListLoaded(true);

View File

@@ -59,6 +59,7 @@ public slots:
void cookedColumnSpinBoxChanged(const int); void cookedColumnSpinBoxChanged(const int);
void cookedModeComboBoxChanged(const int); void cookedModeComboBoxChanged(const int);
void updateModelFromCookedWidget(const int, const int); void updateModelFromCookedWidget(const int, const int);
void selectX26ListRow(int);
private: private:
QTableView *m_x26View; QTableView *m_x26View;

View File

@@ -17,9 +17,11 @@
* along with QTeletextMaker. If not, see <https://www.gnu.org/licenses/>. * along with QTeletextMaker. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "x26model.h"
#include <QList> #include <QList>
#include "x26model.h" #include "x26commands.h"
X26Model::X26Model(TeletextWidget *parent): QAbstractListModel(parent) X26Model::X26Model(TeletextWidget *parent): QAbstractListModel(parent)
{ {
@@ -461,69 +463,56 @@ bool X26Model::setData(const QModelIndex &index, const QVariant &value, int role
// Raw address, mode and data values // Raw address, mode and data values
if (role == Qt::UserRole && value.canConvert<int>() && index.column() <= 2) { if (role == Qt::UserRole && value.canConvert<int>() && index.column() <= 2) {
int intValue = value.toInt(); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), index.column(), 0x00, value.toInt(), role));
switch (index.column()) {
case 0:
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setAddress(intValue);
break;
case 1:
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setMode(intValue);
break;
case 2:
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData(intValue);
break;
}
emit dataChanged(createIndex(index.row(), 0), createIndex(index.row(), 3), {role});
m_parentMainWidget->refreshPage();
return true; return true;
} }
int mode = m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).modeExt(); int mode = m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).modeExt();
// Row, column and triplet mode // Cooked row, column and triplet mode
if (role == Qt::EditRole && value.canConvert<int>()) { if (role == Qt::EditRole && value.canConvert<int>()) {
int intValue = value.toInt(); int intValue = value.toInt();
if (intValue < 0) if (intValue < 0)
return false; return false;
switch (index.column()) { switch (index.column()) {
case 0: case 0: // Cooked row
// Maximum row is 24
if (intValue > 24) if (intValue > 24)
return false; return false;
// Set Active Position and Full Row Colour can't select row 0
if (((mode == 0x04) || (mode == 0x01)) && intValue == 0) if (((mode == 0x04) || (mode == 0x01)) && intValue == 0)
return false; return false;
if (mode == 0x10) // For Origin Modifier address of 40 refers to same row
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setAddress(intValue + 40); if (mode == 0x10 && intValue == 24) {
else m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x00, 40, role));
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setAddressRow(intValue); return true;
emit dataChanged(index, index, {role}); }
m_parentMainWidget->refreshPage(); // Others use address 40 for row 24
m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x00, (intValue == 24) ? 40 : intValue+40, role));
return true; return true;
case 1: case 1: // Cooked column
// Origin modifier allows columns up to 71 // Origin modifier allows columns up to 71
if (intValue > (mode == 0x10 ? 71 : 39)) if (intValue > (mode == 0x10 ? 71 : 39))
return false; return false;
// For Set Active Position and Origin Modifier, data is the column // For Set Active Position and Origin Modifier, data is the column
if (mode == 0x04 || mode == 0x10) if (mode == 0x04 || mode == 0x10)
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData(intValue); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x00, intValue, role));
else else
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setAddressColumn(intValue); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x00, intValue, role));
emit dataChanged(index, index, {role});
m_parentMainWidget->refreshPage();
return true; return true;
case 2: case 2: // Cooked triplet mode
if (intValue < 0x20 && !m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).isRowTriplet()) { if (intValue < 0x20 && !m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).isRowTriplet()) {
// Changing mode from column triplet to row triplet // Changing mode from column triplet to row triplet
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setAddressRow(1); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x00, 41, role));
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData(0); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x00, 0, role));
} }
if (intValue >= 0x20 && m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).isRowTriplet()) { if (intValue >= 0x20 && m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).isRowTriplet()) {
// Changing mode from row triplet to column triplet // Changing mode from row triplet to column triplet
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setAddressColumn(0); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x00, 0, role));
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData(0); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x00, 0, role));
} }
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setMode(intValue & 0x1f); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETmode, 0x00, intValue & 0x1f, role));
emit dataChanged(createIndex(index.row(), 0), createIndex(index.row(), 3), {role});
m_parentMainWidget->refreshPage();
return true; return true;
} }
return false; return false;
@@ -546,45 +535,42 @@ bool X26Model::setData(const QModelIndex &index, const QVariant &value, int role
case 0x20: // Foreground colour case 0x20: // Foreground colour
case 0x23: // Background colour case 0x23: // Background colour
// Colour index // Colour index
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x60) | intValue); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x60, value.toInt(), role));
break; break;
// case 0x04: // Set Active Position - data is the column
// m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData(intValue);
// break;
case 0x11 ... 0x13: // Invoke object case 0x11 ... 0x13: // Invoke object
// Object source: Local, POP or GPOP // Object source: Local, POP or GPOP
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setAddress((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).address() & 0x27) | ((intValue+1) << 3)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x27, (value.toInt()+1) << 3, role));
break; break;
case 0x15 ... 0x17: // Define object case 0x15 ... 0x17: // Define object
// Required at level 2.5 // Required at level 2.5
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setAddress((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).address() & 0x37) | (intValue << 2)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x37, value.toInt() << 2, role));
break; break;
case 0x18: // DRCS Mode case 0x18: // DRCS Mode
// Required at level 2.5 // Required at level 2.5
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x6f) | (intValue << 3)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x6f, value.toInt() << 3, role));
break; break;
case 0x1f: // Termination case 0x1f: // Termination
// Intermed POP subpage|Last POP subpage|Local Object|Local enhance // Intermed POP subpage|Last POP subpage|Local Object|Local enhance
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x01) | (intValue << 1)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x01, value.toInt() << 1, role));
break; break;
case 0x27: // Flash functions case 0x27: // Flash functions
// Flash mode // Flash mode
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x1c) | intValue); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x1c, value.toInt(), role));
break; break;
case 0x2c: // Display attributes case 0x2c: // Display attributes
// Text size // Text size
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x36) | ((intValue & 0x02) << 5) | (intValue & 0x01)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x36, ((value.toInt() & 0x02) << 5) | (value.toInt() & 0x01), role));
break; break;
case 0x2d: // DRCS character case 0x2d: // DRCS character
// Normal or Global // Normal or Global
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x3f) | (intValue << 6)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x3f, value.toInt() << 6, role));
break; break;
case 0x2e: // Font style case 0x2e: // Font style
// Proportional // Proportional
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x7e) | intValue); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x7e, value.toInt(), role));
break; break;
default: default:
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData(intValue); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x00, value.toInt(), role));
} }
break; break;
@@ -594,45 +580,45 @@ bool X26Model::setData(const QModelIndex &index, const QVariant &value, int role
case 0x01: // Full row colour case 0x01: // Full row colour
case 0x07: // Address row 0 case 0x07: // Address row 0
// "this row only" or "down to bottom" // "this row only" or "down to bottom"
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x1f) | (intValue * 0x60)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x1f, value.toInt() * 0x60, role));
break; break;
case 0x11 ... 0x13: // Invoke object case 0x11 ... 0x13: // Invoke object
if ((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).address() & 0x08) == 0x08) { if ((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).address() & 0x08) == 0x08) {
// Local object: Designation code // Local object: Designation code
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x0f) | ((intValue & 0x07) << 4)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x07, value.toInt() << 4, role));
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setAddress((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).address() & 0x3e) | (intValue >> 3)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x3e, value.toInt() >> 3, role));
} else } else
// (G)POP object: Subpage // (G)POP object: Subpage
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x30) | intValue); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x30, value.toInt(), role));
break; break;
case 0x15 ... 0x17: // Define object case 0x15 ... 0x17: // Define object
// Local object: Designation code // Local object: Designation code
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x0f) | ((intValue & 0x07) << 4)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x0f, (value.toInt() & 0x07) << 4, role));
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setAddress((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).address() & 0x3e) | (intValue >> 3)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x3e, value.toInt() >> 3, role));
break; break;
case 0x18: // DRCS Mode case 0x18: // DRCS Mode
// Required at level 3.5 // Required at level 3.5
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x5f) | (intValue << 4)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x5f, value.toInt() << 4, role));
break; break;
case 0x1f: // Termination case 0x1f: // Termination
// More follows/Last // More follows/Last
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x06) | intValue); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x06, value.toInt(), role));
break; break;
case 0x27: // Flash functions case 0x27: // Flash functions
// Flash rate and phase // Flash rate and phase
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x03) | (intValue << 2)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x03, value.toInt() << 2, role));
break; break;
case 0x2c: // Display attributes case 0x2c: // Display attributes
// Boxing/window // Boxing/window
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x7d) | (intValue << 1)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x7d, value.toInt() << 1, role));
break; break;
case 0x2d: // DRCS character case 0x2d: // DRCS character
// Character number // Character number
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x40) | intValue); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x40, value.toInt(), role));
break; break;
case 0x2e: // Font style case 0x2e: // Font style
// Bold // Bold
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x7d) | (intValue << 1)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x7d, value.toInt() << 1, role));
break; break;
} }
break; break;
@@ -642,26 +628,26 @@ bool X26Model::setData(const QModelIndex &index, const QVariant &value, int role
case 0x11 ... 0x13: // Invoke object case 0x11 ... 0x13: // Invoke object
if ((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).address() & 0x08) == 0x08) if ((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).address() & 0x08) == 0x08)
// Local object: triplet number // Local object: triplet number
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x70) | intValue); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x70, value.toInt(), role));
else else
// (G)POP object: Pointer location // (G)POP object: Pointer location
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setAddress((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).address() & 0x7c) | (intValue - 1)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x7c, value.toInt() - 1, role));
break; break;
case 0x15 ... 0x17: // Define object case 0x15 ... 0x17: // Define object
// Local object: triplet number // Local object: triplet number
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x70) | intValue); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x70, value.toInt(), role));
break; break;
case 0x18: // DRCS Mode case 0x18: // DRCS Mode
// Normal or Global // Normal or Global
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x3f) | (intValue << 6)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x3f, value.toInt() << 6, role));
break; break;
case 0x2c: // Display attributes case 0x2c: // Display attributes
// Conceal // Conceal
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x7b) | (intValue << 2)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x7b, value.toInt() << 2, role));
break; break;
case 0x2e: // Font style case 0x2e: // Font style
// Italics // Italics
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x7b) | (intValue << 2)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x7b, value.toInt() << 2, role));
break; break;
} }
break; break;
@@ -670,23 +656,23 @@ bool X26Model::setData(const QModelIndex &index, const QVariant &value, int role
switch (mode) { switch (mode) {
case 0x11 ... 0x13: // Invoke object case 0x11 ... 0x13: // Invoke object
// (G)POP object: Triplet number // (G)POP object: Triplet number
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x1f) | (intValue << 5)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x1f, value.toInt() << 5, role));
break; break;
case 0x15 ... 0x17: // Define object case 0x15 ... 0x17: // Define object
// Required at level 3.5 // Required at level 3.5
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setAddress((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).address() & 0x2f) | (intValue << 3)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETaddress, 0x2f, value.toInt() << 3, role));
break; break;
case 0x18: // DRCS Mode case 0x18: // DRCS Mode
// Subpage // Subpage
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x70) | intValue); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x70, value.toInt(), role));
break; break;
case 0x2c: // Display attributes case 0x2c: // Display attributes
// Invert // Invert
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x6f) | (intValue << 4)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x6f, value.toInt() << 4, role));
break; break;
case 0x2e: // Font style case 0x2e: // Font style
// Number of rows // Number of rows
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x07) | (intValue << 4)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x07, value.toInt() << 4, role));
break; break;
} }
break; break;
@@ -695,18 +681,16 @@ bool X26Model::setData(const QModelIndex &index, const QVariant &value, int role
switch (mode) { switch (mode) {
case 0x11 ... 0x13: // Invoke object case 0x11 ... 0x13: // Invoke object
// (G)POP object: Pointer position // (G)POP object: Pointer position
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x6f) | (intValue << 4)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x6f, value.toInt() << 4, role));
break; break;
case 0x2c: // Display attributes case 0x2c: // Display attributes
// Invert // Underline/Separated
m_parentMainWidget->document()->currentSubPage()->localEnhance[index.row()].setData((m_parentMainWidget->document()->currentSubPage()->localEnhance.at(index.row()).data() & 0x5f) | (intValue << 5)); m_parentMainWidget->document()->undoStack()->push(new EditTripletCommand(m_parentMainWidget->document(), this, index.row(), EditTripletCommand::ETdata, 0x5f, value.toInt() << 5, role));
break; break;
} }
break; break;
} }
emit dataChanged(createIndex(index.row(), 0), createIndex(index.row(), 3), {role});
m_parentMainWidget->refreshPage();
return true; return true;
} }
@@ -734,47 +718,27 @@ QVariant X26Model::headerData(int section, Qt::Orientation orientation, int role
bool X26Model::insertFirstRow() bool X26Model::insertFirstRow()
{ {
X26Triplet firstTriplet; m_parentMainWidget->document()->undoStack()->push(new InsertTripletCommand(m_parentMainWidget->document(), this, 0, 1, X26Triplet(63, 31, 7)));
firstTriplet.setAddress(63);
firstTriplet.setMode(31);
firstTriplet.setData(7);
beginInsertRows(QModelIndex(), 0, 0);
m_parentMainWidget->document()->currentSubPage()->localEnhance.insert(0, firstTriplet);
endInsertRows();
// Since we always insert a Termination Marker there's no need to refresh the page
return true; return true;
} }
bool X26Model::insertRows(int position, int rows, const QModelIndex &parent) bool X26Model::insertRows(int row, int count, const QModelIndex &parent)
{ {
Q_UNUSED(parent); Q_UNUSED(parent);
X26Triplet copyTriplet = m_parentMainWidget->document()->currentSubPage()->localEnhance.at(position);
beginInsertRows(QModelIndex(), position, position+rows-1); m_parentMainWidget->document()->undoStack()->push(new InsertTripletCommand(m_parentMainWidget->document(), this, row, count, m_parentMainWidget->document()->currentSubPage()->localEnhance.at(row)));
for (int row=0; row<rows; ++row)
m_parentMainWidget->document()->currentSubPage()->localEnhance.insert(position+row, copyTriplet);
endInsertRows();
// Since we always insert duplicates of the selected triplet there's no need to refresh the page
return true; return true;
} }
bool X26Model::removeRows(int position, int rows, const QModelIndex &index) bool X26Model::removeRows(int row, int count, const QModelIndex &index)
{ {
Q_UNUSED(index); Q_UNUSED(index);
beginRemoveRows(QModelIndex(), position, position+rows-1);
for (int row=0; row<rows; ++row) m_parentMainWidget->document()->undoStack()->push(new DeleteTripletCommand(m_parentMainWidget->document(), this, row, count));
m_parentMainWidget->document()->currentSubPage()->localEnhance.removeAt(position+row);
endRemoveRows();
m_parentMainWidget->refreshPage();
return true; return true;
} }
/* /*
Qt::ItemFlags X26Model::flags(const QModelIndex &index) const Qt::ItemFlags X26Model::flags(const QModelIndex &index) const
{ {

View File

@@ -40,6 +40,12 @@ public:
bool removeRows(int position, int rows, const QModelIndex &index); bool removeRows(int position, int rows, const QModelIndex &index);
// Qt::ItemFlags flags(const QModelIndex &index) const; // Qt::ItemFlags flags(const QModelIndex &index) const;
// The x26commands classes manipulate the model but beginInsertRows and endInsertRows
// are protected methods, so we need to friend them
friend class InsertTripletCommand;
friend class DeleteTripletCommand;
friend class EditTripletCommand;
private: private:
TeletextWidget *m_parentMainWidget; TeletextWidget *m_parentMainWidget;
bool m_listLoaded; bool m_listLoaded;