Allow copying & exporting console data

This commit is contained in:
Alex Spataru 2021-02-05 10:48:29 -05:00
parent 99471c771f
commit 681952701e
13 changed files with 266 additions and 4 deletions

View File

@ -41,6 +41,13 @@ Control {
//
property alias text: textArea.text
readonly property color consoleColor: "#8ecd9d"
//
// Hacks to allow context menu to work
//
property int curPos
property int selectEnd
property int selectStart
//
// Function to send through serial port data
@ -62,6 +69,42 @@ Control {
property alias displayMode: displayModeCombo.currentIndex
}
//
// Shortcut to copy selection of console
//
Shortcut {
sequence: StandardKey.Copy
onActivated: textArea.copy()
}
//
// Right-click context menu
//
Menu {
id: contextMenu
MenuItem {
text: qsTr("Copy")
opacity: enabled ? 1 : 0.5
onTriggered: textArea.copy()
enabled: textArea.selectedText
}
MenuItem {
text: qsTr("Clear")
opacity: enabled ? 1 : 0.5
enabled: textArea.length > 0
onTriggered: Cpp_IO_Console.clear()
}
MenuItem {
opacity: enabled ? 1 : 0.5
text: qsTr("Save as") + "..."
onTriggered: Cpp_IO_Console.save()
enabled: Cpp_IO_Console.saveAvailable
}
}
//
// Controls
//
@ -111,18 +154,54 @@ Control {
TextEdit {
id: textArea
focus: true
readOnly: true
font.pixelSize: 12
width: flick.width
height: flick.height
selectByMouse: true
selectByKeyboard: true
color: root.consoleColor
persistentSelection: true
wrapMode: TextEdit.NoWrap
font.family: app.monoFont
selectionColor: palette.highlight
selectedTextColor: palette.highlightedText
onCursorRectangleChanged: flick.ensureVisible(cursorRectangle)
onTextChanged: {
if (Cpp_IO_Console.autoscroll)
textArea.cursorPosition = textArea.length
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.RightButton
onClicked: {
root.selectStart = textArea.selectionStart;
root.selectEnd = textArea.selectionEnd;
root.curPos = textArea.cursorPosition;
contextMenu.x = mouse.x;
contextMenu.y = mouse.y;
contextMenu.open();
textArea.cursorPosition = root.curPos;
textArea.select(root.selectStart, root.selectEnd);
}
onPressAndHold: {
if (mouse.source === Qt.MouseEventNotSynthesized) {
root.selectStart = textArea.selectionStart;
root.selectEnd = textArea.selectionEnd;
root.curPos = textArea.cursorPosition;
contextMenu.x = mouse.x;
contextMenu.y = mouse.y;
contextMenu.open();
textArea.cursorPosition = root.curPos;
textArea.select(root.selectStart, root.selectEnd);
}
}
}
}
}
}
@ -246,6 +325,18 @@ Control {
Button {
height: 24
Layout.maximumWidth: 32
icon.color: palette.text
opacity: enabled ? 1 : 0.5
onClicked: Cpp_IO_Console.save()
icon.source: "qrc:/icons/save.svg"
enabled: Cpp_IO_Console.saveAvailable
Behavior on opacity {NumberAnimation{}}
}
Button {
height: 24
Layout.maximumWidth: 32
icon.color: palette.text
opacity: enabled ? 1 : 0.5
enabled: textArea.length > 0

View File

@ -186,7 +186,7 @@ Control {
//
Label {
opacity: enabled ? 1 : 0.5
enabled: !Cpp_IO_Serial.connected
enabled: !Cpp_IO_Manager.connected
Behavior on opacity {NumberAnimation{}}
text: qsTr("COM Port") + ":"
} ComboBox {
@ -200,7 +200,7 @@ Control {
}
opacity: enabled ? 1 : 0.5
enabled: !Cpp_IO_Serial.connected
enabled: !Cpp_IO_Manager.connected
Behavior on opacity {NumberAnimation{}}
}
@ -209,7 +209,6 @@ Control {
//
Label {
opacity: enabled ? 1 : 0.5
enabled: !Cpp_IO_Serial.connected
Behavior on opacity {NumberAnimation{}}
text: qsTr("Baud Rate") + ":"
} ComboBox {

Binary file not shown.

View File

@ -155,6 +155,18 @@
<source>Show timestamp</source>
<translation>Zeitstempel anzeigen</translation>
</message>
<message>
<source>Copy</source>
<translation>Kopieren</translation>
</message>
<message>
<source>Clear</source>
<translation>Löschen</translation>
</message>
<message>
<source>Save as</source>
<translation>Speichern als</translation>
</message>
</context>
<context>
<name>CsvPlayer</name>
@ -459,6 +471,18 @@
<source>Hexadecimal</source>
<translation>Hexadezimal</translation>
</message>
<message>
<source>Export console data</source>
<translation>Konsolendaten exportieren</translation>
</message>
<message>
<source>Text files</source>
<translation>Textdateien</translation>
</message>
<message>
<source>File save error</source>
<translation>Fehler beim Speichern der Datei</translation>
</message>
</context>
<context>
<name>IO::DataSources::Serial</name>

Binary file not shown.

View File

@ -151,6 +151,18 @@
<source>Show timestamp</source>
<translation></translation>
</message>
<message>
<source>Copy</source>
<translation></translation>
</message>
<message>
<source>Clear</source>
<translation></translation>
</message>
<message>
<source>Save as</source>
<translation></translation>
</message>
</context>
<context>
<name>CsvPlayer</name>
@ -396,6 +408,18 @@
<source>Hexadecimal</source>
<translation></translation>
</message>
<message>
<source>Export console data</source>
<translation></translation>
</message>
<message>
<source>Text files</source>
<translation></translation>
</message>
<message>
<source>File save error</source>
<translation></translation>
</message>
</context>
<context>
<name>IO::DataSources::Serial</name>

Binary file not shown.

View File

@ -159,6 +159,18 @@
<source>Show timestamp</source>
<translation>Marca de tiempo</translation>
</message>
<message>
<source>Copy</source>
<translation>Copiar</translation>
</message>
<message>
<source>Clear</source>
<translation>Limpiar</translation>
</message>
<message>
<source>Save as</source>
<translation>Guardar como</translation>
</message>
</context>
<context>
<name>CsvPlayer</name>
@ -491,6 +503,18 @@
<source>Hexadecimal</source>
<translation>Hexadecimal</translation>
</message>
<message>
<source>Export console data</source>
<translation>Exportar datos de la consola</translation>
</message>
<message>
<source>Text files</source>
<translation>Archivos de texto</translation>
</message>
<message>
<source>File save error</source>
<translation>Error al intentar guardar el archivo</translation>
</message>
</context>
<context>
<name>IO::DataSources::Serial</name>

Binary file not shown.

View File

@ -155,6 +155,18 @@
<source>Show timestamp</source>
<translation></translation>
</message>
<message>
<source>Copy</source>
<translation></translation>
</message>
<message>
<source>Clear</source>
<translation></translation>
</message>
<message>
<source>Save as</source>
<translation></translation>
</message>
</context>
<context>
<name>CsvPlayer</name>
@ -487,6 +499,18 @@
<source>Hexadecimal</source>
<translation></translation>
</message>
<message>
<source>Export console data</source>
<translation></translation>
</message>
<message>
<source>Text files</source>
<translation></translation>
</message>
<message>
<source>File save error</source>
<translation></translation>
</message>
</context>
<context>
<name>IO::DataSources::Serial</name>

View File

@ -23,13 +23,21 @@
#include "Console.h"
#include "Manager.h"
#include <QFile>
#include <Logger.h>
#include <QTextCodec>
#include <QFileDialog>
#include <Misc/Utilities.h>
#include <ConsoleAppender.h>
using namespace IO;
static Console *INSTANCE = nullptr;
/**
* Set buffer size to 15 MB
*/
static const int MAX_BUFFER_SIZE = 1024 * 1024 * 15;
/**
* Constructor function
*/
@ -45,6 +53,7 @@ Console::Console()
, m_cursor(nullptr)
, m_document(nullptr)
{
clear();
auto m = Manager::getInstance();
connect(m, &Manager::dataReceived, this, &Console::onDataReceived);
LOG_INFO() << "Class initialized";
@ -79,6 +88,14 @@ bool Console::autoscroll() const
return m_autoscroll;
}
/**
* Returns @c true if data buffer contains information that the user can export.
*/
bool Console::saveAvailable() const
{
return m_dataBuffer.size() > 0;
}
/**
* Returns @c true if a timestamp should be shown before each displayed data block.
*/
@ -190,15 +207,49 @@ QStringList Console::displayModes() const
void Console::copy() { }
void Console::save() { }
/**
* Allows the user to export the information displayed on the console
*/
void Console::save()
{
// No data buffer received, abort
if (!saveAvailable())
return;
// Get file name
auto path
= QFileDialog::getSaveFileName(Q_NULLPTR, tr("Export console data"),
QDir::homePath(), tr("Text files") + " (*.txt)");
// Create file
if (!path.isEmpty())
{
QFile file(path);
if (file.open(QFile::WriteOnly))
{
file.write(m_dataBuffer);
file.close();
Misc::Utilities::revealFile(path);
}
else
Misc::Utilities::showMessageBox(tr("File save error"), file.errorString());
}
}
/**
* Deletes all the text displayed by the current QML text document
*/
void Console::clear()
{
// Clear console display
if (document())
document()->clear();
// Reserve 15 MB for data buffer
m_dataBuffer.clear();
m_dataBuffer.reserve(MAX_BUFFER_SIZE);
}
/**
@ -383,10 +434,25 @@ void Console::setTextDocument(QQuickTextDocument *document)
* Displays the given @a data in the console. @c QByteArray to ~@c QString conversion is
* done by the @c dataToString() function, which displays incoming data either in UTF-8
* or in hexadecimal mode.
*
* The incoming data is also added to a buffer so that the user can save the file if
* needed.
*/
void Console::onDataReceived(const QByteArray &data)
{
// Display data
append(dataToString(data));
// Append data to buffer
m_dataBuffer.append(data);
if (m_dataBuffer.size() > MAX_BUFFER_SIZE)
{
m_dataBuffer.clear();
m_dataBuffer.reserve(MAX_BUFFER_SIZE);
}
// Notify UI
emit dataReceived();
}
/**

View File

@ -48,6 +48,9 @@ class Console : public QObject
READ showTimestamp
WRITE setShowTimestamp
NOTIFY showTimestampChanged)
Q_PROPERTY(bool saveAvailable
READ saveAvailable
NOTIFY dataReceived)
Q_PROPERTY(IO::Console::DataMode dataMode
READ dataMode
WRITE setDataMode
@ -67,6 +70,7 @@ class Console : public QObject
signals:
void echoChanged();
void dataReceived();
void dataModeChanged();
void autoscrollChanged();
void lineEndingChanged();
@ -103,6 +107,7 @@ public:
bool echo() const;
bool autoscroll() const;
bool saveAvailable() const;
bool showTimestamp() const;
DataMode dataMode() const;
@ -145,6 +150,7 @@ private:
private:
DataMode m_dataMode;
QByteArray m_dataBuffer;
LineEnding m_lineEnding;
DisplayMode m_displayMode;

View File

@ -46,6 +46,7 @@ Manager::Manager()
, m_finishSequence("*/")
{
setWatchdogInterval(15);
setMaxBufferSize(1024 * 1024);
LOG_INFO() << "Class initialized";
}
@ -310,6 +311,7 @@ void Manager::disconnectDevice()
m_device = nullptr;
m_receivedBytes = 0;
m_dataBuffer.clear();
m_dataBuffer.reserve(maxBufferSize());
// Update UI
emit deviceChanged();
@ -351,6 +353,8 @@ void Manager::setMaxBufferSize(const int maxBufferSize)
{
m_maxBuzzerSize = maxBufferSize;
emit maxBufferSizeChanged();
m_dataBuffer.reserve(maxBufferSize);
}
/**