diff --git a/x26commands.cpp b/x26commands.cpp index 59170be..023d3fb 100644 --- a/x26commands.cpp +++ b/x26commands.cpp @@ -72,8 +72,8 @@ void InsertTripletCommand::redo() if (m_firstDo) m_firstDo = false; - else - m_teletextDocument->emit tripletCommandHighlight(m_row+1); + + m_teletextDocument->emit tripletCommandHighlight(m_row); } void InsertTripletCommand::undo() diff --git a/x26dockwidget.cpp b/x26dockwidget.cpp index cdf7ac3..a1a9afe 100644 --- a/x26dockwidget.cpp +++ b/x26dockwidget.cpp @@ -133,73 +133,93 @@ X26DockWidget::X26DockWidget(TeletextWidget *parent): QDockWidget(parent) m_cookedModePushButton = new QPushButton; cookedTripletLayout->addWidget(m_cookedModePushButton); - auto newModeMenuAction=[&](QMenu *menu, int mode) - { - QAction *action = menu->addAction(m_x26Model->modeTripletName(mode)); - connect(action, &QAction::triggered, [=]() { cookedModeMenuSelected(mode); }); - }; - // Cooked triplet menu + // We build the menus for both "Insert" buttons at the same time m_cookedModeMenu = new QMenu(this); - newModeMenuAction(m_cookedModeMenu, 0x04); - QMenu *rowTripletSubMenu = m_cookedModeMenu->addMenu(tr("Row triplet")); - newModeMenuAction(rowTripletSubMenu, 0x00); - newModeMenuAction(rowTripletSubMenu, 0x01); - newModeMenuAction(rowTripletSubMenu, 0x07); - newModeMenuAction(rowTripletSubMenu, 0x18); - QMenu *columnTripletSubMenu = m_cookedModeMenu->addMenu(tr("Column triplet")); - newModeMenuAction(columnTripletSubMenu, 0x20); - newModeMenuAction(columnTripletSubMenu, 0x23); - newModeMenuAction(columnTripletSubMenu, 0x27); - newModeMenuAction(columnTripletSubMenu, 0x2c); - newModeMenuAction(columnTripletSubMenu, 0x2e); - newModeMenuAction(columnTripletSubMenu, 0x28); - columnTripletSubMenu->addSeparator(); - newModeMenuAction(columnTripletSubMenu, 0x29); - newModeMenuAction(columnTripletSubMenu, 0x2f); - newModeMenuAction(columnTripletSubMenu, 0x21); - newModeMenuAction(columnTripletSubMenu, 0x22); - newModeMenuAction(columnTripletSubMenu, 0x2b); - newModeMenuAction(columnTripletSubMenu, 0x2d); - QMenu *diacriticalSubMenu = columnTripletSubMenu->addMenu(tr("G0 diacritical")); - for (int i=0; i<16; i++) - newModeMenuAction(diacriticalSubMenu, 0x30 + i); - QMenu *objectSubMenu = m_cookedModeMenu->addMenu(tr("Object")); - newModeMenuAction(objectSubMenu, 0x10); - newModeMenuAction(objectSubMenu, 0x11); - newModeMenuAction(objectSubMenu, 0x12); - newModeMenuAction(objectSubMenu, 0x13); - newModeMenuAction(objectSubMenu, 0x15); - newModeMenuAction(objectSubMenu, 0x16); - newModeMenuAction(objectSubMenu, 0x17); - newModeMenuAction(m_cookedModeMenu, 0x1f); - m_cookedModeMenu->addSeparator(); - QMenu *pdcSubMenu = m_cookedModeMenu->addMenu(tr("PDC/reserved")); - newModeMenuAction(pdcSubMenu, 0x08); - newModeMenuAction(pdcSubMenu, 0x09); - newModeMenuAction(pdcSubMenu, 0x0a); - newModeMenuAction(pdcSubMenu, 0x0b); - newModeMenuAction(pdcSubMenu, 0x0c); - newModeMenuAction(pdcSubMenu, 0x0d); - newModeMenuAction(pdcSubMenu, 0x26); - QMenu *reservedRowSubMenu = pdcSubMenu->addMenu(tr("Reserved row")); - newModeMenuAction(reservedRowSubMenu, 0x02); - newModeMenuAction(reservedRowSubMenu, 0x03); - newModeMenuAction(reservedRowSubMenu, 0x05); - newModeMenuAction(reservedRowSubMenu, 0x06); - newModeMenuAction(reservedRowSubMenu, 0x0e); - newModeMenuAction(reservedRowSubMenu, 0x0f); - newModeMenuAction(reservedRowSubMenu, 0x14); - newModeMenuAction(reservedRowSubMenu, 0x19); - newModeMenuAction(reservedRowSubMenu, 0x1a); - newModeMenuAction(reservedRowSubMenu, 0x1b); - newModeMenuAction(reservedRowSubMenu, 0x1c); - newModeMenuAction(reservedRowSubMenu, 0x1d); - newModeMenuAction(reservedRowSubMenu, 0x1e); - QMenu *reservedColumnSubMenu = pdcSubMenu->addMenu(tr("Reserved column")); - newModeMenuAction(reservedColumnSubMenu, 0x24); - newModeMenuAction(reservedColumnSubMenu, 0x25); - newModeMenuAction(reservedColumnSubMenu, 0x26); + m_insertBeforeMenu = new QMenu(this); + m_insertAfterMenu = new QMenu(this); + + for (int m=0; m<3; m++) { + QMenu *menuToBuild; + + if (m == 0) + menuToBuild = m_cookedModeMenu; + else if (m == 1) + menuToBuild = m_insertBeforeMenu; + else // if (m == 2) + menuToBuild = m_insertAfterMenu; + + auto newModeMenuAction=[&](QMenu *menu, int mode) + { + QAction *action = menu->addAction(m_x26Model->modeTripletName(mode)); + if (m == 0) + connect(action, &QAction::triggered, [=]() { cookedModeMenuSelected(mode); }); + else if (m == 1) + connect(action, &QAction::triggered, [=]() { insertTriplet(mode, false); }); + else // if (m == 2) + connect(action, &QAction::triggered, [=]() { insertTriplet(mode, true); }); + }; + + newModeMenuAction(menuToBuild, 0x04); + QMenu *rowTripletSubMenu = menuToBuild->addMenu(tr("Row triplet")); + newModeMenuAction(rowTripletSubMenu, 0x00); + newModeMenuAction(rowTripletSubMenu, 0x01); + newModeMenuAction(rowTripletSubMenu, 0x07); + newModeMenuAction(rowTripletSubMenu, 0x18); + QMenu *columnTripletSubMenu = menuToBuild->addMenu(tr("Column triplet")); + newModeMenuAction(columnTripletSubMenu, 0x20); + newModeMenuAction(columnTripletSubMenu, 0x23); + newModeMenuAction(columnTripletSubMenu, 0x27); + newModeMenuAction(columnTripletSubMenu, 0x2c); + newModeMenuAction(columnTripletSubMenu, 0x2e); + newModeMenuAction(columnTripletSubMenu, 0x28); + columnTripletSubMenu->addSeparator(); + newModeMenuAction(columnTripletSubMenu, 0x29); + newModeMenuAction(columnTripletSubMenu, 0x2f); + newModeMenuAction(columnTripletSubMenu, 0x21); + newModeMenuAction(columnTripletSubMenu, 0x22); + newModeMenuAction(columnTripletSubMenu, 0x2b); + newModeMenuAction(columnTripletSubMenu, 0x2d); + QMenu *diacriticalSubMenu = columnTripletSubMenu->addMenu(tr("G0 diacritical")); + for (int i=0; i<16; i++) + newModeMenuAction(diacriticalSubMenu, 0x30 + i); + QMenu *objectSubMenu = menuToBuild->addMenu(tr("Object")); + newModeMenuAction(objectSubMenu, 0x10); + newModeMenuAction(objectSubMenu, 0x11); + newModeMenuAction(objectSubMenu, 0x12); + newModeMenuAction(objectSubMenu, 0x13); + newModeMenuAction(objectSubMenu, 0x15); + newModeMenuAction(objectSubMenu, 0x16); + newModeMenuAction(objectSubMenu, 0x17); + newModeMenuAction(menuToBuild, 0x1f); + menuToBuild->addSeparator(); + QMenu *pdcSubMenu = menuToBuild->addMenu(tr("PDC/reserved")); + newModeMenuAction(pdcSubMenu, 0x08); + newModeMenuAction(pdcSubMenu, 0x09); + newModeMenuAction(pdcSubMenu, 0x0a); + newModeMenuAction(pdcSubMenu, 0x0b); + newModeMenuAction(pdcSubMenu, 0x0c); + newModeMenuAction(pdcSubMenu, 0x0d); + newModeMenuAction(pdcSubMenu, 0x26); + QMenu *reservedRowSubMenu = pdcSubMenu->addMenu(tr("Reserved row")); + newModeMenuAction(reservedRowSubMenu, 0x02); + newModeMenuAction(reservedRowSubMenu, 0x03); + newModeMenuAction(reservedRowSubMenu, 0x05); + newModeMenuAction(reservedRowSubMenu, 0x06); + newModeMenuAction(reservedRowSubMenu, 0x0e); + newModeMenuAction(reservedRowSubMenu, 0x0f); + newModeMenuAction(reservedRowSubMenu, 0x14); + newModeMenuAction(reservedRowSubMenu, 0x19); + newModeMenuAction(reservedRowSubMenu, 0x1a); + newModeMenuAction(reservedRowSubMenu, 0x1b); + newModeMenuAction(reservedRowSubMenu, 0x1c); + newModeMenuAction(reservedRowSubMenu, 0x1d); + newModeMenuAction(reservedRowSubMenu, 0x1e); + QMenu *reservedColumnSubMenu = pdcSubMenu->addMenu(tr("Reserved column")); + newModeMenuAction(reservedColumnSubMenu, 0x24); + newModeMenuAction(reservedColumnSubMenu, 0x25); + newModeMenuAction(reservedColumnSubMenu, 0x26); + } m_cookedModePushButton->setMenu(m_cookedModeMenu); @@ -584,12 +604,21 @@ X26DockWidget::X26DockWidget(TeletextWidget *parent): QDockWidget(parent) // Insert and delete widgets QHBoxLayout *insertDeleteLayout = new QHBoxLayout; - m_insertPushButton = new QPushButton(tr("Insert triplet")); - insertDeleteLayout->addWidget(m_insertPushButton); - m_deletePushButton = new QPushButton(tr("Delete triplet")); + m_insertBeforePushButton = new QPushButton(tr("Insert above")); + insertDeleteLayout->addWidget(m_insertBeforePushButton); + m_insertBeforePushButton->setMenu(m_insertBeforeMenu); + + m_insertAfterPushButton = new QPushButton(tr("Insert below")); + insertDeleteLayout->addWidget(m_insertAfterPushButton); + m_insertAfterPushButton->setMenu(m_insertAfterMenu); + + m_insertCopyPushButton = new QPushButton(tr("Insert copy")); + insertDeleteLayout->addWidget(m_insertCopyPushButton); + + m_deletePushButton = new QPushButton(tr("Delete")); insertDeleteLayout->addWidget(m_deletePushButton); - connect(m_insertPushButton, &QPushButton::clicked, this, &X26DockWidget::insertTriplet); + connect(m_insertCopyPushButton, &QPushButton::clicked, this, &X26DockWidget::insertTripletCopy); connect(m_deletePushButton, &QPushButton::clicked, this, &X26DockWidget::deleteTriplet); x26Layout->addLayout(insertDeleteLayout); @@ -607,7 +636,7 @@ void X26DockWidget::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Insert: - insertTriplet(); + insertTripletCopy(); break; case Qt::Key_Delete: deleteTriplet(); @@ -965,14 +994,47 @@ void X26DockWidget::updateModelFromCookedWidget(const int value, const int role) updateAllRawTripletSpinBoxes(m_x26View->currentIndex()); } -void X26DockWidget::insertTriplet() +void X26DockWidget::insertTriplet(int modeExt, bool after) +{ + QModelIndex index = m_x26View->currentIndex(); + X26Triplet newTriplet(modeExt < 0x20 ? 41 : 0, modeExt & 0x1f, 0); + int row; + + if (index.isValid()) { + // If we're inserting a column triplet next to another column triplet, + // duplicate the column number + // Avoid the PDC and reserved mode triplets + if (modeExt >= 0x20 && modeExt != 0x24 && modeExt != 0x25 && modeExt != 0x26 && modeExt != 0x2a) { + const int existingTripletModeExt = index.model()->data(index.model()->index(index.row(), 2), Qt::EditRole).toInt(); + + if (existingTripletModeExt >= 0x20 && existingTripletModeExt != 0x24 && existingTripletModeExt != 0x25 && existingTripletModeExt != 0x26 && existingTripletModeExt != 0x2a) + newTriplet.setAddress(index.model()->data(index.model()->index(index.row(), 0), Qt::UserRole).toInt()); + } + row = index.row()+after; + } else + row = 0; + + // For character triplets, ensure Data is not reserved + if (modeExt == 0x21 || modeExt == 0x22 || modeExt == 0x29 || modeExt == 0x2b || modeExt >= 0x2f) + newTriplet.setData(0x20); + // For Termination Marker, set Address and Mode + if (modeExt == 0x1f) { + newTriplet.setAddress(63); + newTriplet.setData(7); + } + + m_x26Model->insertRows(row, 1, QModelIndex(), newTriplet); +} + +void X26DockWidget::insertTripletCopy() { QModelIndex index = m_x26View->currentIndex(); if (index.isValid()) m_x26Model->insertRow(index.row(), QModelIndex()); else - m_x26Model->insertFirstRow(); + // No existing triplet to copy, so insert a Termination Marker + m_x26Model->insertRows(0, 1, QModelIndex(), X26Triplet(63, 31, 7)); } void X26DockWidget::deleteTriplet() @@ -988,9 +1050,9 @@ void X26DockWidget::customMenuRequested(QPoint pos) QMenu *menu = new QMenu(this); - QAction *insertAct = new QAction("Insert triplet", this); + QAction *insertAct = new QAction("Insert triplet copy", this); menu->addAction(insertAct); - connect(insertAct, &QAction::triggered, this, &X26DockWidget::insertTriplet); + connect(insertAct, &QAction::triggered, this, &X26DockWidget::insertTripletCopy); if (index.isValid()) { QAction *deleteAct = new QAction("Delete triplet", this); menu->addAction(deleteAct); diff --git a/x26dockwidget.h b/x26dockwidget.h index d18cde2..7d27a4b 100644 --- a/x26dockwidget.h +++ b/x26dockwidget.h @@ -61,7 +61,8 @@ public: X26DockWidget(TeletextWidget *parent); public slots: - void insertTriplet(); + void insertTriplet(int, bool); + void insertTripletCopy(); void deleteTriplet(); void customMenuRequested(QPoint pos); void loadX26List(); @@ -87,7 +88,7 @@ private: QTableView *m_x26View; X26Model *m_x26Model; QSpinBox *m_cookedRowSpinBox, *m_cookedColumnSpinBox; - QMenu *m_cookedModeMenu; + QMenu *m_cookedModeMenu, *m_insertBeforeMenu, *m_insertAfterMenu; QPushButton *m_cookedModePushButton; QSpinBox *m_rawTripletAddressSpinBox, *m_rawTripletModeSpinBox, *m_rawTripletDataSpinBox; QStackedLayout *m_rawOrCookedStackedLayout; @@ -113,7 +114,7 @@ private: QSpinBox *m_reservedPDCSpinBox; QComboBox *m_terminationMarkerPageTypeComboBox; QCheckBox *m_terminationMarkerMoreFollowsCheckBox; - QPushButton *m_insertPushButton, *m_deletePushButton; + QPushButton *m_insertBeforePushButton, *m_insertAfterPushButton, *m_insertCopyPushButton, *m_deletePushButton; TeletextWidget *m_parentMainWidget; }; diff --git a/x26model.cpp b/x26model.cpp index 8c2cda8..52016a1 100644 --- a/x26model.cpp +++ b/x26model.cpp @@ -797,13 +797,6 @@ QVariant X26Model::headerData(int section, Qt::Orientation orientation, int role return QVariant(); } -bool X26Model::insertFirstRow() -{ - m_parentMainWidget->document()->undoStack()->push(new InsertTripletCommand(m_parentMainWidget->document(), this, 0, 1, X26Triplet(63, 31, 7))); - - return true; -} - bool X26Model::insertRows(int row, int count, const QModelIndex &parent) { Q_UNUSED(parent); @@ -815,6 +808,17 @@ bool X26Model::insertRows(int row, int count, const QModelIndex &parent) return true; } +bool X26Model::insertRows(int row, int count, const QModelIndex &parent, X26Triplet triplet) +{ + Q_UNUSED(parent); + + if (m_parentMainWidget->document()->currentSubPage()->enhancements()->size() + count > m_parentMainWidget->document()->currentSubPage()->maxEnhancements()) + return false; + + m_parentMainWidget->document()->undoStack()->push(new InsertTripletCommand(m_parentMainWidget->document(), this, row, count, triplet)); + return true; +} + bool X26Model::removeRows(int row, int count, const QModelIndex &index) { Q_UNUSED(index); diff --git a/x26model.h b/x26model.h index 1037213..1ad3d6f 100644 --- a/x26model.h +++ b/x26model.h @@ -36,8 +36,8 @@ public: QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; bool setData(const QModelIndex &index, const QVariant &value, int role); QVariant headerData(int section, Qt::Orientation orientation, int role) const; - bool insertFirstRow(); bool insertRows(int position, int rows, const QModelIndex &parent); + bool insertRows(int position, int rows, const QModelIndex &parent, X26Triplet triplet); bool removeRows(int position, int rows, const QModelIndex &index); // Qt::ItemFlags flags(const QModelIndex &index) const;