Implement cut, copy and paste

This commit is contained in:
G.K.MacGregor
2021-05-03 22:17:51 +01:00
parent 551172aed3
commit 9fa86f8c4c
6 changed files with 286 additions and 11 deletions

View File

@@ -76,6 +76,8 @@ public:
int selectionWidth() const { return m_selectionCornerColumn == -1 ? 1 : selectionRightColumn() - selectionLeftColumn() + 1; }
int selectionHeight() const { return m_selectionCornerRow == -1 ? 1 : selectionBottomRow() - selectionTopRow() + 1; }
bool selectionActive() const { return m_selectionSubPage == currentSubPage(); }
int selectionCornerRow() const { return m_selectionCornerRow == -1 ? m_cursorRow : m_selectionCornerRow; }
int selectionCornerColumn() const { return m_selectionCornerColumn == -1 ? m_cursorColumn : m_selectionCornerColumn; }
void setSelectionCorner(int, int);
void setSelection(int, int, int, int);
void cancelSelection();

View File

@@ -17,6 +17,12 @@
* along with QTeletextMaker. If not, see <https://www.gnu.org/licenses/>.
*/
#include <QApplication>
#include <QByteArray>
#include <QByteArrayList>
#include <QClipboard>
#include <QMimeData>
#include "levelonecommands.h"
#include "document.h"
@@ -340,6 +346,192 @@ void DeleteRowCommand::undo()
}
#ifndef QT_NO_CLIPBOARD
CutCommand::CutCommand(TeletextDocument *teletextDocument, QUndoCommand *parent) : LevelOneCommand(teletextDocument, parent)
{
m_selectionTopRow = m_teletextDocument->selectionTopRow();
m_selectionBottomRow = m_teletextDocument->selectionBottomRow();
m_selectionLeftColumn = m_teletextDocument->selectionLeftColumn();
m_selectionRightColumn = m_teletextDocument->selectionRightColumn();
m_selectionCornerRow = m_teletextDocument->selectionCornerRow();
m_selectionCornerColumn = m_teletextDocument->selectionCornerColumn();
// Store copy of the characters that we're about to blank
for (int r=m_selectionTopRow; r<=m_selectionBottomRow; r++) {
QByteArray rowArray;
for (int c=m_selectionLeftColumn; c<=m_selectionRightColumn; c++)
rowArray.append(m_teletextDocument->currentSubPage()->character(r, c));
m_deletedCharacters.append(rowArray);
}
setText(QObject::tr("cut"));
}
void CutCommand::redo()
{
m_teletextDocument->selectSubPageIndex(m_subPageIndex);
for (int r=m_selectionTopRow; r<=m_selectionBottomRow; r++) {
for (int c=m_selectionLeftColumn; c<=m_selectionRightColumn; c++)
m_teletextDocument->currentSubPage()->setCharacter(r, c, 0x20);
emit m_teletextDocument->contentsChange(r);
}
}
void CutCommand::undo()
{
m_teletextDocument->selectSubPageIndex(m_subPageIndex);
int arrayR = 0;
int arrayC;
for (int r=m_selectionTopRow; r<=m_selectionBottomRow; r++) {
arrayC = 0;
for (int c=m_selectionLeftColumn; c<=m_selectionRightColumn; c++)
m_teletextDocument->currentSubPage()->setCharacter(r, c, m_deletedCharacters[arrayR].at(arrayC++));
emit m_teletextDocument->contentsChange(r);
arrayR++;
}
m_teletextDocument->setSelectionCorner(m_selectionCornerRow, m_selectionCornerColumn);
m_teletextDocument->moveCursor(m_row, m_column, true);
}
PasteCommand::PasteCommand(TeletextDocument *teletextDocument, QUndoCommand *parent) : LevelOneCommand(teletextDocument, parent)
{
const QClipboard *clipboard = QApplication::clipboard();
const QMimeData *mimeData = clipboard->mimeData();
QByteArray nativeData;
m_selectionActive = m_teletextDocument->selectionActive();
if (m_selectionActive) {
m_selectionCornerRow = m_teletextDocument->selectionCornerRow();
m_selectionCornerColumn = m_teletextDocument->selectionCornerColumn();
}
m_clipboardDataHeight = m_clipboardDataWidth = 0;
// Try to get something from the clipboard
nativeData = mimeData->data("application/x-teletext");
if (nativeData.size() > 2) {
// Native clipboard data: we put it there ourselves
m_clipboardDataHeight = nativeData.at(0);
m_clipboardDataWidth = nativeData.at(1);
// Guard against invalid dimensions or total size not matching stated dimensions
if (m_clipboardDataHeight > 0 && m_clipboardDataWidth > 0 && m_clipboardDataHeight <= 25 && m_clipboardDataWidth <= 40 && nativeData.size() == m_clipboardDataHeight * m_clipboardDataWidth + 2)
for (int r=0; r<m_clipboardDataHeight; r++)
m_pastingCharacters.append(nativeData.mid(2 + r * m_clipboardDataWidth, m_clipboardDataWidth));
else
// Invalidate
m_clipboardDataHeight = m_clipboardDataWidth = 0;
}
if (m_clipboardDataWidth == 0)
return;
if (m_selectionActive) {
m_pasteTopRow = m_teletextDocument->selectionTopRow();
m_pasteBottomRow = m_teletextDocument->selectionBottomRow();
m_pasteLeftColumn = m_teletextDocument->selectionLeftColumn();
m_pasteRightColumn = m_teletextDocument->selectionRightColumn();
} else {
m_pasteTopRow = m_row;
m_pasteBottomRow = m_row + m_clipboardDataHeight - 1;
m_pasteLeftColumn = m_column;
m_pasteRightColumn = m_column + m_clipboardDataWidth - 1;
}
// Store copy of the characters that we're about to overwrite
for (int r=m_pasteTopRow; r<=m_pasteBottomRow; r++) {
QByteArray rowArray;
for (int c=m_pasteLeftColumn; c<=m_pasteRightColumn; c++)
// Guard against size of pasted block going beyond last line or column
if (r < 25 && c < 40)
rowArray.append(m_teletextDocument->currentSubPage()->character(r, c));
else
// Gone beyond last line or column - store a filler character which we won't see
// Not sure if this is really necessary as out-of-bounds access might not occur?
rowArray.append(0x7f);
m_deletedCharacters.append(rowArray);
}
setText(QObject::tr("paste"));
}
void PasteCommand::redo()
{
if (m_clipboardDataWidth == 0)
return;
m_teletextDocument->selectSubPageIndex(m_subPageIndex);
int arrayR = 0;
int arrayC;
for (int r=m_pasteTopRow; r<=m_pasteBottomRow; r++) {
arrayC = 0;
for (int c=m_pasteLeftColumn; c<=m_pasteRightColumn; c++)
// Guard against size of pasted block going beyond last line or column
if (r < 25 && c < 40) {
m_teletextDocument->currentSubPage()->setCharacter(r, c, m_pastingCharacters[arrayR].at(arrayC++));
// If paste area is wider than clipboard data, repeat the pattern
if (arrayC == m_clipboardDataWidth)
arrayC = 0;
}
if (r < 25)
emit m_teletextDocument->contentsChange(r);
arrayR++;
// If paste area is taller than clipboard data, repeat the pattern
if (arrayR == m_clipboardDataHeight)
arrayR = 0;
}
if (m_selectionActive) {
m_teletextDocument->setSelectionCorner(m_selectionCornerRow, m_selectionCornerColumn);
m_teletextDocument->moveCursor(m_row, m_column, true);
} else {
m_teletextDocument->moveCursor(m_row, m_column+m_clipboardDataWidth-1);
m_teletextDocument->cursorRight();
}
}
void PasteCommand::undo()
{
if (m_clipboardDataWidth == 0)
return;
m_teletextDocument->selectSubPageIndex(m_subPageIndex);
int arrayR = 0;
int arrayC;
for (int r=m_pasteTopRow; r<=m_pasteBottomRow; r++) {
arrayC = 0;
for (int c=m_pasteLeftColumn; c<=m_pasteRightColumn; c++)
// Guard against size of pasted block going beyond last line or column
if (r < 25 && c < 40)
m_teletextDocument->currentSubPage()->setCharacter(r, c, m_deletedCharacters[arrayR].at(arrayC++));
if (r < 25)
emit m_teletextDocument->contentsChange(r);
arrayR++;
}
}
#endif // !QT_NO_CLIPBOARD
InsertSubPageCommand::InsertSubPageCommand(TeletextDocument *teletextDocument, bool afterCurrentSubPage, bool copySubPage, QUndoCommand *parent) : LevelOneCommand(teletextDocument, parent)
{
m_newSubPageIndex = m_subPageIndex + afterCurrentSubPage;

View File

@@ -20,6 +20,7 @@
#ifndef LEVELONECOMMANDS_H
#define LEVELONECOMMANDS_H
#include <QByteArrayList>
#include <QUndoCommand>
#include "document.h"
@@ -150,6 +151,38 @@ private:
unsigned char m_deletedRow[40];
};
#ifndef QT_NO_CLIPBOARD
class CutCommand : public LevelOneCommand
{
public:
CutCommand(TeletextDocument *, QUndoCommand *parent = 0);
void redo() override;
void undo() override;
private:
QByteArrayList m_deletedCharacters;
int m_selectionTopRow, m_selectionBottomRow, m_selectionLeftColumn, m_selectionRightColumn;
int m_selectionCornerRow, m_selectionCornerColumn;
};
class PasteCommand : public LevelOneCommand
{
public:
PasteCommand(TeletextDocument *, QUndoCommand *parent = 0);
void redo() override;
void undo() override;
private:
QByteArrayList m_deletedCharacters, m_pastingCharacters;
int m_pasteTopRow, m_pasteBottomRow, m_pasteLeftColumn, m_pasteRightColumn;
int m_clipboardDataHeight, m_clipboardDataWidth;
int m_selectionCornerRow, m_selectionCornerColumn;
bool m_selectionActive;
};
#endif // !QT_NO_CLIPBOARD
class SetColourCommand : public LevelOneCommand
{
public:

View File

@@ -17,7 +17,9 @@
* along with QTeletextMaker. If not, see <https://www.gnu.org/licenses/>.
*/
#include <QApplication>
#include <QBitmap>
#include <QClipboard>
#include <QFrame>
#include <QGraphicsItem>
#include <QGraphicsItemGroup>
@@ -25,6 +27,7 @@
#include <QGraphicsScene>
#include <QKeyEvent>
#include <QMenu>
#include <QMimeData>
#include <QPainter>
#include <QPair>
#include <QUndoCommand>
@@ -387,6 +390,48 @@ void TeletextWidget::toggleCharacterBit(unsigned char bitToToggle)
m_teletextDocument->undoStack()->push(new ToggleMosaicBitCommand(m_teletextDocument, bitToToggle));
}
void TeletextWidget::selectionToClipboard()
{
QByteArray nativeData;
QClipboard *clipboard = QApplication::clipboard();
nativeData.resize(2 + m_teletextDocument->selectionWidth() * m_teletextDocument->selectionHeight());
nativeData[0] = m_teletextDocument->selectionHeight();
nativeData[1] = m_teletextDocument->selectionWidth();
int i=2;
for (int r=m_teletextDocument->selectionTopRow(); r<=m_teletextDocument->selectionBottomRow(); r++)
for (int c=m_teletextDocument->selectionLeftColumn(); c<=m_teletextDocument->selectionRightColumn(); c++)
nativeData[i++] = m_teletextDocument->currentSubPage()->character(r, c);
QMimeData *mimeData = new QMimeData();
mimeData->setData("application/x-teletext", nativeData);
clipboard->setMimeData(mimeData);
}
void TeletextWidget::cut()
{
if (!m_teletextDocument->selectionActive())
return;
selectionToClipboard();
m_teletextDocument->undoStack()->push(new CutCommand(m_teletextDocument));
}
void TeletextWidget::copy()
{
if (!m_teletextDocument->selectionActive())
return;
selectionToClipboard();
}
void TeletextWidget::paste()
{
m_teletextDocument->undoStack()->push(new PasteCommand(m_teletextDocument));
}
QPair<int, int> TeletextWidget::mouseToRowAndColumn(const QPoint &mousePosition)
{
int row = mousePosition.y() / 10;

View File

@@ -75,6 +75,11 @@ public slots:
void setBlackBackgroundSubst(bool);
void setSidePanelWidths(int, int);
void setSidePanelAtL35Only(bool);
void cut();
void copy();
void paste();
void changeSize();
protected:
@@ -96,6 +101,7 @@ private:
int m_flashTiming, m_flashPhase;
void timerEvent(QTimerEvent *event) override;
void selectionToClipboard();
QPair<int, int> mouseToRowAndColumn(const QPoint &);
};

View File

@@ -292,36 +292,33 @@ void MainWindow::createActions()
redoAction->setShortcuts(QKeySequence::Redo);
editMenu->addSeparator();
#ifndef QT_NO_CLIPBOARD
/* const QIcon cutIcon = QIcon::fromTheme("edit-cut", QIcon(":/images/cut.png"));
const QIcon cutIcon = QIcon::fromTheme("edit-cut", QIcon(":/images/cut.png"));
QAction *cutAct = new QAction(cutIcon, tr("Cu&t"), this);
cutAct->setShortcuts(QKeySequence::Cut);
cutAct->setStatusTip(tr("Cut the current selection's contents to the "
"clipboard"));
connect(cutAct, &QAction::triggered, textWidget, &QTextEdit::cut);
cutAct->setStatusTip(tr("Cut the current selection's contents to the clipboard"));
connect(cutAct, &QAction::triggered, m_textWidget, &TeletextWidget::cut);
editMenu->addAction(cutAct);
editToolBar->addAction(cutAct);
const QIcon copyIcon = QIcon::fromTheme("edit-copy", QIcon(":/images/copy.png"));
QAction *copyAct = new QAction(copyIcon, tr("&Copy"), this);
copyAct->setShortcuts(QKeySequence::Copy);
copyAct->setStatusTip(tr("Copy the current selection's contents to the "
"clipboard"));
connect(copyAct, &QAction::triggered, textWidget, &QTextEdit::copy);
copyAct->setStatusTip(tr("Copy the current selection's contents to the clipboard"));
connect(copyAct, &QAction::triggered, m_textWidget, &TeletextWidget::copy);
editMenu->addAction(copyAct);
editToolBar->addAction(copyAct);
const QIcon pasteIcon = QIcon::fromTheme("edit-paste", QIcon(":/images/paste.png"));
QAction *pasteAct = new QAction(pasteIcon, tr("&Paste"), this);
pasteAct->setShortcuts(QKeySequence::Paste);
pasteAct->setStatusTip(tr("Paste the clipboard's contents into the current "
"selection"));
connect(pasteAct, &QAction::triggered, textWidget, &QTextEdit::paste);
pasteAct->setStatusTip(tr("Paste the clipboard's contents into the current selection"));
connect(pasteAct, &QAction::triggered, m_textWidget, &TeletextWidget::paste);
editMenu->addAction(pasteAct);
editToolBar->addAction(pasteAct);
editMenu->addSeparator();
*/
#endif // !QT_NO_CLIPBOARD
QAction *insertBlankRowAct = editMenu->addAction(tr("Insert blank row"));