Skip to content
Snippets Groups Projects
Commit 7e640165 authored by Hoop77's avatar Hoop77
Browse files

Message gui

parent 7d0f88d6
No related merge requests found
Showing
with 884 additions and 183 deletions
......@@ -30,18 +30,22 @@ public:
using OnMessageProcessedCallback = std::function<void(const Message & message)>;
using OnRequestFinishedCallback = std::function<void(const networking::error::ErrorCode & error)>;
static constexpr std::size_t MAX_MESSAGE_SIZE{1024};
static Ptr create(networking::Networking & net, std::uint16_t port, std::size_t maxBufferSize=1024)
{ return std::make_shared<Client>(PrivateTag{}, net, port, maxBufferSize); }
static Ptr create(networking::Networking & net, std::uint16_t port)
{ return std::make_shared<Client>(PrivateTag{}, net, port); }
Client(PrivateTag, networking::Networking & net, std::uint16_t port);
Client(PrivateTag, networking::Networking & net, std::uint16_t port, std::size_t maxBufferSize);
void requestMessages(const std::string & host,
const networking::time::Duration & timeout,
const Client::OnMessageProcessedCallback & onMessageProcessedCallback,
const Client::OnRequestFinishedCallback & onRequestFinishedCallback =
[](const auto & error) {});
const OnMessageProcessedCallback & onMessageProcessedCallback,
const OnRequestFinishedCallback & onRequestFinishedCallback = [](const auto & error) {});
void requestMessagesPeriodically(const std::string & host,
const networking::time::Duration & requestInterval,
const networking::time::Duration & retryInterval,
const OnMessageProcessedCallback & onMessageProcessedCallback,
const OnRequestFinishedCallback & onRequestFinishedCallback =
[](const auto & error) {});
void stop();
......@@ -65,10 +69,47 @@ private:
OnRequestFinishedCallback onRequestFinishedCallback;
};
struct PeriodicAsyncState
{
using Ptr = std::shared_ptr<PeriodicAsyncState>;
PeriodicAsyncState(Client::Ptr self,
const std::string & host,
const networking::time::Duration & requestInterval,
const networking::time::Duration & retryInterval,
const OnMessageProcessedCallback & onMessageProcessedCallback,
const OnRequestFinishedCallback & onRequestFinishedCallback)
: lock(*self)
, self(self)
, host(host)
, requestInterval(requestInterval)
, retryInterval(retryInterval)
, onMessageProcessedCallback(onMessageProcessedCallback)
, onRequestFinishedCallback(onRequestFinishedCallback)
{}
networking::BusyLock lock;
Client::Ptr self;
std::string host;
networking::time::Duration requestInterval;
networking::time::Duration retryInterval;
OnMessageProcessedCallback onMessageProcessedCallback;
OnRequestFinishedCallback onRequestFinishedCallback;
};
networking::Networking & net;
std::uint16_t port;
ServiceClient::Ptr client;
Parser parser;
networking::time::Timer::Ptr timer;
std::atomic<bool> requesting{false};
void processResponse(const std::string & response,
const OnMessageProcessedCallback & onMessageProcessedCallback);
void scheduleNextRequest(PeriodicAsyncState::Ptr state, const networking::time::Duration & waitTime);
void nextRequest(PeriodicAsyncState::Ptr state);
};
}
......
......@@ -8,10 +8,11 @@
namespace message
{
Client::Client(Client::PrivateTag, networking::Networking & net, std::uint16_t port)
Client::Client(Client::PrivateTag, networking::Networking & net, std::uint16_t port, std::size_t maxBufferSize)
: net(net), port(port)
{
client = ServiceClient::create(net, MAX_MESSAGE_SIZE);
client = ServiceClient::create(net, maxBufferSize);
timer = networking::time::Timer::create(net);
}
void Client::requestMessages(const std::string & host,
......@@ -25,30 +26,75 @@ void Client::requestMessages(const std::string & host,
std::string emptyRequest;
client->asyncCall(
emptyRequest, host, port, timeout,
[state](const auto & error, auto & responseMessage)
[state](const auto & error, const auto & responseMessage)
{
if (error)
{
state->onRequestFinishedCallback(error);
return;
}
if (!responseMessage.empty())
{
auto & parser = state->self->parser;
parser << responseMessage;
Message message;
while (parser >> message)
state->onMessageProcessedCallback(message);
}
state->self->processResponse(responseMessage, state->onMessageProcessedCallback);
state->onRequestFinishedCallback(error);
});
}
void Client::requestMessagesPeriodically(const std::string & host,
const networking::time::Duration & requestInterval,
const networking::time::Duration & retryInterval,
const OnMessageProcessedCallback & onMessageProcessedCallback,
const OnRequestFinishedCallback & onRequestFinishedCallback)
{
auto self = shared_from_this();
auto state = std::make_shared<PeriodicAsyncState>(
self, host, requestInterval, retryInterval, onMessageProcessedCallback, onRequestFinishedCallback);
requesting = true;
nextRequest(std::move(state));
}
void Client::stop()
{
client->stop();
timer->stop();
requesting = false;
}
void Client::processResponse(const std::string & response,
const OnMessageProcessedCallback & onMessageProcessedCallback)
{
if (!response.empty())
{
parser << response;
Message message;
while (parser >> message)
onMessageProcessedCallback(message);
}
}
void Client::nextRequest(PeriodicAsyncState::Ptr state)
{
using namespace std::chrono_literals;
if (!requesting)
return;
std::string emptyRequest;
net.waitWhileBusy(*(state->self->client));
client->asyncCall(
emptyRequest, state->host, state->self->port, state->retryInterval,
[state](const auto & error, const auto & responseMessage)
{
auto & self = state->self;
if (error)
{
state->onRequestFinishedCallback(error);
self->net.callLater([state] { state->self->nextRequest(state); });
return;
}
self->processResponse(responseMessage, state->onMessageProcessedCallback);
state->onRequestFinishedCallback(error);
self->timer->startTimeout(
state->requestInterval, [state] { state->self->nextRequest(state); });
});
}
}
......
......@@ -41,38 +41,16 @@ void fromLocal()
while (running);
}
void requestNextMessages(networking::Networking & net,
networking::time::Timer::Ptr timer,
message::Client::Ptr client,
const networking::time::Duration & delay)
{
using namespace std::chrono_literals;
timer->startTimeout(delay, [&net, timer, client]
{
net.waitWhileBusy(*client);
client->requestMessages(
"127.0.0.1", 10s,
[](const auto & message) { printMessage(message); },
[&net, timer, client](const auto & error)
{
if (error)
{
std::cerr << "Could not connect to car!\n";
requestNextMessages(net, timer, client, 3s);
}
else requestNextMessages(net, timer, client, 10ms);
});
});
}
void fromCar()
{
using namespace message;
using namespace std::chrono_literals;
networking::Networking net;
auto client = Client::create(net, 10207);
auto timer = networking::time::Timer::create(net);
requestNextMessages(net, timer, client, 10ms);
client->requestMessagesPeriodically(
"127.0.0.1", 10ms, 3s,
[](const auto & message) { printMessage(message); },
[](const auto & error) { if (error) std::cerr << "Could not connect to car!\n"; });
while (1);
}
......
.vscode/
build-PCGui-Desktop_Qt_5_7_1_GCC_64bit-Default/
CMakeLists.txt.*
\ No newline at end of file
CMakeLists.txt.*
cmake-build-debug/
\ No newline at end of file
......@@ -2,12 +2,10 @@ cmake_minimum_required(VERSION 3.5.1)
project(PCGui LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt5 COMPONENTS Core Quick REQUIRED)
......@@ -20,17 +18,38 @@ find_package(Boost REQUIRED COMPONENTS regex system)
find_package(NetworkingLib REQUIRED)
find_package(PlatoonProtocolLib REQUIRED)
find_package(PC2CarLib REQUIRED)
find_package(MessageLib REQUIRED)
set(LIBS
Qt5::Core Qt5::Quick
NetworkingLib
PlatoonProtocolLib
PC2CarLib
MessageLib)
set(INCLUDE_DIRS
${PC2CarLib_INCLUDE_DIRS}
${MessageLib_INCLUDE_DIRS})
set(SOURCE_FILES
include/Logger.h
src/Logger.cpp
src/main.cpp
qml.qrc)
add_executable(${PROJECT_NAME} ${SOURCE_FILES})
target_link_libraries(${PROJECT_NAME}
Qt5::Core Qt5::Quick
NetworkingLib
PlatoonProtocolLib
PC2CarLib)
target_include_directories(${PROJECT_NAME} PUBLIC ${PC2CarLib_INCLUDE_DIRS})
include/QtQuickControlsApplication.h
qml.qrc)
add_executable(CommandGui ${SOURCE_FILES}
src/CommandGui.cpp)
add_executable(MessageGui ${SOURCE_FILES}
include/SortFilterProxyModel.h
include/MessageModel.h
include/MessageList.h
include/MessageProducer.h
src/MessageGui.cpp
src/MessageModel.cpp
src/MessageList.cpp
src/SortFilterProxyModel.cpp)
target_link_libraries(CommandGui ${LIBS})
target_link_libraries(MessageGui ${LIBS})
target_include_directories(CommandGui PUBLIC ${INCLUDE_DIRS})
target_include_directories(MessageGui PUBLIC ${INCLUDE_DIRS})
......@@ -5,5 +5,5 @@ Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
title: qsTr("Command Gui")
}
import QtQuick 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.2
import car.pcgui 1.0
ApplicationWindow {
id: window
visible: true
title: "Message Gui"
toolBar: ToolBar {
height: 180
Label {
id: moduleLabel
text: "Module: "
anchors.left: parent.left
anchors.leftMargin: 10
anchors.top: parent.top
anchors.topMargin: 20
}
TextField {
id: moduleSearchBox
placeholderText: "Search..."
inputMethodHints: Qt.ImhNoPredictiveText
anchors.left: moduleLabel.right
anchors.leftMargin: 10
anchors.right: parent.right
anchors.rightMargin: 10
anchors.verticalCenter: moduleLabel.verticalCenter
}
Label {
id: keyLabel
text: "Key: "
anchors.left: moduleLabel.left
anchors.top: moduleLabel.bottom
anchors.topMargin: 20
}
TextField {
id: keySearchBox
placeholderText: "Search..."
inputMethodHints: Qt.ImhNoPredictiveText
anchors.left: moduleSearchBox.left
anchors.right: moduleSearchBox.right
anchors.verticalCenter: keyLabel.verticalCenter
}
CheckBox {
id: mostRecentCheckBox
text: "show only most recent values"
checked: false
anchors.left: moduleLabel.left
anchors.top: keyLabel.bottom
anchors.topMargin: 20
}
Label {
id: statusLabel
text: "Status:"
anchors.left: moduleLabel.left
anchors.top: mostRecentCheckBox.bottom
anchors.topMargin: 20
}
Label {
id: status
text: "Disconnected"
color: "red"
anchors.left: moduleSearchBox.left
anchors.top: statusLabel.top
}
}
TableView {
id: tableView
frameVisible: false
sortIndicatorVisible: true
anchors.fill: parent
Layout.minimumWidth: 400
Layout.minimumHeight: 240
Layout.preferredWidth: 600
Layout.preferredHeight: 400
TableViewColumn {
id: moduleColumn
title: "Module"
role: "module"
movable: false
resizable: true
width: tableView.viewport.width / 3
}
TableViewColumn {
id: keyColumn
title: "Key"
role: "key"
movable: false
resizable: true
width: tableView.viewport.width / 3
}
TableViewColumn {
id: valueColumn
title: "Value"
role: "value"
movable: false
resizable: true
width: tableView.viewport.width / 3
}
// model: SortFilterProxyModel {
// id: proxyModel
// source: sourceModel.count > 0 ? sourceModel : null
// sortOrder: tableView.sortIndicatorOrder
// sortCaseSensitivity: Qt.CaseInsensitive
// sortRole: sourceModel.count > 0 ? tableView.getColumn(tableView.sortIndicatorColumn).role : ""
// filterString: moduleSearchBox.text
// filterSyntax: SortFilterProxyModel.FixedString
// filterCaseSensitivity: Qt.CaseInsensitive
// }
model: MessageModel {
id: messageModel
messageList: messages
}
}
}
//
// Created by philipp on 08.05.18.
//
#ifndef PC_LOGGER_H
#define PC_LOGGER_H
#include <memory>
#include <NetworkingLib/Networking.h>
#include <NetworkingLib/ServiceClient.h>
namespace pc
{
class Logger
: public std::enable_shared_from_this<Logger>
, private networking::Busyable
{
private:
struct PrivateTag
{
};
struct LoggingService
{
using RequestMessage = std::string;
using ResponseMessage = std::string;
};
public:
using Ptr = std::shared_ptr<Logger>;
using LoggingClient = networking::service::Client<LoggingService>;
static constexpr std::size_t PORT{10207};
static constexpr std::size_t MAX_MESSAGE_SIZE{1024};
static Ptr create(networking::Networking & net, const std::string & host)
{ return std::make_shared<Logger>(PrivateTag{}, net, host); }
Logger(PrivateTag, networking::Networking & net, const std::string & host);
void start();
void stop();
private:
struct AsyncState
{
using Ptr = std::shared_ptr<AsyncState>;
AsyncState(Logger::Ptr self)
: lock(*self), self(self)
{}
networking::BusyLock lock;
Logger::Ptr self;
};
networking::Networking & net;
std::string host;
LoggingClient::Ptr client;
networking::time::Timer::Ptr timer;
void log(AsyncState::Ptr state);
};
}
#endif //PC_LOGGER_H
//
// Created by philipp on 13.05.18.
//
#ifndef PCGUI_MESSAGELIST_H
#define PCGUI_MESSAGELIST_H
#include <QObject>
#include <MessageLib/Message.h>
#include <QtCore/QVector>
class MessageList : public QObject
{
Q_OBJECT
public:
explicit MessageList(QObject * parent = nullptr);
const QVector<message::Message> & getItems() const noexcept;
signals:
void preMessageAppended();
void postMessageAppended();
public slots:
void appendMessage(const message::Message & message);
private:
QVector<message::Message> items;
};
#endif //PCGUI_MESSAGELIST_H
#ifndef MESSAGEMODEL_H
#define MESSAGEMODEL_H
#include <QAbstractListModel>
#include "MessageLib/Message.h"
#include "MessageList.h"
class MessageModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(MessageList * messageList READ getMessageList WRITE setMessageList)
public:
explicit MessageModel(QObject * parent = nullptr);
enum
{
ModuleRole = Qt::UserRole,
KeyRole,
ValueRole
};
int rowCount(const QModelIndex & parent = QModelIndex()) const override;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override;
MessageList * getMessageList() const noexcept;
void setMessageList(MessageList * newMessageList);
private:
MessageList * messageList;
};
#endif // MESSAGEMODEL_H
\ No newline at end of file
//
// Created by philipp on 14.05.18.
//
#ifndef PCGUI_MESSAGEPRODUCER_H
#define PCGUI_MESSAGEPRODUCER_H
#include <QObject>
#include "MessageLib/Message.h"
class MessageProducer : public QObject
{
Q_OBJECT
public:
void produceMessage(const message::Message & message)
{ emit messageProduced(message); }
signals:
void messageProduced(message::Message);
};
#endif //PCGUI_MESSAGEPRODUCER_H
//
// Created by philipp on 13.05.18.
//
#ifndef PCGUI_QTQUICKCONTROLSAPPLICATION_H
#define PCGUI_QTQUICKCONTROLSAPPLICATION_H
#ifdef QT_WIDGETS_LIB
#include <QtWidgets/QApplication>
#else
#include <QtGui/QGuiApplication>
#endif
QT_BEGIN_NAMESPACE
#ifdef QT_WIDGETS_LIB
#define QtQuickControlsApplication QApplication
#else
#define QtQuickControlsApplication QGuiApplication
#endif
QT_END_NAMESPACE
#endif //PCGUI_QTQUICKCONTROLSAPPLICATION_H
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef SORTFILTERPROXYMODEL_H
#define SORTFILTERPROXYMODEL_H
#include <QtCore/qsortfilterproxymodel.h>
#include <QtQml/qqmlparserstatus.h>
#include <QtQml/qjsvalue.h>
class SortFilterProxyModel : public QSortFilterProxyModel, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(int count READ count NOTIFY countChanged)
Q_PROPERTY(QObject *source READ source WRITE setSource)
Q_PROPERTY(QByteArray sortRole READ sortRole WRITE setSortRole)
Q_PROPERTY(Qt::SortOrder sortOrder READ sortOrder WRITE setSortOrder)
Q_PROPERTY(QByteArray filterRole READ filterRole WRITE setFilterRole)
Q_PROPERTY(QString filterString READ filterString WRITE setFilterString)
Q_PROPERTY(FilterSyntax filterSyntax READ filterSyntax WRITE setFilterSyntax)
Q_ENUMS(FilterSyntax)
public:
explicit SortFilterProxyModel(QObject *parent = 0);
QObject *source() const;
void setSource(QObject *source);
QByteArray sortRole() const;
void setSortRole(const QByteArray &role);
void setSortOrder(Qt::SortOrder order);
QByteArray filterRole() const;
void setFilterRole(const QByteArray &role);
QString filterString() const;
void setFilterString(const QString &filter);
enum FilterSyntax {
RegExp,
Wildcard,
FixedString
};
FilterSyntax filterSyntax() const;
void setFilterSyntax(FilterSyntax syntax);
int count() const;
Q_INVOKABLE QJSValue get(int index) const;
void classBegin();
void componentComplete();
signals:
void countChanged();
protected:
int roleKey(const QByteArray &role) const;
QHash<int, QByteArray> roleNames() const;
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
private:
bool m_complete;
QByteArray m_sortRole;
QByteArray m_filterRole;
};
#endif // SORTFILTERPROXYMODEL_H
<RCC>
<qresource prefix="/">
<file>main.qml</file>
<file>CommandGui.qml</file>
<file>MessageGui.qml</file>
</qresource>
</RCC>
......@@ -6,7 +6,7 @@ int main(int argc, char *argv[])
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
engine.load(QUrl(QStringLiteral("qrc:/CommandGui.qml")));
if (engine.rootObjects().isEmpty())
return -1;
......
//
// Created by philipp on 08.05.18.
//
#include "../include/Logger.h"
#include <iostream>
namespace pc
{
Logger::Logger(Logger::PrivateTag, networking::Networking & net, const std::string & host)
: net(net), host(host)
{
client = LoggingClient::create(net, MAX_MESSAGE_SIZE);
timer = networking::time::Timer::create(net);
}
void Logger::start()
{
auto self = shared_from_this();
auto state = std::make_shared<AsyncState>(self);
log(state);
}
void Logger::stop()
{
timer->stop();
client->stop();
}
void Logger::log(AsyncState::Ptr state)
{
using namespace std::chrono_literals;
std::string emptyRequest;
client->asyncCall(
emptyRequest, host, PORT, 10s,
[state](const auto & error, auto & responseMessage)
{
if (!responseMessage.empty())
std::cout << responseMessage;
state->self->timer->startTimeout(1ms, [state]
{ state->self->log(state); });
});
}
}
#include "../include/QtQuickControlsApplication.h"
#include "../include/SortFilterProxyModel.h"
#include <QtQml/qqmlapplicationengine.h>
#include <QtGui/qsurfaceformat.h>
#include <QtQml/qqml.h>
#include <QtQml/QQmlContext>
#include <include/MessageModel.h>
#include "NetworkingLib/Networking.h"
#include "MessageLib/Client.h"
#include <chrono>
#include <iostream>
#include <include/MessageProducer.h>
Q_DECLARE_METATYPE(message::Message);
int main(int argc, char * argv[])
{
using namespace std::chrono_literals;
qmlRegisterType<SortFilterProxyModel>("car.pcgui", 1, 0, "SortFilterProxyModel");
qmlRegisterType<MessageModel>("car.pcgui", 1, 0, "MessageModel");
qRegisterMetaType<message::Message>();
qmlRegisterUncreatableType<MessageList>(
"car.pcgui", 1, 0, "MessageList", QStringLiteral("MessageList should not be created in QML"));
networking::Networking net;
auto messageClient = message::Client::create(net, 10207);
MessageList messages;
MessageProducer producer;
QObject::connect(&producer, SIGNAL(messageProduced(message::Message)),
&messages, SLOT(appendMessage(const message::Message &)));
QtQuickControlsApplication app(argc, argv);
if (QCoreApplication::arguments().contains(QLatin1String("--coreprofile")))
{
QSurfaceFormat fmt;
fmt.setVersion(4, 4);
fmt.setProfile(QSurfaceFormat::CoreProfile);
QSurfaceFormat::setDefaultFormat(fmt);
}
QQmlApplicationEngine engine{};
engine.rootContext()->setContextProperty(QStringLiteral("messages"), &messages);
engine.load(QUrl("qrc:/MessageGui.qml"));
if (engine.rootObjects().isEmpty())
return -1;
messageClient->requestMessagesPeriodically(
"127.0.0.1", 10ms, 3s,
[&producer](const auto & message)
{ producer.produceMessage(message); });
return app.exec();
}
//
// Created by philipp on 13.05.18.
//
#include "../include/MessageList.h"
MessageList::MessageList(QObject * parent) : QObject(parent)
{
}
const QVector<message::Message> & MessageList::getItems() const noexcept
{
return items;
}
void MessageList::appendMessage(const message::Message & message)
{
emit preMessageAppended();
items.append(message);
emit postMessageAppended();
}
#include "../include/MessageModel.h"
MessageModel::MessageModel(QObject * parent)
: QAbstractListModel(parent)
, messageList(nullptr)
{
}
int MessageModel::rowCount(const QModelIndex & parent) const
{
// For list models only the root node (an invalid parent) should return the list's size. For all
// other (valid) parents, rowCount() should return 0 so that it does not become a tree model.
if (parent.isValid() || !messageList)
return 0;
return messageList->getItems().size();
}
QVariant MessageModel::data(const QModelIndex & index, int role) const
{
if (!index.isValid() || !messageList)
return QVariant{};
auto message = messageList->getItems().at(index.row());
switch (role)
{
case ModuleRole:
return QVariant{QString::fromStdString(message.module)};
case KeyRole:
return QVariant{QString::fromStdString(message.key)};
case ValueRole:
return QVariant{QString::fromStdString(message.value)};
}
return QVariant{};
}
QHash<int, QByteArray> MessageModel::roleNames() const
{
QHash<int, QByteArray> names;
names[ModuleRole] = "module";
names[KeyRole] = "key";
names[ValueRole] = "value";
return names;
}
MessageList * MessageModel::getMessageList() const noexcept
{
return messageList;
}
void MessageModel::setMessageList(MessageList * newMessageList)
{
beginResetModel();
if (messageList)
messageList->disconnect(this);
messageList = newMessageList;
if (messageList)
{
connect(messageList, &MessageList::preMessageAppended, this, [this]
{
int index = messageList->getItems().size();
beginInsertRows(QModelIndex{}, index, index);
});
connect(messageList, &MessageList::postMessageAppended, this, [this]
{
endInsertRows();
});
}
endResetModel();
}
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "../include/SortFilterProxyModel.h"
#include <QtDebug>
#include <QtQml>
SortFilterProxyModel::SortFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent), m_complete(false)
{
connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SIGNAL(countChanged()));
connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SIGNAL(countChanged()));
}
int SortFilterProxyModel::count() const
{
return rowCount();
}
QObject *SortFilterProxyModel::source() const
{
return sourceModel();
}
void SortFilterProxyModel::setSource(QObject *source)
{
setSourceModel(qobject_cast<QAbstractItemModel *>(source));
}
QByteArray SortFilterProxyModel::sortRole() const
{
return m_sortRole;
}
void SortFilterProxyModel::setSortRole(const QByteArray &role)
{
if (m_sortRole != role) {
m_sortRole = role;
if (m_complete)
QSortFilterProxyModel::setSortRole(roleKey(role));
}
}
void SortFilterProxyModel::setSortOrder(Qt::SortOrder order)
{
QSortFilterProxyModel::sort(0, order);
}
QByteArray SortFilterProxyModel::filterRole() const
{
return m_filterRole;
}
void SortFilterProxyModel::setFilterRole(const QByteArray &role)
{
if (m_filterRole != role) {
m_filterRole = role;
if (m_complete)
QSortFilterProxyModel::setFilterRole(roleKey(role));
}
}
QString SortFilterProxyModel::filterString() const
{
return filterRegExp().pattern();
}
void SortFilterProxyModel::setFilterString(const QString &filter)
{
setFilterRegExp(QRegExp(filter, filterCaseSensitivity(), static_cast<QRegExp::PatternSyntax>(filterSyntax())));
}
SortFilterProxyModel::FilterSyntax SortFilterProxyModel::filterSyntax() const
{
return static_cast<FilterSyntax>(filterRegExp().patternSyntax());
}
void SortFilterProxyModel::setFilterSyntax(SortFilterProxyModel::FilterSyntax syntax)
{
setFilterRegExp(QRegExp(filterString(), filterCaseSensitivity(), static_cast<QRegExp::PatternSyntax>(syntax)));
}
QJSValue SortFilterProxyModel::get(int idx) const
{
QJSEngine *engine = qmlEngine(this);
QJSValue value = engine->newObject();
if (idx >= 0 && idx < count()) {
QHash<int, QByteArray> roles = roleNames();
QHashIterator<int, QByteArray> it(roles);
while (it.hasNext()) {
it.next();
value.setProperty(QString::fromUtf8(it.value()), data(index(idx, 0), it.key()).toString());
}
}
return value;
}
void SortFilterProxyModel::classBegin()
{
}
void SortFilterProxyModel::componentComplete()
{
m_complete = true;
if (!m_sortRole.isEmpty())
QSortFilterProxyModel::setSortRole(roleKey(m_sortRole));
if (!m_filterRole.isEmpty())
QSortFilterProxyModel::setFilterRole(roleKey(m_filterRole));
}
int SortFilterProxyModel::roleKey(const QByteArray &role) const
{
QHash<int, QByteArray> roles = roleNames();
QHashIterator<int, QByteArray> it(roles);
while (it.hasNext()) {
it.next();
if (it.value() == role)
return it.key();
}
return -1;
}
QHash<int, QByteArray> SortFilterProxyModel::roleNames() const
{
if (QAbstractItemModel *source = sourceModel())
return source->roleNames();
return QHash<int, QByteArray>();
}
bool SortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
QRegExp rx = filterRegExp();
if (rx.isEmpty())
return true;
QAbstractItemModel *model = sourceModel();
if (filterRole().isEmpty()) {
QHash<int, QByteArray> roles = roleNames();
QHashIterator<int, QByteArray> it(roles);
while (it.hasNext()) {
it.next();
QModelIndex sourceIndex = model->index(sourceRow, 0, sourceParent);
QString key = model->data(sourceIndex, it.key()).toString();
if (key.contains(rx))
return true;
}
return false;
}
QModelIndex sourceIndex = model->index(sourceRow, 0, sourceParent);
if (!sourceIndex.isValid())
return true;
QString key = model->data(sourceIndex, roleKey(filterRole())).toString();
return key.contains(rx);
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment