diff --git a/CellFrameDashboardGUI/CellFrameDashboardGUI.pro b/CellFrameDashboardGUI/CellFrameDashboardGUI.pro index 3a5fc878c2c2072fe838dec521d924a81a280ddf..b9b8631a41905b1b7a8607763560e991d61d841e 100755 --- a/CellFrameDashboardGUI/CellFrameDashboardGUI.pro +++ b/CellFrameDashboardGUI/CellFrameDashboardGUI.pro @@ -42,6 +42,7 @@ ICON = icon.ico SOURCES += \ DapChainNodeNetworkExplorer.cpp \ DapChainNodeNetworkModel.cpp \ + DapConsoleModel.cpp \ DapScreenHistoryFilterModel.cpp \ DapScreenHistoryModel.cpp \ DapSettingsNetworkModel.cpp \ @@ -79,6 +80,7 @@ else: unix:!android: target.path = /opt/cellframe-dashboard/bin HEADERS += \ DapChainNodeNetworkExplorer.h \ DapChainNodeNetworkModel.h \ + DapConsoleModel.h \ DapScreenHistoryFilterModel.h \ DapScreenHistoryModel.h \ DapSettingsNetworkModel.h \ diff --git a/CellFrameDashboardGUI/DapCommandController.cpp b/CellFrameDashboardGUI/DapCommandController.cpp index a6f5629a5d3d37d75481175318508cdc5e96b916..47562227a6d7cb21cf7422882613cefa457157d7 100755 --- a/CellFrameDashboardGUI/DapCommandController.cpp +++ b/CellFrameDashboardGUI/DapCommandController.cpp @@ -39,11 +39,6 @@ void DapCommandController::processCommandResult() emit sigCommandResult(reply->response().result()); } -void DapCommandController::clearLogModel() -{ - emit onClearLogModel(); -} - /// Get node logs. void DapCommandController::getNodeLogs() { @@ -63,6 +58,18 @@ void DapCommandController::setNewHistory(const QVariant& aData) emit sendHistory(aData); } +void DapCommandController::requestConsole(const QString& aQueue) +{ + DapRpcServiceReply *reply = m_DAPRpcSocket->invokeRemoteMethod("RPCServer.getQueryResult", aQueue); + connect(reply, SIGNAL(finished()), this, SLOT(processResponseConsole())); +} + +void DapCommandController::getCmdHistory() +{ + DapRpcServiceReply *reply = m_DAPRpcSocket->invokeRemoteMethod("RPCServer.getCmdHistory"); + connect(reply, SIGNAL(finished()), this, SLOT(processGetCmdHistory())); +} + void DapCommandController::changeCurrentNetwork(const QString& aNetwork) { m_DAPRpcSocket->invokeRemoteMethod("RPCServer.changeCurrentNetwork", aNetwork); @@ -73,7 +80,7 @@ void DapCommandController::processChangedLog() // QStringList tempLogModel; // for(int x{0}; x < aLogModel.count(); ++x) // tempLogModel.append(aLogModel.at(x).toString()); - emit onLogModel(); + emit onChangeLogModel(); } /// Handling service response for receiving node logs. @@ -196,6 +203,20 @@ void DapCommandController::processGetHistory() emit sendHistory(result); } +void DapCommandController::processResponseConsole() +{ + DapRpcServiceReply *reply = static_cast<DapRpcServiceReply *>(sender()); + QString result = reply->response().result().toVariant().toString(); + emit responseConsole(result); +} + +void DapCommandController::processGetCmdHistory() +{ + DapRpcServiceReply *reply = static_cast<DapRpcServiceReply *>(sender()); + QString result = reply->response().result().toVariant().toString(); + emit sigCmdHistory(result); +} + void DapCommandController::processGetNetworkList() { DapRpcServiceReply *reply = static_cast<DapRpcServiceReply *>(sender()); diff --git a/CellFrameDashboardGUI/DapCommandController.h b/CellFrameDashboardGUI/DapCommandController.h index 605f85ff3e073607df8a6157cc156cf62b633ab6..a8dd9ffdbee2728879168f809cae0981fe1dc4e0 100755 --- a/CellFrameDashboardGUI/DapCommandController.h +++ b/CellFrameDashboardGUI/DapCommandController.h @@ -42,12 +42,14 @@ signals: void sendNodeStatus(const QVariant& aData); /// void executeCommandChanged(const QString& result); - /// Signal for cleaning log - void onClearLogModel(); - /// - void onLogModel(); + /// Signal for changing logs + void onChangeLogModel(); /// Signal for sending new transaction history void sendHistory(const QVariant& aData); + /// Response from service about command request + void responseConsole(const QString& aResponse); + /// Signal about changing history of commands + void sigCmdHistory(const QString& aHistory); void sendNetworkList(const QStringList& aList); @@ -82,6 +84,10 @@ private slots: void processGetNetworkList(); + void processResponseConsole(); + + void processGetCmdHistory(); + public slots: /// Show or hide GUI client by clicking on the tray icon. /// @param aIsActivated Accepts true - when requesting to @@ -108,7 +114,6 @@ public slots: void executeCommand(const QString& command); - void clearLogModel(); /// Get node logs. void getNodeLogs(); @@ -116,6 +121,10 @@ public slots: void getHistory(); /// Send to model new history void setNewHistory(const QVariant& aData); + /// Commands request + void requestConsole(const QString& aQueue); + /// Get command history + void getCmdHistory(); void changeCurrentNetwork(const QString& aNetwork); }; diff --git a/CellFrameDashboardGUI/DapConsoleModel.cpp b/CellFrameDashboardGUI/DapConsoleModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..01d0ad78a6a60f5ca25964bc7d4342da5b9ce6dc --- /dev/null +++ b/CellFrameDashboardGUI/DapConsoleModel.cpp @@ -0,0 +1,101 @@ +#include "DapConsoleModel.h" + +DapConsoleModel::DapConsoleModel(QObject *parent) : + QAbstractListModel(parent) +{ + +} + +DapConsoleModel& DapConsoleModel::getInstance() +{ + static DapConsoleModel instance; + return instance; +} + +void DapConsoleModel::receiveResponse(const QString& aResponse) +{ + m_History.append(aResponse); + emit sendResponse(aResponse); +} + +int DapConsoleModel::rowCount(const QModelIndex& parent) const +{ + Q_UNUSED(parent) + + return m_CommandList.count(); +} + +QVariant DapConsoleModel::data(const QModelIndex& index, int role) const +{ + if (!index.isValid()) return QVariant(); + + if(role == LastCommand) + return m_CommandList.at(index.row()); + + return QVariant(); +} + +QHash<int, QByteArray> DapConsoleModel::roleNames() const +{ + QHash<int, QByteArray> roles; + roles[LastCommand] = "lastCommand"; + return roles; +} + +QString DapConsoleModel::getCommandUp() +{ + if(m_CommandList.isEmpty()) return QString(); + if(m_CommandIndex > m_CommandList.begin()) m_CommandIndex--; + return *m_CommandIndex; +} + +QString DapConsoleModel::getCommandDown() +{ + if(m_CommandList.isEmpty()) return QString(); + if(m_CommandIndex < m_CommandList.end() -1) m_CommandIndex++; + else return QString(); + return *m_CommandIndex; +} + +void DapConsoleModel::receiveRequest(const QString& aCommand) +{ + beginResetModel(); + if(!m_CommandList.contains(aCommand)) + m_CommandList.append(aCommand); + endResetModel(); + m_CommandIndex = m_CommandList.end(); + + QString returnSymbol = "\n"; + +#ifdef Q_OS_WIN + returnSymbol.prepend("\r"); +#endif + + m_History.append(returnSymbol + "> " + aCommand + returnSymbol); + emit sendRequest(aCommand); +} + +QString DapConsoleModel::getCmdHistory() +{ + return m_History; +} + +void DapConsoleModel::receiveCmdHistory(const QString& aHistory) +{ + m_History = aHistory; + QRegularExpression rx("^> (.+)$"); + rx.setPatternOptions(QRegularExpression::MultilineOption); + + QRegularExpressionMatchIterator i = rx.globalMatch(m_History); + + while (i.hasNext()) { + QRegularExpressionMatch match = i.next(); + QString cmd = match.captured(1).remove(QChar('\r'), Qt::CaseInsensitive); + if(!m_CommandList.contains(cmd)) + m_CommandList.append(cmd); + } + + if(!m_CommandList.isEmpty()) + m_CommandIndex = m_CommandList.end(); + emit cmdHistoryChanged(m_History); +} diff --git a/CellFrameDashboardGUI/DapConsoleModel.h b/CellFrameDashboardGUI/DapConsoleModel.h new file mode 100644 index 0000000000000000000000000000000000000000..00bd228e4d905260b56eb8f6eb988f9fe8dc905d --- /dev/null +++ b/CellFrameDashboardGUI/DapConsoleModel.h @@ -0,0 +1,69 @@ +#ifndef DAPUIQMLSCREENCONSOLEFORM_H +#define DAPUIQMLSCREENCONSOLEFORM_H + +#include <QDebug> +#include <QAbstractListModel> +#include <QStringList> +#include <QRegularExpression> + +/// Model for DAP console +class DapConsoleModel : public QAbstractListModel +{ + Q_OBJECT + +public: + /// Enumeration for model roles + enum ConsoleRole { + LastCommand = Qt::DisplayRole + }; + +private: + QString m_History; + QStringList m_CommandList; + QStringList::iterator m_CommandIndex; + +public: + explicit DapConsoleModel(QObject *parent = nullptr); + +public slots: + /// Receive response from service about command + /// @param result + void receiveResponse(const QString& aResponse); + /// Override methods of abstract model + int rowCount(const QModelIndex& parent) const override; + QVariant data(const QModelIndex& index, int role) const override; + QHash<int, QByteArray> roleNames() const override; + + /// Getting instanse of this class + /// @return instanse of this class + Q_INVOKABLE static DapConsoleModel& getInstance(); + /// Get the latest commands + /// @return the latest commands + Q_INVOKABLE QString getCommandUp(); + /// Get the earliest commands + /// @return the earliest commands. If it is last command in the list + /// it returns QString() + Q_INVOKABLE QString getCommandDown(); + /// Receive command requst for service + /// @param command request + Q_INVOKABLE void receiveRequest(const QString& aCommand); + /// Get current history + /// @return history of commands + Q_INVOKABLE QString getCmdHistory(); + /// Receive new history of commands + /// @param last 50 commands + void receiveCmdHistory(const QString& aHistory); + +signals: + /// Signal to send request to the service + /// @param command + void sendRequest(QString command); + /// Signal for getting response from service + /// @param result of command + void sendResponse(QString response); + /// Signal for view about changing history + /// @param last 50 commands + void cmdHistoryChanged(QString history); +}; + +#endif // DAPUIQMLSCREENCONSOLEFORM_H diff --git a/CellFrameDashboardGUI/DapScreenHistoryModel.cpp b/CellFrameDashboardGUI/DapScreenHistoryModel.cpp index 91754fae220b5828e8b552efadac766768a0db9c..ac5b71693c474e239c347945181a39be5a4402ea 100644 --- a/CellFrameDashboardGUI/DapScreenHistoryModel.cpp +++ b/CellFrameDashboardGUI/DapScreenHistoryModel.cpp @@ -50,6 +50,7 @@ void DapScreenHistoryModel::receiveNewData(const QVariant& aData) return; } + qDebug() << aData; beginResetModel(); QList<QVariant> dataList = aData.toList(); m_elementList.clear(); diff --git a/CellFrameDashboardGUI/DapServiceController.cpp b/CellFrameDashboardGUI/DapServiceController.cpp index 3b60c7bbeac5ede1f271a3833d7de3235df67e2c..3792b8135fa1c5cff5551a232bdee20989713bd2 100755 --- a/CellFrameDashboardGUI/DapServiceController.cpp +++ b/CellFrameDashboardGUI/DapServiceController.cpp @@ -3,6 +3,8 @@ #include "DapLogMessage.h" #include "DapChainWallet.h" +#include <QRegularExpression> + DapServiceController::DapServiceController(QObject *apParent) : QObject(apParent) { @@ -29,6 +31,8 @@ void DapServiceController::closeClient() void DapServiceController::init(DapServiceClient *apDapServiceClient) { m_pDapServiceClient = apDapServiceClient; + + connect(m_pDapServiceClient, SIGNAL(sigDisconnected()), SLOT(clearLogModel())); // Creating rpc controller m_pDapCommandController = new DapCommandController(apDapServiceClient->getClientSocket(), this); @@ -51,7 +55,7 @@ void DapServiceController::init(DapServiceClient *apDapServiceClient) connect(m_pDapCommandController, SIGNAL(executeCommandChanged(QString)), SLOT(processExecuteCommandInfo(QString))); connect(m_pDapCommandController, SIGNAL(sendNodeNetwork(QVariant)), this, SLOT(processGetNodeNetwork(QVariant))); - connect(m_pDapCommandController, SIGNAL(onLogModel()), SLOT(get())); + connect(m_pDapCommandController, SIGNAL(onChangeLogModel()), SLOT(getNodeLogs())); connect(&DapChainNodeNetworkModel::getInstance(), SIGNAL(requestNodeNetwork()), this, SLOT(getNodeNetwork())); connect(&DapChainNodeNetworkModel::getInstance(), SIGNAL(requestNodeStatus(bool)), this, SLOT(setNodeStatus(bool))); @@ -60,6 +64,10 @@ void DapServiceController::init(DapServiceClient *apDapServiceClient) connect(m_pDapCommandController, &DapCommandController::sendHistory, &DapScreenHistoryModel::getInstance(), &DapScreenHistoryModel::receiveNewData); + connect(&DapConsoleModel::getInstance(), &DapConsoleModel::sendRequest, m_pDapCommandController, &DapCommandController::requestConsole); + connect(m_pDapCommandController, &DapCommandController::responseConsole, &DapConsoleModel::getInstance(), &DapConsoleModel::receiveResponse); + connect(m_pDapCommandController, &DapCommandController::sigCmdHistory, &DapConsoleModel::getInstance(), &DapConsoleModel::receiveCmdHistory); + connect(m_pDapCommandController, &DapCommandController::sendNetworkList, &DapSettingsNetworkModel::getInstance(), &DapSettingsNetworkModel::setNetworkList); connect(&DapSettingsNetworkModel::getInstance(), &DapSettingsNetworkModel::currentNetworkChanged, m_pDapCommandController, &DapCommandController::changeCurrentNetwork); } @@ -83,7 +91,7 @@ QString DapServiceController::getResult() void DapServiceController::getWallets() const { - qInfo() << QString("getNodeLogs()"); + qInfo() << QString("getWallets()"); m_pDapCommandController->getWallets(); } @@ -91,44 +99,26 @@ void DapServiceController::getWallets() const /// @param aNodeLogs List of node logs. void DapServiceController::processGetNodeLogs(const QStringList &aNodeLogs) { - if(aNodeLogs.count() <= 0) + if(aNodeLogs.isEmpty()) return; - int counter {0}; - QStringList list; + int xx = DapLogModel::getInstance().rowCount(); - for(int x{0}; x <= aNodeLogs.size(); ++x) + QRegularExpression re("(?<=])\\s"); + for (auto const & log : aNodeLogs) { - if(counter == 4) - { - DapLogMessage message; - message.setTimeStamp(list.at(0)); - message.setType(list.at(1)); - message.setFile(list.at(2)); - message.setMessage(list.at(3)); - DapLogModel::getInstance().append(message); - list.clear(); - counter = 0; - if(x != aNodeLogs.size()) - --x; - } - else if( x != aNodeLogs.size()) - { - list.append(aNodeLogs[x]); - ++counter; - } + const QStringList list = log.split(re); + DapLogMessage logMessage; + logMessage.setTimeStamp(list.at(0)); + logMessage.setType(list.at(1)); + logMessage.setFile(list.at(2)); + logMessage.setMessage(list.at(3)); + DapLogModel::getInstance().append(logMessage); } - emit logCompleted(); -} -void DapServiceController::get() -{ - clearLogModel(); - getNodeLogs(); + emit logCompleted(); } /// Get node logs. -/// @param aiTimeStamp Timestamp start reading logging. -/// @param aiRowCount Number of lines displayed. void DapServiceController::getNodeLogs() const { qInfo() << QString("getNodeLogs()"); @@ -174,6 +164,11 @@ void DapServiceController::getWalletInfo(const QString &asWalletName) m_pDapCommandController->getWalletInfo(asWalletName); } +void DapServiceController::getCmdHistory() +{ + m_pDapCommandController->getCmdHistory(); +} + void DapServiceController::getHistory() { m_pDapCommandController->getHistory(); diff --git a/CellFrameDashboardGUI/DapServiceController.h b/CellFrameDashboardGUI/DapServiceController.h index 4943d9cb4aa02d46541e42fccd4d7e144424cce8..e93daea8921b1a98705968e27bf6dd3a5e30ec9e 100755 --- a/CellFrameDashboardGUI/DapServiceController.h +++ b/CellFrameDashboardGUI/DapServiceController.h @@ -16,6 +16,7 @@ #include "DapChainNodeNetworkModel.h" #include "DapScreenHistoryModel.h" #include "DapSettingsNetworkModel.h" +#include "DapConsoleModel.h" class DapServiceController : public QObject { @@ -68,12 +69,13 @@ public: /// @param aiTimeStamp Timestamp start reading logging. /// @param aiRowCount Number of lines displayed. void getNodeLogs(int aiTimeStamp, int aiRowCount) const; - + /// Get wallets Q_INVOKABLE void getWallets() const; DapLogModel getLogModel() const; void setLogModel(const DapLogModel &dapLogModel); - + /// Add new wallet + /// @param wallet Q_INVOKABLE void addWallet(const QString& asWalletName); Q_INVOKABLE void removeWallet(int index, const QString& asWalletName); Q_INVOKABLE void sendToken(const QString &asSendWallet, const QString& asAddressReceiver, const QString& asToken, const QString& aAmount); @@ -82,6 +84,8 @@ public: void getWalletInfo(const QString& asWalletName); /// Request about new netowrk list void getNetworkList(); + /// Get history of commands + void getCmdHistory(); signals: /// The signal is emitted when the Brand company property changes. @@ -125,8 +129,6 @@ public slots: /// Change status of node /// @param it is true if a node is online void setNodeStatus(const bool aIsOnline); - /// - void get(); /// Get node logs. Q_INVOKABLE void getNodeLogs() const; diff --git a/CellFrameDashboardGUI/DapUiQmlScreenConsoleForm.ui.qml b/CellFrameDashboardGUI/DapUiQmlScreenConsoleForm.ui.qml new file mode 100644 index 0000000000000000000000000000000000000000..56fc11f427a7c396c7fc55d2d161c860ec6b8bc0 --- /dev/null +++ b/CellFrameDashboardGUI/DapUiQmlScreenConsoleForm.ui.qml @@ -0,0 +1,27 @@ +import QtQuick 2.13 +import QtQml 2.12 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 1.4 + +Page { + SplitView { + anchors.fill: parent + orientation: Qt.Horizontal + anchors.leftMargin: 30 * pt + handleDelegate: Item { } + + + DapUiQmlWidgetConsoleForm { + id: dapConsoleForm + Layout.fillWidth: true + Layout.topMargin: 30 * pt + Layout.rightMargin: 30 * pt + } + + DapUiQmlWidgetConsoleLastActionsForm { + id: lastActionsPanel + consoleData: dapConsoleForm.textAreaCmdHistory + } + } +} diff --git a/CellFrameDashboardGUI/DapUiQmlScreenDashboard.qml b/CellFrameDashboardGUI/DapUiQmlScreenDashboard.qml index ad42c4374c14bb08a9bc2920d007cd5d9a110925..9b79c70f1f71f66a496fa103bc1ae92758dcf7c9 100755 --- a/CellFrameDashboardGUI/DapUiQmlScreenDashboard.qml +++ b/CellFrameDashboardGUI/DapUiQmlScreenDashboard.qml @@ -51,6 +51,13 @@ Page { page: "DapUiQmlScreenHistory.qml" source: "qrc:/Resources/Icons/defaul_icon.png" } + + ListElement { + name: qsTr("Console") + page: "DapUiQmlScreenConsoleForm.qml" + source: "qrc:/Resources/Icons/defaul_icon.png" + } + ListElement { name: qsTr("About") page: "DapQmlScreenAbout.qml" diff --git a/CellFrameDashboardGUI/DapUiQmlScreenDialog.qml b/CellFrameDashboardGUI/DapUiQmlScreenDialog.qml index a7209ed492bbc7d1587fea850f6b8e945fc42fe6..7423cdc55b25e9133b9ba8b0a9573c86155f0473 100644 --- a/CellFrameDashboardGUI/DapUiQmlScreenDialog.qml +++ b/CellFrameDashboardGUI/DapUiQmlScreenDialog.qml @@ -58,5 +58,14 @@ Page { } } - DapUiQmlWidgetLastActions {} + DapUiQmlWidgetLastActions { + viewModel: dapHistoryModel + viewDelegate: DapUiQmlWidgetLastActionsDelegateForm {} + viewSection.property: "date" + viewSection.criteria: ViewSection.FullString + viewSection.delegate: DapUiQmlWidgetLastActionsSectionForm { + width: parent.width + height: 30 * pt + } + } } diff --git a/CellFrameDashboardGUI/DapUiQmlScreenMainWindowForm.ui.qml b/CellFrameDashboardGUI/DapUiQmlScreenMainWindowForm.ui.qml index f538161eee58356dc4ab14aafdb61b8811eebcef..20e633e36faec0231a30bd5cd848b90c815813ad 100644 --- a/CellFrameDashboardGUI/DapUiQmlScreenMainWindowForm.ui.qml +++ b/CellFrameDashboardGUI/DapUiQmlScreenMainWindowForm.ui.qml @@ -64,6 +64,11 @@ Page { page: "DapUiQmlScreenHistory.qml" source: "qrc:/Resources/Icons/defaul_icon.png" } + ListElement { + name: qsTr("Console") + page: "DapUiQmlScreenConsoleForm.ui.qml" + source: "qrc:/Resources/Icons/defaul_icon.png" + } ListElement { name: qsTr("About") page: "DapQmlScreenAbout.qml" diff --git a/CellFrameDashboardGUI/DapUiQmlWidgetConsole.qml b/CellFrameDashboardGUI/DapUiQmlWidgetConsole.qml index 51daf175e8ac5cc74566191555d1b610c6073aba..74752d1b4039e09d433a565101ac1e8a7c8fdf10 100644 --- a/CellFrameDashboardGUI/DapUiQmlWidgetConsole.qml +++ b/CellFrameDashboardGUI/DapUiQmlWidgetConsole.qml @@ -1,28 +1,100 @@ -import QtQuick 2.9 -import QtQuick.Controls 1.4 -import QtQuick.Controls 2.2 -import QtQuick.Window 2.0 -import QtQuick.Controls.Styles 1.3 -import QtQuick.Controls.Styles 1.4 -import Qt.labs.platform 1.0 -import CellFrameDashboard 1.0 - - -DapUiQmlWidgetConsoleForm { - id: dapQmlWidgetConsole - execute.onClicked: { - dapServiceController.executeCommand(command.text) - execute.enabled = false; +import QtQuick 2.13 +import QtQuick.Controls 2.5 +import QtQuick.Layouts 1.13 + + +Rectangle { + + property alias textAreaCmdHistory: txtCommand + property alias textAreaCmd: consoleCmd + + ColumnLayout { + anchors.fill: parent + + Flickable { + id: scrollCmdHistory + contentY: txtCommand.height - height + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + + TextArea.flickable: TextArea { + id: txtCommand + text: dapConsoleModel.getCmdHistory(); + selectByMouse: true + wrapMode: TextArea.WordWrap + + Keys.onPressed: { + switch(event.key) + { + case Qt.Key_Left: break; + case Qt.Key_Right: break; + case Qt.Key_Up: break; + case Qt.Key_Down: break; + default: event.accepted = + !(event.modifiers & Qt.ControlModifier) || (event.key === Qt.Key_X); break; + } + } + } + + ScrollBar.vertical: ScrollBar { } + ScrollBar.horizontal: ScrollBar { } + } + + RowLayout { + spacing: 0 + + Text { + id: promt + verticalAlignment: Qt.AlignVCenter + text: ">" + color: consoleCmd.color + font.family: consoleCmd.font.family + font.pixelSize: consoleCmd.font.pixelSize + } + + TextArea { + id: consoleCmd + + Layout.fillWidth: true + height: contentChildren.height + wrapMode: TextArea.Wrap + placeholderText: qsTr("Type here...") + selectByMouse: true + focus: true + + Keys.onUpPressed: { + consoleCmd.text = dapConsoleModel.getCommandUp(); + } + + Keys.onDownPressed: { + consoleCmd.text = dapConsoleModel.getCommandDown(); + } + + Keys.onEnterPressed: { + Keys.onReturnPressed(event); + } + + Keys.onReturnPressed: { + txtCommand.append("> " + consoleCmd.text); + if(consoleCmd.text === "") return; + dapConsoleModel.receiveRequest(consoleCmd.text); + consoleCmd.text = ""; + } + } + } } Connections { - target: dapServiceController - onResultChanged: { - command.clear() - result.text = dapServiceController.Result - execute.enabled = true + target: dapConsoleModel + onSendResponse: { + txtCommand.append(response); } - } + onCmdHistoryChanged: { + txtCommand.append(history); + } + } } + diff --git a/CellFrameDashboardGUI/DapUiQmlWidgetConsoleForm.ui.qml b/CellFrameDashboardGUI/DapUiQmlWidgetConsoleForm.ui.qml index 0fe42cea054435147c8235c83eb33e54944609e0..1b3ac691dd07cd3d8da0550e27978bac1292eacf 100644 --- a/CellFrameDashboardGUI/DapUiQmlWidgetConsoleForm.ui.qml +++ b/CellFrameDashboardGUI/DapUiQmlWidgetConsoleForm.ui.qml @@ -1,83 +1,12 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.1 - -Page { - id: dapUiQmlWidgetConsole - property alias result: result - property alias command: command - property alias execute: execute - - - Rectangle { - id: rectangle - y: 0 - width: 640 - height: 480 - color: "#ffffff" - anchors.left: parent.left - anchors.leftMargin: 0 - anchors.verticalCenter: parent.verticalCenter - border.width: 0 - - Button { - id: execute - x: 250 - y: 366 - text: qsTr("Execute") - anchors.horizontalCenterOffset: 0 - anchors.bottom: parent.bottom - anchors.bottomMargin: 74 - anchors.horizontalCenter: parent.horizontalCenter - } - - TextEdit { - id: command - x: 290 - y: 50 - width: 606 - height: 208 - anchors.horizontalCenterOffset: 4 - anchors.horizontalCenter: parent.horizontalCenter - font.pixelSize: 12 - } - - Label { - id: result - y: 422 - width: 606 - height: 50 - text: qsTr("") - anchors.left: parent.left - anchors.leftMargin: 21 - anchors.bottom: parent.bottom - anchors.bottomMargin: 8 - } - - Label { - id: commandText - x: 21 - y: 24 - width: 82 - height: 14 - text: qsTr("Command:") - anchors.left: parent.left - anchors.leftMargin: 21 - } - - Label { - id: resultText - x: 21 - y: 409 - text: qsTr("Result:") - } - } -} - - - - -/*##^## Designer { - D{i:0;autoSize:true;height:480;width:640} +import QtQuick 2.4 +import QtQuick.Controls 2.5 +import QtQuick.Layouts 1.13 + +DapUiQmlWidgetConsole { + textAreaCmdHistory.color: "#707070" + textAreaCmdHistory.font.family: "Roboto" + textAreaCmdHistory.font.pixelSize: 20 * pt + textAreaCmd.color: "#707070" + textAreaCmd.font.family: "Roboto" + textAreaCmd.font.pixelSize: 20 * pt } - ##^##*/ diff --git a/CellFrameDashboardGUI/DapUiQmlWidgetConsoleLastActionsDelegateForm.qml b/CellFrameDashboardGUI/DapUiQmlWidgetConsoleLastActionsDelegateForm.qml new file mode 100644 index 0000000000000000000000000000000000000000..9a54cf094185d62b1d7b50a43d80abf22dc1c110 --- /dev/null +++ b/CellFrameDashboardGUI/DapUiQmlWidgetConsoleLastActionsDelegateForm.qml @@ -0,0 +1,41 @@ +import QtQuick 2.0 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.13 + +Component { + ColumnLayout { + + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: 18 * pt + anchors.rightMargin: 18 * pt + + Rectangle { + height: 18 * pt + } + + Text { + id: textLastCmd + Layout.fillWidth: true + verticalAlignment: Qt.AlignVCenter + wrapMode: Text.Wrap + text: lastCommand + color: "#5F5F63" + font.family: "Roboto Regular" + font.pixelSize: 14 * pt + clip: true + + MouseArea { + anchors.fill: parent + onClicked: { + consoleData.append("> " + lastCommand); + dapConsoleModel.receiveRequest(lastCommand); + } + } + } + + Rectangle { + height: 18 * pt + } + } +} diff --git a/CellFrameDashboardGUI/DapUiQmlWidgetConsoleLastActionsForm.qml b/CellFrameDashboardGUI/DapUiQmlWidgetConsoleLastActionsForm.qml new file mode 100644 index 0000000000000000000000000000000000000000..e96f0f39cca36d0f9ba446d5e68f2074b75d1a15 --- /dev/null +++ b/CellFrameDashboardGUI/DapUiQmlWidgetConsoleLastActionsForm.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.13 + +DapUiQmlWidgetLastActions { + property TextArea consoleData + + id: lastActionsPanel + viewModel: dapConsoleModel + viewDelegate: DapUiQmlWidgetConsoleLastActionsDelegateForm { } +} diff --git a/CellFrameDashboardGUI/DapUiQmlWidgetLastActions.qml b/CellFrameDashboardGUI/DapUiQmlWidgetLastActions.qml index 6dc8088d818ce6d946eeb0c55172db663981d65b..43b5284e3fdd437e19645472fca63bc05432f8e9 100644 --- a/CellFrameDashboardGUI/DapUiQmlWidgetLastActions.qml +++ b/CellFrameDashboardGUI/DapUiQmlWidgetLastActions.qml @@ -7,6 +7,10 @@ import DapTransactionHistory 1.0 DapUiQmlWidgetLastActionsForm { + property alias viewModel: dapListView.model + property alias viewDelegate: dapListView.delegate + property alias viewSection: dapListView.section + MouseArea { id: mainMouseArea anchors.fill: parent @@ -35,12 +39,6 @@ DapUiQmlWidgetLastActionsForm { anchors.bottom: parent.bottom clip: true - model: dapHistoryModel - delegate: DapUiQmlWidgetLastActionsDelegateForm {} - section.property: "date" - section.criteria: ViewSection.FullString - section.delegate: DapUiQmlWidgetLastActionsSectionForm {} - property var contentPos: 0.0; onContentYChanged: { if(atYBeginning) buttonListScroll.state = "goUp"; diff --git a/CellFrameDashboardGUI/DapUiQmlWidgetLastActionsSectionForm.qml b/CellFrameDashboardGUI/DapUiQmlWidgetLastActionsSectionForm.qml index 2f57446cc5f0365f4aefd64d9538c37c21d1d724..a015babb205d8a140f241e1a11c204e522a42f9e 100644 --- a/CellFrameDashboardGUI/DapUiQmlWidgetLastActionsSectionForm.qml +++ b/CellFrameDashboardGUI/DapUiQmlWidgetLastActionsSectionForm.qml @@ -3,21 +3,19 @@ import QtQml 2.12 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.12 -Component { - Rectangle { - width: dapListView.width - height: 30 * pt - color: "#C2CAD1" +Rectangle { +// width: dapListView.width +// height: 30 * pt + color: "#C2CAD1" - Text { - anchors.fill: parent - verticalAlignment: Qt.AlignVCenter - horizontalAlignment: Qt.AlignLeft - color: "#797979" - text: section - font.family: "Roboto" - font.pixelSize: 12 * pt - leftPadding: 16 * pt - } + Text { + anchors.fill: parent + verticalAlignment: Qt.AlignVCenter + horizontalAlignment: Qt.AlignLeft + color: "#797979" + text: section + font.family: "Roboto" + font.pixelSize: 12 * pt + leftPadding: 16 * pt } } diff --git a/CellFrameDashboardGUI/main.cpp b/CellFrameDashboardGUI/main.cpp index b53c3f7c9aaf6a37bbc175ff133bdf572314b31e..741860dc262f5f38270c7c020b51e4f00c0a3951 100755 --- a/CellFrameDashboardGUI/main.cpp +++ b/CellFrameDashboardGUI/main.cpp @@ -24,7 +24,7 @@ #include "DapChainNodeNetworkExplorer.h" #include "DapScreenHistoryFilterModel.h" #include "DapSettingsNetworkModel.h" - +#include "DapConsoleModel.h" #include <QRegExp> @@ -54,6 +54,7 @@ int main(int argc, char *argv[]) dapServiceClient.init(); controller.getWallets(); controller.getHistory(); + controller.getCmdHistory(); controller.getNetworkList(); DapScreenHistoryFilterModel::getInstance() @@ -65,7 +66,7 @@ int main(int argc, char *argv[]) qmlRegisterType<DapChainNodeNetworkExplorer>("NodeNetworkExplorer", 1, 0, "DapUiQmlWidgetNodeNetwork"); qmlRegisterSingletonType<DapUiQmlWidgetModel>("CellFrameDashboard", 1, 0, "DapUiQmlWidgetModel", DapUiQmlWidgetModel::singletonProvider); qmlRegisterType<DapScreenHistoryModel>("DapTransactionHistory", 1, 0, "DapTransactionModel"); - + QQmlApplicationEngine engine; /// TODO: this method for getting DPI screen can be useful in the future // qreal dpi = QGuiApplication::primaryScreen()->physicalDotsPerInch(); @@ -74,6 +75,7 @@ int main(int argc, char *argv[]) engine.rootContext()->setContextProperty("dapLogModel", &DapLogModel::getInstance()); engine.rootContext()->setContextProperty("dapChainWalletsModel", &DapChainWalletsModel::getInstance()); engine.rootContext()->setContextProperty("dapNodeNetworkModel", &DapChainNodeNetworkModel::getInstance()); + engine.rootContext()->setContextProperty("dapConsoleModel", &DapConsoleModel::getInstance()); engine.rootContext()->setContextProperty("dapHistoryModel", &DapScreenHistoryFilterModel::getInstance()); engine.rootContext()->setContextProperty("dapSettingsNetworkModel", &DapSettingsNetworkModel::getInstance()); engine.rootContext()->setContextProperty("pt", 1.3); diff --git a/CellFrameDashboardGUI/qml.qrc b/CellFrameDashboardGUI/qml.qrc index 5f7955c323df1b6fb80dfcad029cdae2d96427c7..b642898dbc665a63e3795f9f784ad16916824bf6 100755 --- a/CellFrameDashboardGUI/qml.qrc +++ b/CellFrameDashboardGUI/qml.qrc @@ -22,8 +22,6 @@ <file>DapUiQmlWidgetChainNodeLogsForm.ui.qml</file> <file>DapUiQmlScreenDialogSendToken.qml</file> <file>DapUiQmlScreenDialogRemoveWallet.qml</file> - <file>DapUiQmlWidgetConsoleForm.ui.qml</file> - <file>DapUiQmlWidgetConsole.qml</file> <file>DapUiQmlWidgetNodeNetworkExplorer.qml</file> <file>Resources/Icons/defaul_icon.png</file> <file>DapUiQmlScreenExchangeForm.ui.qml</file> @@ -58,6 +56,11 @@ <file>DapUiQmlWidgetLastActions.qml</file> <file>DapUiQmlWidgetLastActionsForm.ui.qml</file> <file>DapUiQmlScreenHistoryForm.ui.qml</file> + <file>DapUiQmlScreenConsoleForm.ui.qml</file> + <file>DapUiQmlWidgetConsoleLastActionsForm.qml</file> + <file>DapUiQmlWidgetConsoleLastActionsDelegateForm.qml</file> + <file>DapUiQmlWidgetConsole.qml</file> + <file>DapUiQmlWidgetConsoleForm.ui.qml</file> <file>DapUiQmlWidgetSettingsNetwork.qml</file> <file>DapUiQmlWidgetSettingsNetworkForm.ui.qml</file> <file>DapUiQmlScreenSettings.qml</file> diff --git a/CellFrameDashboardService/CellFrameDashboardService.pro b/CellFrameDashboardService/CellFrameDashboardService.pro index 3921104f0755e44850b99f5d7c4a95896ec5ecbb..64bcd5e54e9a3f599d365192faf0eeff8c3a93c5 100755 --- a/CellFrameDashboardService/CellFrameDashboardService.pro +++ b/CellFrameDashboardService/CellFrameDashboardService.pro @@ -22,11 +22,13 @@ win32 { VERSION = $${VER_MAJ}.$${VER_MIN}.$$VER_PAT DEFINES += CLI_PATH=\\\"./cellframe-node-cli.exe\\\" DEFINES += LOG_FILE=\\\"./opt/cellframe-node/var/log/cellframe-node_logs.txt\\\" + DEFINES += CMD_LOG=\\\"./opt/cellframe-dashboard/data/cellframe-cmd_log.txt\\\" } else { VERSION = $$VER_MAJ\.$$VER_MIN\-$$VER_PAT DEFINES += CLI_PATH=\\\"/opt/cellframe-node/bin/cellframe-node-cli\\\" DEFINES += LOG_FILE=\\\"/opt/cellframe-node/var/log/cellframe-node_logs.txt\\\" + DEFINES += CMD_LOG=\\\"/opt/cellframe-dashboard/data/cellframe-cmd_log.txt\\\" } # The following define makes your compiler emit warnings if you use @@ -49,7 +51,8 @@ SOURCES += \ $$PWD/DapChainNodeCache.cpp \ $$PWD/DapChainWalletHandler.cpp \ $$PWD/DapChainLogHandler.cpp \ - DapChainNetworkHandler.cpp + $$PWD/DapChainNetworkHandler.cpp \ + $$PWD/DapChainConsoleHandler.cpp HEADERS += \ $$PWD/DapChainDashboardService.h \ @@ -59,7 +62,8 @@ HEADERS += \ $$PWD/DapChainNodeNetworkHandler.h \ $$PWD/DapChainWalletHandler.h \ $$PWD/DapChainLogHandler.h \ - DapChainNetworkHandler.h + $$PWD/DapChainNetworkHandler.h \ + $$PWD/DapChainConsoleHandler.h include (../libdap/libdap.pri) include (../libdap-crypto/libdap-crypto.pri) diff --git a/CellFrameDashboardService/DapChainConsoleHandler.cpp b/CellFrameDashboardService/DapChainConsoleHandler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c65b2aa344b19fcab50f070a6f912d79ba3228e2 --- /dev/null +++ b/CellFrameDashboardService/DapChainConsoleHandler.cpp @@ -0,0 +1,48 @@ +#include "DapChainConsoleHandler.h" + +#define MAX_COUNT_CMD 50 + +DapChainConsoleHandler::DapChainConsoleHandler(QObject *parent) : QObject(parent) +{ + QDir().mkpath(QFileInfo(CMD_LOG).path()); + m_File = new QFile(CMD_LOG, this); + m_File->open(QIODevice::Append | QIODevice::ReadWrite); +} + +QString DapChainConsoleHandler::getHistory() const +{ + if(!m_File->isOpen()) return QString(); + + quint8 countCmd = 0; + while (m_File->pos() > 0) + { + QByteArray symbol = m_File->read(1); + if(symbol == ">") ++countCmd; + m_File->seek(m_File->pos() - 2); + if(countCmd == MAX_COUNT_CMD) break; + } + + QByteArray lastCmd = m_File->read(m_File->size() - m_File->pos()); + + return QString::fromStdString(lastCmd.toStdString()); +} + +QString DapChainConsoleHandler::getResult(const QString& aQuery) const +{ + QProcess process; + process.start(QString(CLI_PATH) + " " + aQuery); + process.waitForFinished(-1); + + QByteArray returnSymbol = "\n"; + +#ifdef Q_OS_WIN + returnSymbol.prepend("\r"); +#endif + + QByteArray result = process.readAll(); + m_File->write("> " + aQuery.toUtf8() + returnSymbol); + m_File->write(result + returnSymbol); + m_File->flush(); + + return QString::fromStdString(result.toStdString()); +} diff --git a/CellFrameDashboardService/DapChainConsoleHandler.h b/CellFrameDashboardService/DapChainConsoleHandler.h new file mode 100644 index 0000000000000000000000000000000000000000..faaced1aad3a66ad9277a9555b6b44b2efd783f7 --- /dev/null +++ b/CellFrameDashboardService/DapChainConsoleHandler.h @@ -0,0 +1,29 @@ +#ifndef DAPCHAINCONSOLEHANDLER_H +#define DAPCHAINCONSOLEHANDLER_H + +#include <QObject> +#include <QProcess> +#include <QDebug> +#include <QFile> +#include <QDir> + +class DapChainConsoleHandler : public QObject +{ + Q_OBJECT + +private: + QFile * m_File; + +public: + explicit DapChainConsoleHandler(QObject *parent = nullptr); + + /// Get history of commands + /// @return history + QString getHistory() const; + /// Get result of command + /// @param command + /// @return command result + QString getResult(const QString& aQuery) const; +}; + +#endif // DAPCHAINCONSOLEHANDLER_H diff --git a/CellFrameDashboardService/DapChainDashboardService.cpp b/CellFrameDashboardService/DapChainDashboardService.cpp index 7e680b60d85eceb3b002efad468a89285f3ce64e..d12ef4577ce76de2d464f73a737a45dc5889cee7 100755 --- a/CellFrameDashboardService/DapChainDashboardService.cpp +++ b/CellFrameDashboardService/DapChainDashboardService.cpp @@ -4,7 +4,6 @@ DapChainDashboardService::DapChainDashboardService() : DapRpcService(nullptr) { // Log reader m_pDapChainLogHandler = new DapChainLogHandler(this); - connect(m_pDapChainLogHandler, SIGNAL(onUpdateModel()), SLOT(clearLogModel())); connect(m_pDapChainLogHandler, SIGNAL(onChangedLog()), SLOT(changedLogModel())); m_pDapChainWalletHandler = new DapChainWalletHandler(this); connect(this, &DapChainDashboardService::onNewClientConnected, [=] { @@ -18,6 +17,9 @@ DapChainDashboardService::DapChainDashboardService() : DapRpcService(nullptr) QObject::connect(m_pDapChainHistoryHandler, &DapChainHistoryHandler::changeHistory, this, &DapChainDashboardService::doSendNewHistory); m_pDapChainNetworkHandler = new DapChainNetworkHandler(this); + + m_pDapChainConsoleHandler = new DapChainConsoleHandler(this); + } bool DapChainDashboardService::start() @@ -90,6 +92,16 @@ QVariant DapChainDashboardService::getHistory() const return m_pDapChainHistoryHandler->getHistory(); } +QString DapChainDashboardService::getQueryResult(const QString& aQuery) const +{ + return m_pDapChainConsoleHandler->getResult(aQuery); +} + +QString DapChainDashboardService::getCmdHistory() const +{ + return m_pDapChainConsoleHandler->getHistory(); +} + QStringList DapChainDashboardService::getNetworkList() const { return m_pDapChainNetworkHandler->getNetworkList(); @@ -121,13 +133,6 @@ QString DapChainDashboardService::sendToken(const QString &asWalletName, const Q return m_pDapChainWalletHandler->sendToken(asWalletName, asReceiverAddr, asToken, asAmount); } -void DapChainDashboardService::clearLogModel() -{ - qDebug() << "clearLogModel()"; - QJsonArray arguments; - m_pServer->notifyConnectedClients("RPCClient.clearLogModel", arguments); -} - void DapChainDashboardService::changedLogModel() { qDebug() << "changedLogModel()"; diff --git a/CellFrameDashboardService/DapChainDashboardService.h b/CellFrameDashboardService/DapChainDashboardService.h index b7ae8b64c437a380ab16d6a648de76362f1566af..85144bd63138023d52fd08dda1284ff8c46ae51e 100755 --- a/CellFrameDashboardService/DapChainDashboardService.h +++ b/CellFrameDashboardService/DapChainDashboardService.h @@ -28,6 +28,7 @@ #include "DapChainNodeNetworkHandler.h" #include "DapChainHistoryHandler.h" #include "DapChainNetworkHandler.h" +#include "DapChainConsoleHandler.h" #include <QLocalServer> typedef class DapRpcLocalServer DapUiService; @@ -49,6 +50,8 @@ class DapChainDashboardService : public DapRpcService DapChainNodeNetworkHandler * m_pDapChainNodeHandler {nullptr}; /// Recipient history of transactions DapChainHistoryHandler* m_pDapChainHistoryHandler {nullptr}; + /// Recipient history of commands + DapChainConsoleHandler* m_pDapChainConsoleHandler {nullptr}; DapChainNetworkHandler* m_pDapChainNetworkHandler {nullptr}; @@ -63,8 +66,6 @@ signals: void onNewClientConnected(); public slots: - void clearLogModel(); - void changedLogModel(); /// Activate the main client window by double-clicking the application icon in the system tray. /// @param reason Type of action on the icon in the system tray. @@ -111,6 +112,13 @@ public slots: /// Change current network /// @param name of network whcih was selected void changeCurrentNetwork(const QString& aNetwork); + /// Get result for command + /// @param command + /// @return result + QString getQueryResult(const QString& aQuery) const; + /// Get history of commands + /// @return history of last 50 commands + QString getCmdHistory() const; private slots: void doRequestWallets(); diff --git a/CellFrameDashboardService/DapChainLogHandler.cpp b/CellFrameDashboardService/DapChainLogHandler.cpp index 809610d45a0a6ee894541db4ea0b857083f7c89d..6f5cbaae7c0d79df63c7f92030e3386124052fde 100755 --- a/CellFrameDashboardService/DapChainLogHandler.cpp +++ b/CellFrameDashboardService/DapChainLogHandler.cpp @@ -1,5 +1,7 @@ #include "DapChainLogHandler.h" +#include <QRegularExpression> + DapChainLogHandler::DapChainLogHandler(QObject *parent) : QObject(parent) { m_fileSystemWatcher.addPath(LOG_FILE); @@ -13,31 +15,31 @@ DapChainLogHandler::DapChainLogHandler(QObject *parent) : QObject(parent) QStringList DapChainLogHandler::request() { - /// TODO: The application doesn't work because of it. It needs to be changed -// QStringList m_listLogs; -// QFile file(LOG_FILE); -// if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) -// { -// emit onUpdateModel(); -// } -// else -// { -// QTextStream in(&file); -//// QRegExp rx("(\\[|\\]|\\s)([\\w*]{1,1}[\\w\\s\\W]+)([\\n]|\\])" ); !!! DO NOT DELETE!!! -// QRegExp rx("(\\[|\\]|\\s)([\\w*]{1,1}[\\w\\s\\W]+)(\\]|$)" ); -// rx.setMinimal(true); - - -// while (!in.atEnd()) { -// QString line = in.readLine(); -// int pos{0}; -// while((pos = rx.indexIn(line, pos)) != -1) -// { -// m_listLogs.append(rx.cap(2)); -// pos += rx.matchedLength(); -// } -// } -// } -// return m_listLogs; - return QStringList(); + QFile file(LOG_FILE); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + qWarning() << "Failed to open file " << file.fileName(); + return QStringList(); + } + else + { + QTextStream in(&file); + in.seek(m_currentCaretPosition); + const QRegularExpression re("(\\[\\d\\d\\/\\d\\d\\/\\d\\d\\-\\d\\d\\:\\d\\d\\:\\d\\d])\\s(\\[\\w+\\])\\s(\\[\\w+\\])(.+)"); + + QStringList listLogs; + while (!in.atEnd()) { + const QString line = in.readLine(); + const auto match = re.match(line); + if(!match.hasMatch()) + continue; + + const QString matchedLog = match.captured(); + listLogs.append(matchedLog); + m_currentCaretPosition += matchedLog.length(); + } + + return listLogs; + + } } diff --git a/CellFrameDashboardService/DapChainLogHandler.h b/CellFrameDashboardService/DapChainLogHandler.h index 45453ca252d413eb090bc44c37be48be175cd68a..8f0fb75731bc36277a82051eff0bc258aed8760f 100644 --- a/CellFrameDashboardService/DapChainLogHandler.h +++ b/CellFrameDashboardService/DapChainLogHandler.h @@ -17,7 +17,8 @@ class DapChainLogHandler : public QObject /// Log file change watcher. QFileSystemWatcher m_fileSystemWatcher; - + /// Current caret position in log file + qint64 m_currentCaretPosition{0}; public: explicit DapChainLogHandler(QObject *parent = nullptr); diff --git a/KelvinDashboardGUI/DapConsoleModel.cpp b/KelvinDashboardGUI/DapConsoleModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..01d0ad78a6a60f5ca25964bc7d4342da5b9ce6dc --- /dev/null +++ b/KelvinDashboardGUI/DapConsoleModel.cpp @@ -0,0 +1,101 @@ +#include "DapConsoleModel.h" + +DapConsoleModel::DapConsoleModel(QObject *parent) : + QAbstractListModel(parent) +{ + +} + +DapConsoleModel& DapConsoleModel::getInstance() +{ + static DapConsoleModel instance; + return instance; +} + +void DapConsoleModel::receiveResponse(const QString& aResponse) +{ + m_History.append(aResponse); + emit sendResponse(aResponse); +} + +int DapConsoleModel::rowCount(const QModelIndex& parent) const +{ + Q_UNUSED(parent) + + return m_CommandList.count(); +} + +QVariant DapConsoleModel::data(const QModelIndex& index, int role) const +{ + if (!index.isValid()) return QVariant(); + + if(role == LastCommand) + return m_CommandList.at(index.row()); + + return QVariant(); +} + +QHash<int, QByteArray> DapConsoleModel::roleNames() const +{ + QHash<int, QByteArray> roles; + roles[LastCommand] = "lastCommand"; + return roles; +} + +QString DapConsoleModel::getCommandUp() +{ + if(m_CommandList.isEmpty()) return QString(); + if(m_CommandIndex > m_CommandList.begin()) m_CommandIndex--; + return *m_CommandIndex; +} + +QString DapConsoleModel::getCommandDown() +{ + if(m_CommandList.isEmpty()) return QString(); + if(m_CommandIndex < m_CommandList.end() -1) m_CommandIndex++; + else return QString(); + return *m_CommandIndex; +} + +void DapConsoleModel::receiveRequest(const QString& aCommand) +{ + beginResetModel(); + if(!m_CommandList.contains(aCommand)) + m_CommandList.append(aCommand); + endResetModel(); + m_CommandIndex = m_CommandList.end(); + + QString returnSymbol = "\n"; + +#ifdef Q_OS_WIN + returnSymbol.prepend("\r"); +#endif + + m_History.append(returnSymbol + "> " + aCommand + returnSymbol); + emit sendRequest(aCommand); +} + +QString DapConsoleModel::getCmdHistory() +{ + return m_History; +} + +void DapConsoleModel::receiveCmdHistory(const QString& aHistory) +{ + m_History = aHistory; + QRegularExpression rx("^> (.+)$"); + rx.setPatternOptions(QRegularExpression::MultilineOption); + + QRegularExpressionMatchIterator i = rx.globalMatch(m_History); + + while (i.hasNext()) { + QRegularExpressionMatch match = i.next(); + QString cmd = match.captured(1).remove(QChar('\r'), Qt::CaseInsensitive); + if(!m_CommandList.contains(cmd)) + m_CommandList.append(cmd); + } + + if(!m_CommandList.isEmpty()) + m_CommandIndex = m_CommandList.end(); + emit cmdHistoryChanged(m_History); +} diff --git a/KelvinDashboardGUI/DapConsoleModel.h b/KelvinDashboardGUI/DapConsoleModel.h new file mode 100644 index 0000000000000000000000000000000000000000..00bd228e4d905260b56eb8f6eb988f9fe8dc905d --- /dev/null +++ b/KelvinDashboardGUI/DapConsoleModel.h @@ -0,0 +1,69 @@ +#ifndef DAPUIQMLSCREENCONSOLEFORM_H +#define DAPUIQMLSCREENCONSOLEFORM_H + +#include <QDebug> +#include <QAbstractListModel> +#include <QStringList> +#include <QRegularExpression> + +/// Model for DAP console +class DapConsoleModel : public QAbstractListModel +{ + Q_OBJECT + +public: + /// Enumeration for model roles + enum ConsoleRole { + LastCommand = Qt::DisplayRole + }; + +private: + QString m_History; + QStringList m_CommandList; + QStringList::iterator m_CommandIndex; + +public: + explicit DapConsoleModel(QObject *parent = nullptr); + +public slots: + /// Receive response from service about command + /// @param result + void receiveResponse(const QString& aResponse); + /// Override methods of abstract model + int rowCount(const QModelIndex& parent) const override; + QVariant data(const QModelIndex& index, int role) const override; + QHash<int, QByteArray> roleNames() const override; + + /// Getting instanse of this class + /// @return instanse of this class + Q_INVOKABLE static DapConsoleModel& getInstance(); + /// Get the latest commands + /// @return the latest commands + Q_INVOKABLE QString getCommandUp(); + /// Get the earliest commands + /// @return the earliest commands. If it is last command in the list + /// it returns QString() + Q_INVOKABLE QString getCommandDown(); + /// Receive command requst for service + /// @param command request + Q_INVOKABLE void receiveRequest(const QString& aCommand); + /// Get current history + /// @return history of commands + Q_INVOKABLE QString getCmdHistory(); + /// Receive new history of commands + /// @param last 50 commands + void receiveCmdHistory(const QString& aHistory); + +signals: + /// Signal to send request to the service + /// @param command + void sendRequest(QString command); + /// Signal for getting response from service + /// @param result of command + void sendResponse(QString response); + /// Signal for view about changing history + /// @param last 50 commands + void cmdHistoryChanged(QString history); +}; + +#endif // DAPUIQMLSCREENCONSOLEFORM_H diff --git a/KelvinDashboardGUI/DapUiQmlScreenConsoleForm.ui.qml b/KelvinDashboardGUI/DapUiQmlScreenConsoleForm.ui.qml new file mode 100644 index 0000000000000000000000000000000000000000..86238fb7694a7203711deb25b686ddb78d598ddd --- /dev/null +++ b/KelvinDashboardGUI/DapUiQmlScreenConsoleForm.ui.qml @@ -0,0 +1,22 @@ +import QtQuick 2.13 +import QtQml 2.12 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.12 + +Page { + + DapUiQmlWidgetConsoleForm { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: lastActionsPanel.left + + anchors.topMargin: 30 * pt + anchors.leftMargin: 30 * pt + anchors.rightMargin: 30 * pt + } + + DapUiQmlWidgetConsoleLastActionsForm { + id: lastActionsPanel + } +} diff --git a/KelvinDashboardGUI/DapUiQmlWidgetConsoleLastActionsDelegateForm.qml b/KelvinDashboardGUI/DapUiQmlWidgetConsoleLastActionsDelegateForm.qml new file mode 100644 index 0000000000000000000000000000000000000000..3092bc5c15cf97d79817c358a3416c13bcc44a73 --- /dev/null +++ b/KelvinDashboardGUI/DapUiQmlWidgetConsoleLastActionsDelegateForm.qml @@ -0,0 +1,31 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.13 + +Component { + ColumnLayout { + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: 18 * pt + anchors.rightMargin: 18 * pt + + Rectangle { + height: 18 * pt + } + + Text { + id: textLastCmd + Layout.fillWidth: true + verticalAlignment: Qt.AlignVCenter + wrapMode: Text.Wrap + text: lastCommand + color: "#5F5F63" + font.family: "Roboto Regular" + font.pixelSize: 14 * pt + clip: true + } + + Rectangle { + height: 18 * pt + } + } +} diff --git a/KelvinDashboardGUI/DapUiQmlWidgetConsoleLastActionsForm.qml b/KelvinDashboardGUI/DapUiQmlWidgetConsoleLastActionsForm.qml new file mode 100644 index 0000000000000000000000000000000000000000..d2ffab08835e00f5a6f2166fe15ace5d79e72924 --- /dev/null +++ b/KelvinDashboardGUI/DapUiQmlWidgetConsoleLastActionsForm.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.13 + +DapUiQmlWidgetLastActions { + id: lastActionsPanel + viewModel: dapConsoleModel + viewDelegate: DapUiQmlWidgetConsoleLastActionsDelegateForm {} +} diff --git a/KelvinDashboardService/DapChainConsoleHandler.cpp b/KelvinDashboardService/DapChainConsoleHandler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c13b20ac7eda6d00de44bdeec7eb5c192845734c --- /dev/null +++ b/KelvinDashboardService/DapChainConsoleHandler.cpp @@ -0,0 +1,47 @@ +#include "DapChainConsoleHandler.h" + +#define MAX_COUNT_CMD 50 + +DapChainConsoleHandler::DapChainConsoleHandler(QObject *parent) : QObject(parent) +{ + m_File = new QFile("cmd_log.txt", this); + m_File->open(QIODevice::Append | QIODevice::ReadWrite); +} + +QString DapChainConsoleHandler::getHistory() const +{ + if(!m_File->isOpen()) return QString(); + + quint8 countCmd = 0; + while (m_File->pos() > 0) + { + QByteArray symbol = m_File->read(1); + if(symbol == ">") ++countCmd; + m_File->seek(m_File->pos() - 2); + if(countCmd == MAX_COUNT_CMD) break; + } + + QByteArray lastCmd = m_File->read(m_File->size() - m_File->pos()); + + return QString::fromStdString(lastCmd.toStdString()); +} + +QString DapChainConsoleHandler::getResult(const QString& aQuery) const +{ + QProcess process; + process.start(QString(CLI_PATH) + " " + aQuery); + process.waitForFinished(-1); + + QByteArray returnSymbol = "\n"; + +#ifdef Q_OS_WIN + returnSymbol.prepend("\r"); +#endif + + QByteArray result = process.readAll(); + m_File->write("> " + aQuery.toUtf8() + returnSymbol); + m_File->write(result + returnSymbol); + m_File->flush(); + + return QString::fromStdString(result.toStdString()); +} diff --git a/KelvinDashboardService/DapChainConsoleHandler.h b/KelvinDashboardService/DapChainConsoleHandler.h new file mode 100644 index 0000000000000000000000000000000000000000..907c47e6b9a62b15c312a0abdef0900c76f32df3 --- /dev/null +++ b/KelvinDashboardService/DapChainConsoleHandler.h @@ -0,0 +1,28 @@ +#ifndef DAPCHAINCONSOLEHANDLER_H +#define DAPCHAINCONSOLEHANDLER_H + +#include <QObject> +#include <QProcess> +#include <QDebug> +#include <QFile> + +class DapChainConsoleHandler : public QObject +{ + Q_OBJECT + +private: + QFile * m_File; + +public: + explicit DapChainConsoleHandler(QObject *parent = nullptr); + + /// Get history of commands + /// @return history + QString getHistory() const; + /// Get result of command + /// @param command + /// @return command result + QString getResult(const QString& aQuery) const; +}; + +#endif // DAPCHAINCONSOLEHANDLER_H