Document changes

This commit is contained in:
Alex Spataru 2021-02-09 22:37:01 -05:00
parent f170984552
commit 5bdc1783d7
4 changed files with 221 additions and 24 deletions

View File

@ -86,16 +86,12 @@ Control {
Menu {
id: menu
onVisibleChanged: {
if (visible)
copyMenu.enabled = textEdit.copyAvailable()
}
MenuItem {
id: copyMenu
text: qsTr("Copy")
opacity: enabled ? 1 : 0.5
onClicked: textEdit.copy()
enabled: textEdit.copyAvailable
}
MenuItem {
@ -137,7 +133,7 @@ Control {
readOnly: true
color: "#8ecd9d"
font.pixelSize: 12
centerOnScroll: true
centerOnScroll: false
undoRedoEnabled: false
Layout.fillWidth: true
Layout.fillHeight: true

View File

@ -318,6 +318,10 @@ void Generator::readData(const QByteArray &data)
thread->start();
}
//----------------------------------------------------------------------------------------
// JSON worker object (executed for each frame on a new thread)
//----------------------------------------------------------------------------------------
JSONWorker::JSONWorker(const QByteArray &data)
{
m_data = data;

View File

@ -22,14 +22,29 @@
#include <QScrollBar>
#include <QApplication>
#include <IO/Console.h>
#include "QmlPlainTextEdit.h"
using namespace UI;
/*
* NOTE: most of the Doxygen documentation comments where heavily based from the following
* URL https://doc.qt.io/qt-5/qplaintextedit.html. In some cases the comments are a
* simple copy-paste job. I am lazy and the Qt documentation is very good IMO.
*
* This class works by initializing a QPlainTextEdit widget, rendering it into the
* the painter of a QML item and handling keyboard/mouse events.
*
* The rest of the functions are just a wrapper around the functions of the
* QPlainTextEdit widget for increased QML-friendliness.
*/
/**
* Constructor function
*/
QmlPlainTextEdit::QmlPlainTextEdit(QQuickItem *parent)
: QQuickPaintedItem(parent)
, m_copyAvailable(false)
{
// Set item flags
setFlag(ItemHasContents, true);
@ -39,9 +54,7 @@ QmlPlainTextEdit::QmlPlainTextEdit(QQuickItem *parent)
// Initialize the text edit widget
m_textEdit = new QPlainTextEdit();
m_textEdit->installEventFilter(this);
// Set focus to the text edit
m_textEdit->setContextMenuPolicy(Qt::DefaultContextMenu);
m_textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
// Set the QML item's implicit size
auto hint = m_textEdit->sizeHint();
@ -55,13 +68,22 @@ QmlPlainTextEdit::QmlPlainTextEdit(QQuickItem *parent)
&QmlPlainTextEdit::updateWidgetSize);
connect(this, &QQuickPaintedItem::heightChanged, this,
&QmlPlainTextEdit::updateWidgetSize);
// React to widget events
connect(m_textEdit, SIGNAL(copyAvailable(bool)), this, SLOT(setCopyAvailable(bool)));
}
/**
* Destructor function
*/
QmlPlainTextEdit::~QmlPlainTextEdit()
{
m_textEdit->deleteLater();
}
/**
* Handle application events manually
*/
bool QmlPlainTextEdit::event(QEvent *event)
{
switch (event->type())
@ -88,12 +110,18 @@ bool QmlPlainTextEdit::event(QEvent *event)
return QApplication::sendEvent(m_textEdit, event);
}
/**
* Render the text edit on the given @a painter
*/
void QmlPlainTextEdit::paint(QPainter *painter)
{
if (m_textEdit && painter)
m_textEdit->render(painter);
}
/**
* Custom event filter to manage redraw requests
*/
bool QmlPlainTextEdit::eventFilter(QObject *watched, QEvent *event)
{
Q_ASSERT(m_textEdit);
@ -114,80 +142,144 @@ bool QmlPlainTextEdit::eventFilter(QObject *watched, QEvent *event)
return QQuickPaintedItem::eventFilter(watched, event);
}
/**
* Returns the font used by the QPlainTextEdit widget
*/
QFont QmlPlainTextEdit::font() const
{
return m_textEdit->font();
}
/**
* Returns the text color used by the QPlainTextEdit widget
*/
QColor QmlPlainTextEdit::color() const
{
return m_color;
}
/**
* Returns the plain text of the QPlainTextEdit widget
*/
QString QmlPlainTextEdit::text() const
{
return m_textEdit->toPlainText();
}
/**
* Returns @c true if the widget is set to read-only
*/
bool QmlPlainTextEdit::readOnly() const
{
return m_textEdit->isReadOnly();
}
/**
* Returns @c true if the widget shall scroll automatically to the bottom when new
* text is appended to the widget.
*/
bool QmlPlainTextEdit::autoscroll() const
{
return m_autoscroll;
}
/**
* Returns the palette used by the QPlainTextEdit widget
*/
QPalette QmlPlainTextEdit::palette() const
{
return m_textEdit->palette();
}
/**
* Returns the wrap mode of the QPlainTextEdit casted to an integer type (so that it
* can be used from the QML interface).
*/
int QmlPlainTextEdit::wordWrapMode() const
{
return static_cast<int>(m_textEdit->wordWrapMode());
}
/**
* Returns @c true if the user is able to copy any text from the document. This value is
* updated through the copyAvailable() signal sent by the QPlainTextEdit.
*/
bool QmlPlainTextEdit::copyAvailable() const
{
return m_copyAvailable;
}
/**
* Returns @c true if the QPlainTextEdit widget is enabled
*/
bool QmlPlainTextEdit::widgetEnabled() const
{
return m_textEdit->isEnabled();
}
/**
* If set to true, the plain text edit scrolls the document vertically to make the cursor
* visible at the center of the viewport. This also allows the text edit to scroll below
* the end of the document. Otherwise, if set to false, the plain text edit scrolls the
* smallest amount possible to ensure the cursor is visible.
*/
bool QmlPlainTextEdit::centerOnScroll() const
{
return m_textEdit->centerOnScroll();
}
/**
* This property holds whether undo and redo are enabled.
* Users are only able to undo or redo actions if this property is true, and if there is
* an action that can be undone (or redone).
*/
bool QmlPlainTextEdit::undoRedoEnabled() const
{
return m_textEdit->isUndoRedoEnabled();
}
/**
* This property holds the limit for blocks in the document.
*
* Specifies the maximum number of blocks the document may have. If there are more blocks
* in the document that specified with this property blocks are removed from the beginning
* of the document.
*
* A negative or zero value specifies that the document may contain an unlimited amount
* of blocks.
*/
int QmlPlainTextEdit::maximumBlockCount() const
{
return m_textEdit->maximumBlockCount();
}
/**
* This property holds the editor placeholder text.
*
* Setting this property makes the editor display a grayed-out placeholder text as long as
* the document is empty.
*/
QString QmlPlainTextEdit::placeholderText() const
{
return m_textEdit->placeholderText();
}
bool QmlPlainTextEdit::copyAvailable() const
{
return text().length() > 0;
}
/**
* Process mouse incoming from the QML interface
*/
void QmlPlainTextEdit::routeMouseEvents(QMouseEvent *event)
{
QMouseEvent *newEvent
= new QMouseEvent(event->type(), event->localPos(), event->button(),
event->buttons(), event->modifiers());
m_textEdit->setFocus(Qt::ActiveWindowFocusReason);
m_textEdit->grabMouse();
QApplication::postEvent(m_textEdit, newEvent);
}
/**
* Process mouse wheel incoming from the QML interface
*/
void QmlPlainTextEdit::routeWheelEvents(QWheelEvent *event)
{
QWheelEvent *newEvent
@ -196,11 +288,17 @@ void QmlPlainTextEdit::routeWheelEvents(QWheelEvent *event)
QApplication::postEvent(m_textEdit, newEvent);
}
/**
* Copies any selected text to the clipboard.
*/
void QmlPlainTextEdit::copy()
{
m_textEdit->copy();
}
/**
* Deletes all the text in the text edit.
*/
void QmlPlainTextEdit::clear()
{
m_textEdit->clear();
@ -209,6 +307,9 @@ void QmlPlainTextEdit::clear()
emit textChanged();
}
/**
* Selects all the text of the text edit.
*/
void QmlPlainTextEdit::selectAll()
{
m_textEdit->selectAll();
@ -217,6 +318,12 @@ void QmlPlainTextEdit::selectAll()
emit textChanged();
}
/**
* Changes the read-only state of the text edit.
*
* In a read-only text edit the user can only navigate through the text and select text;
* modifying the text is not possible.
*/
void QmlPlainTextEdit::setReadOnly(const bool ro)
{
m_textEdit->setReadOnly(ro);
@ -225,6 +332,9 @@ void QmlPlainTextEdit::setReadOnly(const bool ro)
emit readOnlyChanged();
}
/**
* Changes the font used to display the text of the text edit.
*/
void QmlPlainTextEdit::setFont(const QFont &font)
{
m_textEdit->setFont(font);
@ -233,34 +343,43 @@ void QmlPlainTextEdit::setFont(const QFont &font)
emit fontChanged();
}
/**
* Appends a new paragraph with text to the end of the text edit.
*
* If @c autoscroll() is enabled, this function shall also update the scrollbar position
* to scroll to the bottom of the text.
*/
void QmlPlainTextEdit::append(const QString &text)
{
m_textEdit->appendPlainText(text);
if (autoscroll())
{
auto *bar = m_textEdit->verticalScrollBar();
bar->setValue(bar->maximum());
}
scrollToBottom(false);
update();
emit textChanged();
}
/**
* Replaces the text of the text editor with @c text.
*
* If @c autoscroll() is enabled, this function shall also update the scrollbar position
* to scroll to the bottom of the text.
*/
void QmlPlainTextEdit::setText(const QString &text)
{
m_textEdit->setPlainText(text);
if (autoscroll())
{
auto *bar = m_textEdit->verticalScrollBar();
bar->setValue(bar->maximum());
}
scrollToBottom(false);
update();
emit textChanged();
}
/**
* Changes the text color of the text editor.
*/
void QmlPlainTextEdit::setColor(const QColor &color)
{
m_color = color;
@ -271,6 +390,9 @@ void QmlPlainTextEdit::setColor(const QColor &color)
emit colorChanged();
}
/**
* Changes the @c QPalette of the text editor widget and its children.
*/
void QmlPlainTextEdit::setPalette(const QPalette &palette)
{
m_textEdit->setPalette(palette);
@ -279,6 +401,9 @@ void QmlPlainTextEdit::setPalette(const QPalette &palette)
emit paletteChanged();
}
/**
* Enables or disables the text editor widget.
*/
void QmlPlainTextEdit::setWidgetEnabled(const bool enabled)
{
m_textEdit->setEnabled(enabled);
@ -287,12 +412,22 @@ void QmlPlainTextEdit::setWidgetEnabled(const bool enabled)
emit widgetEnabledChanged();
}
/**
* Enables/disable automatic scrolling. If automatic scrolling is enabled, then the
* vertical scrollbar shall automatically scroll to the end of the document when the
* text of the text editor is changed.
*/
void QmlPlainTextEdit::setAutoscroll(const bool enabled)
{
m_autoscroll = enabled;
emit autoscrollChanged();
}
/**
* Changes the word wrap mode of the text editor.
*
* This property holds the mode QPlainTextEdit will use when wrapping text by words.
*/
void QmlPlainTextEdit::setWordWrapMode(const int mode)
{
m_textEdit->setWordWrapMode(static_cast<QTextOption::WrapMode>(mode));
@ -301,6 +436,12 @@ void QmlPlainTextEdit::setWordWrapMode(const int mode)
emit wordWrapModeChanged();
}
/**
* If set to true, the plain text edit scrolls the document vertically to make the cursor
* visible at the center of the viewport. This also allows the text edit to scroll below
* the end of the document. Otherwise, if set to false, the plain text edit scrolls the
* smallest amount possible to ensure the cursor is visible.
*/
void QmlPlainTextEdit::setCenterOnScroll(const bool enabled)
{
m_textEdit->setCenterOnScroll(enabled);
@ -309,6 +450,9 @@ void QmlPlainTextEdit::setCenterOnScroll(const bool enabled)
emit centerOnScrollChanged();
}
/**
* Enables/disables undo/redo history support.
*/
void QmlPlainTextEdit::setUndoRedoEnabled(const bool enabled)
{
m_textEdit->setUndoRedoEnabled(enabled);
@ -317,6 +461,10 @@ void QmlPlainTextEdit::setUndoRedoEnabled(const bool enabled)
emit undoRedoEnabledChanged();
}
/**
* Changes the placeholder text of the text editor. The placeholder text is only displayed
* when the document is empty.
*/
void QmlPlainTextEdit::setPlaceholderText(const QString &text)
{
m_textEdit->setPlaceholderText(text);
@ -325,6 +473,35 @@ void QmlPlainTextEdit::setPlaceholderText(const QString &text)
emit placeholderTextChanged();
}
/**
* Moves the position of the vertical scrollbar to the end of the document. However, this
* function also ensures that the last line of the document is shown at the bottom of
* the widget to mimic a terminal.
*/
void QmlPlainTextEdit::scrollToBottom(const bool repaint)
{
auto *bar = m_textEdit->verticalScrollBar();
auto textHeight = m_textEdit->height() / m_textEdit->fontMetrics().height();
auto scrollIndex = bar->maximum() - textHeight;
if (scrollIndex < 0)
scrollIndex = 0;
bar->setValue(scrollIndex);
bar->setMaximum(scrollIndex);
if (repaint)
update();
}
/**
* Specifies the maximum number of blocks the document may have. If there are more blocks
* in the document that specified with this property blocks are removed from the beginning
* of the document.
*
* A negative or zero value specifies that the document may contain an unlimited amount of
* blocks.
*/
void QmlPlainTextEdit::setMaximumBlockCount(const int maxBlockCount)
{
m_textEdit->setMaximumBlockCount(maxBlockCount);
@ -333,8 +510,21 @@ void QmlPlainTextEdit::setMaximumBlockCount(const int maxBlockCount)
emit maximumBlockCountChanged();
}
/**
* Resizes the text editor widget to fit inside the QML item.
*/
void QmlPlainTextEdit::updateWidgetSize()
{
m_textEdit->setGeometry(0, 0, static_cast<int>(width()), static_cast<int>(height()));
update();
}
/**
* Updates the value of copy-available. This function is automatically called by the text
* editor widget when the user makes any text selection/deselection.
*/
void QmlPlainTextEdit::setCopyAvailable(const bool yes)
{
m_copyAvailable = yes;
emit copyAvailableChanged();
}

View File

@ -82,6 +82,9 @@ class QmlPlainTextEdit : public QQuickPaintedItem
READ maximumBlockCount
WRITE setMaximumBlockCount
NOTIFY maximumBlockCountChanged)
Q_PROPERTY(bool copyAvailable
READ copyAvailable
NOTIFY copyAvailableChanged)
// clang-format on
signals:
@ -92,6 +95,7 @@ signals:
void readOnlyChanged();
void autoscrollChanged();
void wordWrapModeChanged();
void copyAvailableChanged();
void widgetEnabledChanged();
void centerOnScrollChanged();
void placeholderTextChanged();
@ -114,12 +118,12 @@ public:
bool autoscroll() const;
QPalette palette() const;
int wordWrapMode() const;
bool copyAvailable() const;
bool widgetEnabled() const;
bool centerOnScroll() const;
bool undoRedoEnabled() const;
int maximumBlockCount() const;
QString placeholderText() const;
Q_INVOKABLE bool copyAvailable() const;
protected:
void routeMouseEvents(QMouseEvent *event);
@ -141,14 +145,17 @@ public slots:
void setCenterOnScroll(const bool enabled);
void setUndoRedoEnabled(const bool enabled);
void setPlaceholderText(const QString &text);
void scrollToBottom(const bool repaint = true);
void setMaximumBlockCount(const int maxBlockCount);
private slots:
void updateWidgetSize();
void setCopyAvailable(const bool yes);
private:
QColor m_color;
bool m_autoscroll;
bool m_copyAvailable;
QPlainTextEdit *m_textEdit;
};
}