From 5c2fc0d8cbbacc1cc9665759f723150b8e67085c Mon Sep 17 00:00:00 2001
From: Hoop77 <p.badenhoop@gmx.de>
Date: Wed, 16 May 2018 14:53:07 +0200
Subject: [PATCH] MessageGui still crashes when showing most recent messages;
 CommandGui ready

---
 .../catkin_ws/src/MessageLib/src/Client.cpp   |   2 +-
 .../catkin_ws/src/PC2CarLib/CMakeLists.txt    |   8 +-
 .../src/PC2CarLib/test/DisplayCommands.cpp    |  59 ++++++++
 .../src/PC2CarLib/test/{Main.cpp => Test.cpp} |   0
 .../catkin_ws/src/PCGui/PCGui/CMakeLists.txt  |  26 ++--
 .../catkin_ws/src/PCGui/PCGui/CommandGui.qml  | 136 +++++++++++++++++-
 .../catkin_ws/src/PCGui/PCGui/MessageGui.qml  |  97 ++++++++++---
 .../PCGui/include/CommandGui/SignalConsumer.h |  63 ++++++++
 .../PCGui/PCGui/include/MessageGui/Message.h  |  25 ++++
 .../include/MessageGui/MessageCollection.h    |  42 ++++++
 .../PCGui/include/MessageGui/MessageList.h    |  32 +++++
 .../include/{ => MessageGui}/MessageModel.h   |  15 +-
 .../PCGui/include/MessageGui/MessageRole.h    |  33 +++++
 .../MostRecentMessageFiltertProxyModel.h      |  91 ++++++++++++
 .../PCGui/include/MessageGui/SignalConsumer.h |  47 ++++++
 .../PCGui/include/MessageGui/SignalProducer.h |  36 +++++
 .../{ => MessageGui}/SortFilterProxyModel.h   |   0
 .../PCGui/PCGui/include/MessageGui/Utils.h    |  31 ++++
 .../src/PCGui/PCGui/include/MessageList.h     |  32 -----
 .../src/PCGui/PCGui/include/MessageProducer.h |  23 ---
 .../src/PCGui/PCGui/src/CommandGui.cpp        |  14 --
 .../PCGui/PCGui/src/CommandGui/CommandGui.cpp |  97 +++++++++++++
 .../src/PCGui/PCGui/src/MessageGui.cpp        |  54 -------
 .../PCGui/PCGui/src/MessageGui/MessageGui.cpp | 119 +++++++++++++++
 .../PCGui/src/MessageGui/MessageList.cpp      |  33 +++++
 .../PCGui/src/MessageGui/MessageModel.cpp     |  87 +++++++++++
 .../MostRecentMessageFilterProxyModel.cpp     | 103 +++++++++++++
 .../{ => MessageGui}/SortFilterProxyModel.cpp |   2 +-
 .../src/PCGui/PCGui/src/MessageList.cpp       |  21 ---
 .../src/PCGui/PCGui/src/MessageModel.cpp      |  78 ----------
 .../src/car/src/ultrasonic/Ultrasonic.cpp     |   6 +-
 31 files changed, 1142 insertions(+), 270 deletions(-)
 create mode 100644 modules/catkin_ws/src/PC2CarLib/test/DisplayCommands.cpp
 rename modules/catkin_ws/src/PC2CarLib/test/{Main.cpp => Test.cpp} (100%)
 create mode 100644 modules/catkin_ws/src/PCGui/PCGui/include/CommandGui/SignalConsumer.h
 create mode 100644 modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/Message.h
 create mode 100644 modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/MessageCollection.h
 create mode 100644 modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/MessageList.h
 rename modules/catkin_ws/src/PCGui/PCGui/include/{ => MessageGui}/MessageModel.h (62%)
 create mode 100644 modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/MessageRole.h
 create mode 100644 modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/MostRecentMessageFiltertProxyModel.h
 create mode 100644 modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/SignalConsumer.h
 create mode 100644 modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/SignalProducer.h
 rename modules/catkin_ws/src/PCGui/PCGui/include/{ => MessageGui}/SortFilterProxyModel.h (100%)
 create mode 100644 modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/Utils.h
 delete mode 100644 modules/catkin_ws/src/PCGui/PCGui/include/MessageList.h
 delete mode 100644 modules/catkin_ws/src/PCGui/PCGui/include/MessageProducer.h
 delete mode 100644 modules/catkin_ws/src/PCGui/PCGui/src/CommandGui.cpp
 create mode 100644 modules/catkin_ws/src/PCGui/PCGui/src/CommandGui/CommandGui.cpp
 delete mode 100644 modules/catkin_ws/src/PCGui/PCGui/src/MessageGui.cpp
 create mode 100644 modules/catkin_ws/src/PCGui/PCGui/src/MessageGui/MessageGui.cpp
 create mode 100644 modules/catkin_ws/src/PCGui/PCGui/src/MessageGui/MessageList.cpp
 create mode 100644 modules/catkin_ws/src/PCGui/PCGui/src/MessageGui/MessageModel.cpp
 create mode 100644 modules/catkin_ws/src/PCGui/PCGui/src/MessageGui/MostRecentMessageFilterProxyModel.cpp
 rename modules/catkin_ws/src/PCGui/PCGui/src/{ => MessageGui}/SortFilterProxyModel.cpp (96%)
 delete mode 100644 modules/catkin_ws/src/PCGui/PCGui/src/MessageList.cpp
 delete mode 100644 modules/catkin_ws/src/PCGui/PCGui/src/MessageModel.cpp

diff --git a/modules/catkin_ws/src/MessageLib/src/Client.cpp b/modules/catkin_ws/src/MessageLib/src/Client.cpp
index a00ef36c..38eb532b 100644
--- a/modules/catkin_ws/src/MessageLib/src/Client.cpp
+++ b/modules/catkin_ws/src/MessageLib/src/Client.cpp
@@ -78,7 +78,7 @@ void Client::nextRequest(PeriodicAsyncState::Ptr state)
         return;
 
     std::string emptyRequest;
-    net.waitWhileBusy(*(state->self->client));
+    net.waitWhileBusy(*(client));
     client->asyncCall(
         emptyRequest, state->host, state->self->port, state->retryInterval,
         [state](const auto & error, const auto & responseMessage)
diff --git a/modules/catkin_ws/src/PC2CarLib/CMakeLists.txt b/modules/catkin_ws/src/PC2CarLib/CMakeLists.txt
index f2b61086..15a3de67 100644
--- a/modules/catkin_ws/src/PC2CarLib/CMakeLists.txt
+++ b/modules/catkin_ws/src/PC2CarLib/CMakeLists.txt
@@ -114,12 +114,12 @@ endif()
 #######
 # Test
 #######
-set(TEST_SOURCE_FILES ${SOURCE_FILES} test/Main.cpp)
-add_executable(PC2CarTest ${TEST_SOURCE_FILES})
+add_executable(PC2CarTest ${SOURCE_FILES} test/Test.cpp)
+add_executable(DisplayCommands ${SOURCE_FILES} test/DisplayCommands.cpp)
 
 # NetworkingLib
 target_include_directories(PC2CarTest PUBLIC ${NetworkingLib_INCLUDE_DIRS})
 target_link_libraries(PC2CarTest NetworkingLib)
 
-# For debugging
-target_compile_options(PC2CarTest PUBLIC -fopenmp -fPIC -O0 -g3 -ggdb)
\ No newline at end of file
+target_include_directories(DisplayCommands PUBLIC ${NetworkingLib_INCLUDE_DIRS})
+target_link_libraries(DisplayCommands NetworkingLib)
\ No newline at end of file
diff --git a/modules/catkin_ws/src/PC2CarLib/test/DisplayCommands.cpp b/modules/catkin_ws/src/PC2CarLib/test/DisplayCommands.cpp
new file mode 100644
index 00000000..a40c8a20
--- /dev/null
+++ b/modules/catkin_ws/src/PC2CarLib/test/DisplayCommands.cpp
@@ -0,0 +1,59 @@
+//
+// Created by philipp on 16.05.18.
+//
+
+#include <iostream>
+#include "../include/PC2CarLib/CommandSender.h"
+#include "../include/PC2CarLib/CommandReceiver.h"
+
+int main(int argc, char ** argv)
+{
+    using namespace pc2car;
+
+    networking::Networking net;
+    CommandSender sender{net, "127.0.0.1"};
+    auto receiver = CommandReceiver::create(net);
+
+    receiver->receiveCommands(
+        [receiver](CommandCode code)
+        {
+            using namespace commandCodes;
+            std::cout << "code: " << code << "\n";
+            switch (code)
+            {
+                case ENABLE_LOGGING:
+                    std::cout << "ENABLE_LOGGING\n";
+                    std::cout << receiver->isLoggingEnabled().get() << "\n";
+                    break;
+
+                case ENABLE_PLATOON:
+                    std::cout << "ENABLE_PLATOON\n";
+                    std::cout << receiver->isPlatoonEnabled().get() << "\n";
+                    break;
+
+                case ENABLE_RC_MODE:
+                    std::cout << "ENABLE_RC_MODE\n";
+                    std::cout << receiver->isRcModeEnabled().get() << "\n";
+                    break;
+
+                case SET_PS:
+                    std::cout << "SET_PS\n";
+                    std::cout << receiver->getPlatoonSpeed().get() << "\n";
+                    break;
+
+                case SET_IPD:
+                    std::cout << "SET_IPD\n";
+                    std::cout << receiver->getInnerPlatoonDistance().get() << "\n";
+                    break;
+
+                case SET_SPEED:
+                    std::cout << "SET_SPEED\n";
+                    std::cout << receiver->getSpeed().get() << "\n";
+                    break;
+            }
+            std::cout << std::flush;
+        });
+
+    while (1);
+    return 0;
+}
\ No newline at end of file
diff --git a/modules/catkin_ws/src/PC2CarLib/test/Main.cpp b/modules/catkin_ws/src/PC2CarLib/test/Test.cpp
similarity index 100%
rename from modules/catkin_ws/src/PC2CarLib/test/Main.cpp
rename to modules/catkin_ws/src/PC2CarLib/test/Test.cpp
diff --git a/modules/catkin_ws/src/PCGui/PCGui/CMakeLists.txt b/modules/catkin_ws/src/PCGui/PCGui/CMakeLists.txt
index ac4fc842..abe911b5 100644
--- a/modules/catkin_ws/src/PCGui/PCGui/CMakeLists.txt
+++ b/modules/catkin_ws/src/PCGui/PCGui/CMakeLists.txt
@@ -36,17 +36,25 @@ set(SOURCE_FILES
         qml.qrc)
 
 add_executable(CommandGui ${SOURCE_FILES}
-        src/CommandGui.cpp)
+        include/CommandGui/SignalConsumer.h
+        src/CommandGui/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)
+        include/MessageGui/SortFilterProxyModel.h
+        include/MessageGui/MessageModel.h
+        include/MessageGui/MessageCollection.h
+        include/MessageGui/MessageList.h
+        include/MessageGui/SignalProducer.h
+        include/MessageGui/SignalConsumer.h
+        include/MessageGui/Utils.h
+        include/MessageGui/MostRecentMessageFiltertProxyModel.h
+        include/MessageGui/MessageRole.h
+        include/MessageGui/Message.h
+        src/MessageGui/MessageGui.cpp
+        src/MessageGui/MessageModel.cpp
+        src/MessageGui/MessageList.cpp
+        src/MessageGui/MostRecentMessageFilterProxyModel.cpp
+        src/MessageGui/SortFilterProxyModel.cpp)
 
 target_link_libraries(CommandGui ${LIBS})
 target_link_libraries(MessageGui ${LIBS})
diff --git a/modules/catkin_ws/src/PCGui/PCGui/CommandGui.qml b/modules/catkin_ws/src/PCGui/PCGui/CommandGui.qml
index 9a40ba2d..ca724ffb 100644
--- a/modules/catkin_ws/src/PCGui/PCGui/CommandGui.qml
+++ b/modules/catkin_ws/src/PCGui/PCGui/CommandGui.qml
@@ -1,9 +1,139 @@
 import QtQuick 2.5
 import QtQuick.Window 2.2
+import QtQuick.Controls 1.2
 
-Window {
+ApplicationWindow {
     visible: true
-    width: 640
-    height: 480
+    width: 500
+    height: 250
     title: qsTr("Command Gui")
+
+    // --- host ---
+    Label {
+        id: hostLabel
+        text: "Host:"
+
+        anchors.left: parent.left
+        anchors.leftMargin: 30
+        anchors.top: parent.top
+        anchors.topMargin: 30
+    }
+
+    TextField {
+        id: hostTextField
+        objectName: "hostTextField"
+        text: "127.0.0.1"
+
+        anchors.left: hostLabel.right
+        anchors.leftMargin: 150
+        anchors.verticalCenter: hostLabel.verticalCenter
+    }
+
+    Button {
+        id: setHostButton
+        objectName: "setHostButton"
+        text: "set"
+
+        anchors.left: hostTextField.right
+        anchors.leftMargin: 10
+        anchors.verticalCenter: hostTextField.verticalCenter
+    }
+
+    // --- enablePlatoon ---
+    CheckBox {
+        id: enablePlatoonCheckbox
+        objectName: "enablePlatoonCheckbox"
+        text: "Platoon enabled"
+
+        anchors.left: hostLabel.left
+        anchors.top: hostLabel.bottom
+        anchors.topMargin: 20
+    }
+
+    // --- platoonSpeed ---
+    Label {
+        id: platoonSpeedLabel
+        text: "Platoon Speed:"
+
+        anchors.left: hostLabel.left
+        anchors.top: enablePlatoonCheckbox.bottom
+        anchors.topMargin: 20
+    }
+
+    TextField {
+        id: platoonSpeedTextField
+        objectName: "platoonSpeedTextField"
+        text: "0"
+
+        anchors.left: hostTextField.left
+        anchors.verticalCenter: platoonSpeedLabel.verticalCenter
+    }
+
+    Button {
+        id: setPlatoonSpeedButton
+        objectName: "setPlatoonSpeedButton"
+        text: "set"
+
+        anchors.left: platoonSpeedTextField.right
+        anchors.leftMargin: 10
+        anchors.verticalCenter: platoonSpeedTextField.verticalCenter
+    }
+
+    // --- innerPlatoonDistance ---
+    Label {
+        id: innerPlatoonDistanceLabel
+        text: "Inner Platoon Distance:"
+
+        anchors.left: hostLabel.left
+        anchors.top: platoonSpeedLabel.bottom
+        anchors.topMargin: 20
+    }
+
+    TextField {
+        id: innerPlatoonDistanceTextField
+        objectName: "innerPlatoonDistanceTextField"
+        text: "0"
+
+        anchors.left: hostTextField.left
+        anchors.verticalCenter: innerPlatoonDistanceLabel.verticalCenter
+    }
+
+    Button {
+        id: setInnerPlatoonDistanceButton
+        objectName: "setInnerPlatoonDistanceButton"
+        text: "set"
+
+        anchors.left: innerPlatoonDistanceTextField.right
+        anchors.leftMargin: 10
+        anchors.verticalCenter: innerPlatoonDistanceTextField.verticalCenter
+    }
+
+    // --- speed ---
+    Label {
+        id: speedLabel
+        text: "Platoon Speed:"
+
+        anchors.left: hostLabel.left
+        anchors.top: innerPlatoonDistanceLabel.bottom
+        anchors.topMargin: 20
+    }
+
+    TextField {
+        id: speedTextField
+        objectName: "speedTextField"
+        text: "0"
+
+        anchors.left: hostTextField.left
+        anchors.verticalCenter: speedLabel.verticalCenter
+    }
+
+    Button {
+        id: setPlatoonButton
+        objectName: "setSpeedButton"
+        text: "set"
+
+        anchors.left: speedTextField.right
+        anchors.leftMargin: 10
+        anchors.verticalCenter: speedTextField.verticalCenter
+    }
 }
diff --git a/modules/catkin_ws/src/PCGui/PCGui/MessageGui.qml b/modules/catkin_ws/src/PCGui/PCGui/MessageGui.qml
index 45d0b62e..08350fbc 100644
--- a/modules/catkin_ws/src/PCGui/PCGui/MessageGui.qml
+++ b/modules/catkin_ws/src/PCGui/PCGui/MessageGui.qml
@@ -62,22 +62,66 @@ ApplicationWindow {
             anchors.topMargin: 20
         }
 
+        Button {
+            id: clearButton
+            text: "Clear"
+            onClicked: {
+                messageList_.clear();
+            }
+
+            anchors.left: mostRecentCheckBox.right
+            anchors.leftMargin: 20
+            anchors.verticalCenter: mostRecentCheckBox.verticalCenter
+        }
+
         Label {
-            id: statusLabel
-            text: "Status:"
+            id: hostLabel
+            text: "Host:"
 
             anchors.left: moduleLabel.left
             anchors.top: mostRecentCheckBox.bottom
             anchors.topMargin: 20
         }
 
+        TextField {
+            id: hostTextField
+            objectName: "hostTextField"
+            text: "127.0.0.1"
+
+            anchors.left: hostLabel.right
+            anchors.leftMargin: 20
+            anchors.verticalCenter: hostLabel.verticalCenter
+        }
+
+        Button {
+            id: connectButton
+            objectName: "connectButton"
+            text: "Connect"
+
+            anchors.left: hostTextField.right
+            anchors.leftMargin: 20
+            anchors.verticalCenter: hostTextField.verticalCenter
+        }
+
+        Label {
+            id: statusLabel
+            text: "Status:"
+
+            anchors.left: connectButton.right
+            anchors.leftMargin: 20
+            anchors.verticalCenter: connectButton.verticalCenter
+        }
+
         Label {
-            id: status
+            id: statusTextLabel
+            objectName: "statusTextLabel"
+
             text: "Disconnected"
             color: "red"
 
-            anchors.left: moduleSearchBox.left
-            anchors.top: statusLabel.top
+            anchors.left: statusLabel.right
+            anchors.leftMargin: 20
+            anchors.verticalCenter: statusLabel.verticalCenter
         }
     }
 
@@ -121,22 +165,41 @@ ApplicationWindow {
             width: tableView.viewport.width / 3
         }
 
-        // model: SortFilterProxyModel {
-        //     id: proxyModel
-        //     source: sourceModel.count > 0 ? sourceModel : null
+        model: SortFilterProxyModel {
+            id: filterKeyModel
+            source: filterModuleModel
 
-        //     sortOrder: tableView.sortIndicatorOrder
-        //     sortCaseSensitivity: Qt.CaseInsensitive
-        //     sortRole: sourceModel.count > 0 ? tableView.getColumn(tableView.sortIndicatorColumn).role : ""
+            //sortOrder: tableView.sortIndicatorOrder
+            sortCaseSensitivity: Qt.CaseInsensitive
+            sortRole: "key"
 
-        //     filterString: moduleSearchBox.text
-        //     filterSyntax: SortFilterProxyModel.FixedString
-        //     filterCaseSensitivity: Qt.CaseInsensitive
-        // }
+            filterString: "*" + keySearchBox.text + "*"
+            filterSyntax: SortFilterProxyModel.Wildcard
+            filterCaseSensitivity: Qt.CaseInsensitive
+        }
+
+        SortFilterProxyModel {
+            id: filterModuleModel
+            source: mostRecentModel
+
+            //sortOrder: tableView.sortIndicatorOrder
+            sortCaseSensitivity: Qt.CaseInsensitive
+            sortRole: "module"
+
+            filterString: "*" + moduleSearchBox.text + "*"
+            filterSyntax: SortFilterProxyModel.Wildcard
+            filterCaseSensitivity: Qt.CaseInsensitive
+        }
+
+        MostRecentMessageFilterProxyModel {
+            id: mostRecentModel
+            source: messageModel
+            enabled: mostRecentCheckBox.checked
+        }
 
-        model: MessageModel {
+        MessageModel {
             id: messageModel
-            messageList: messages
+            messageCollection: messageList_
         }
     }
 }
diff --git a/modules/catkin_ws/src/PCGui/PCGui/include/CommandGui/SignalConsumer.h b/modules/catkin_ws/src/PCGui/PCGui/include/CommandGui/SignalConsumer.h
new file mode 100644
index 00000000..efefa1ea
--- /dev/null
+++ b/modules/catkin_ws/src/PCGui/PCGui/include/CommandGui/SignalConsumer.h
@@ -0,0 +1,63 @@
+//
+// Created by philipp on 16.05.18.
+//
+
+#ifndef PCGUI_SIGNALCONSUMER_H
+#define PCGUI_SIGNALCONSUMER_H
+
+#include <QObject>
+#include <functional>
+
+class SignalConsumer : public QObject
+{
+Q_OBJECT
+
+public:
+
+    using Callback = std::function<void()>;
+
+    explicit SignalConsumer(QObject * parent = nullptr) : QObject(parent)
+    {}
+
+    void setOnHostChanged(const Callback & callback)
+    { onHostChanged = callback; }
+
+    void setOnEnablePlatoonChanged(const Callback & callback)
+    { onEnablePlatoonChanged = callback; }
+
+    void setOnPlatoonSpeedChanged(const Callback & callback)
+    { onPlatoonSpeedChanged = callback; }
+
+    void setOnInnerPlatoonDistanceChanged(const Callback & callback)
+    { onInnerPlatoonDistanceChanged = callback; }
+
+    void setOnSpeedChanged(const Callback & callback)
+    { onSpeedChanged = callback; }
+
+public slots:
+
+    void hostChanged()
+    { onHostChanged(); };
+
+    void enablePlatoonChanged()
+    { onEnablePlatoonChanged(); }
+
+    void platoonSpeedChanged()
+    { onPlatoonSpeedChanged(); }
+
+    void innerPlatoonDistanceChanged()
+    { onInnerPlatoonDistanceChanged(); }
+
+    void speedChanged()
+    { onSpeedChanged(); }
+
+private:
+
+    Callback onHostChanged = [] {};
+    Callback onEnablePlatoonChanged = [] {};
+    Callback onPlatoonSpeedChanged = [] {};
+    Callback onInnerPlatoonDistanceChanged = [] {};
+    Callback onSpeedChanged = [] {};
+};
+
+#endif //PCGUI_SIGNALCONSUMER_H
diff --git a/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/Message.h b/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/Message.h
new file mode 100644
index 00000000..f93ce811
--- /dev/null
+++ b/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/Message.h
@@ -0,0 +1,25 @@
+//
+// Created by philipp on 15.05.18.
+//
+
+#ifndef PCGUI_MESSAGE_H
+#define PCGUI_MESSAGE_H
+
+#include "MessageLib/Message.h"
+#include <QMetaType>
+
+struct Message
+{
+    Message() = default;
+
+    Message(int id, const message::Message & data)
+        : id(id), data(data)
+    {}
+
+    int id;
+    message::Message data;
+};
+
+Q_DECLARE_METATYPE(Message);
+
+#endif //PCGUI_MESSAGE_H
diff --git a/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/MessageCollection.h b/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/MessageCollection.h
new file mode 100644
index 00000000..20e8d8be
--- /dev/null
+++ b/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/MessageCollection.h
@@ -0,0 +1,42 @@
+
+//
+// Created by philipp on 15.05.18.
+//
+
+#ifndef PCGUI_MESSAGECOLLECTION_H
+#define PCGUI_MESSAGECOLLECTION_H
+
+#include <QObject>
+#include "Message.h"
+
+class MessageCollection : public QObject
+{
+Q_OBJECT
+
+public:
+    explicit MessageCollection(QObject * parent = nullptr) : QObject(parent)
+    {}
+
+    virtual Message & getItem(int index) = 0;
+
+    virtual int getSize() const noexcept = 0;
+
+signals:
+
+    void preMessageInserted();
+
+    void postMessageInserted();
+
+    void preMessagesCleared();
+
+    void postMessagesCleared();
+
+public slots:
+
+    virtual void insert(const Message & message) = 0;
+
+    virtual void clear() = 0;
+
+};
+
+#endif //PCGUI_MESSAGECOLLECTION_H
diff --git a/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/MessageList.h b/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/MessageList.h
new file mode 100644
index 00000000..456a768c
--- /dev/null
+++ b/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/MessageList.h
@@ -0,0 +1,32 @@
+//
+// Created by philipp on 13.05.18.
+//
+
+#ifndef PCGUI_MESSAGELIST_H
+#define PCGUI_MESSAGELIST_H
+
+#include "MessageCollection.h"
+#include <QtCore/QVector>
+
+class MessageList : public MessageCollection
+{
+Q_OBJECT
+
+public:
+    explicit MessageList(QObject * parent = nullptr);
+
+    Message & getItem(int index) override;
+
+    int getSize() const noexcept override;
+
+public slots:
+
+    void insert(const Message & message) override;
+
+    void clear() override;
+
+private:
+    QVector<Message> items;
+};
+
+#endif //PCGUI_MESSAGELIST_H
diff --git a/modules/catkin_ws/src/PCGui/PCGui/include/MessageModel.h b/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/MessageModel.h
similarity index 62%
rename from modules/catkin_ws/src/PCGui/PCGui/include/MessageModel.h
rename to modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/MessageModel.h
index 3434974b..18961fd9 100644
--- a/modules/catkin_ws/src/PCGui/PCGui/include/MessageModel.h
+++ b/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/MessageModel.h
@@ -9,30 +9,23 @@ class MessageModel : public QAbstractListModel
 {
 Q_OBJECT
 
-Q_PROPERTY(MessageList * messageList READ getMessageList WRITE setMessageList)
+Q_PROPERTY(MessageCollection * messageCollection READ getMessageCollection WRITE setMessageCollection)
 
 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;
+    MessageCollection * getMessageCollection() const noexcept;
 
-    void setMessageList(MessageList * newMessageList);
+    void setMessageCollection(MessageCollection * newMessageCollection);
 
 private:
-    MessageList * messageList;
+    MessageCollection * messageCollection;
 };
 
 #endif // MESSAGEMODEL_H
\ No newline at end of file
diff --git a/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/MessageRole.h b/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/MessageRole.h
new file mode 100644
index 00000000..e76c0e10
--- /dev/null
+++ b/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/MessageRole.h
@@ -0,0 +1,33 @@
+//
+// Created by philipp on 15.05.18.
+//
+
+#ifndef PCGUI_MESSAGEROLES_H
+#define PCGUI_MESSAGEROLES_H
+
+#include <QHash>
+
+namespace messageRole
+{
+
+enum
+{
+    id = Qt::UserRole,
+    module,
+    key,
+    value
+};
+
+inline QHash<int, QByteArray> roleNames()
+{
+    QHash<int, QByteArray> names;
+    names[id] = "id";
+    names[module] = "module";
+    names[key] = "key";
+    names[value] = "value";
+    return names;
+}
+
+}
+
+#endif //PCGUI_MESSAGEROLES_H
diff --git a/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/MostRecentMessageFiltertProxyModel.h b/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/MostRecentMessageFiltertProxyModel.h
new file mode 100644
index 00000000..58c137a3
--- /dev/null
+++ b/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/MostRecentMessageFiltertProxyModel.h
@@ -0,0 +1,91 @@
+//
+// Created by philipp on 15.05.18.
+//
+
+#ifndef PCGUI_MOSTRECENTFILTERTPROXYMODEL_H
+#define PCGUI_MOSTRECENTFILTERTPROXYMODEL_H
+
+#include <QtCore/QSortFilterProxyModel>
+#include <unordered_map>
+#include "MessageLib/Message.h"
+
+struct MessageKey
+{
+    MessageKey(const std::string & module, const std::string & key)
+        : module(module), key(key)
+    {}
+
+    std::string module;
+    std::string key;
+};
+
+namespace std
+{
+
+template<>
+struct hash<MessageKey>
+{
+    std::size_t operator()(const MessageKey & key) const
+    {
+        return std::hash<std::string>{}(key.module + "#" + key.key);
+    }
+};
+
+template<>
+struct equal_to<MessageKey>
+{
+    bool operator()(const MessageKey & lhs, const MessageKey & rhs) const noexcept
+    {
+        return lhs.module == rhs.module && lhs.key == rhs.key;
+    }
+};
+
+}
+
+class MostRecentMessageFilterProxyModel : public QSortFilterProxyModel
+{
+Q_OBJECT
+
+    Q_PROPERTY(int count READ count NOTIFY countChanged)
+    Q_PROPERTY(QObject * source READ source WRITE setSource)
+    Q_PROPERTY(bool enabled READ enabled WRITE enable )
+
+public:
+    explicit MostRecentMessageFilterProxyModel(QObject * parent = nullptr);
+
+    QObject * source() const;
+
+    void setSource(QObject * source);
+
+    int count() const;
+
+    void enable(bool flag);
+
+    bool enabled() const noexcept;
+
+signals:
+
+    void countChanged();
+
+protected slots:
+
+    void onRowsInserted(const QModelIndex & parent, int first, int last);
+
+    void onRowsRemoved(const QModelIndex & parent, int first, int last);
+
+protected:
+    QHash<int, QByteArray> roleNames() const;
+
+    bool filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const override;
+
+private:
+
+    MessageKey messageKeyFromRow(int row, const QModelIndex & parent) const;
+
+    int idFromRow(int row, const QModelIndex & parent) const;
+
+    std::unordered_map<MessageKey, int> mostRecent;
+    bool enabledFlag{false};
+};
+
+#endif //PCGUI_MOSTRECENTFILTERTPROXYMODEL_H
diff --git a/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/SignalConsumer.h b/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/SignalConsumer.h
new file mode 100644
index 00000000..c49f3f11
--- /dev/null
+++ b/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/SignalConsumer.h
@@ -0,0 +1,47 @@
+//
+// Created by philipp on 15.05.18.
+//
+
+#ifndef PCGUI_SIGNALCONSUMER_H
+#define PCGUI_SIGNALCONSUMER_H
+
+#include <QObject>
+#include <functional>
+
+class SignalConsumer : public QObject
+{
+Q_OBJECT
+
+public:
+    using Callback = std::function<void()>;
+
+    SignalConsumer(QObject * parent = nullptr)
+    {}
+
+    void setOnShowConnected(const Callback & callback)
+    { onShowConnected = callback; }
+
+    void setOnShowDisconnected(const Callback & callback)
+    { onShowDisconnected = callback; }
+
+    void setOnDoConnect(const Callback & callback)
+    { onDoConnect = callback; }
+
+public slots:
+
+    void showConnected()
+    { onShowConnected(); };
+
+    void showDisconnected()
+    { onShowDisconnected(); }
+
+    void doConnect()
+    { onDoConnect(); }
+
+private:
+    Callback onShowConnected = [] {};
+    Callback onShowDisconnected = [] {};
+    Callback onDoConnect = [] {};
+};
+
+#endif //PCGUI_SIGNALCONSUMER_H
diff --git a/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/SignalProducer.h b/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/SignalProducer.h
new file mode 100644
index 00000000..3cf62a56
--- /dev/null
+++ b/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/SignalProducer.h
@@ -0,0 +1,36 @@
+//
+// Created by philipp on 15.05.18.
+//
+
+#ifndef PCGUI_SIGNALPRODUCER_H
+#define PCGUI_SIGNALPRODUCER_H
+
+#include <QObject>
+
+class SignalProducer : public QObject
+{
+Q_OBJECT
+
+public:
+    SignalProducer(QObject * parent = nullptr)
+    {}
+
+    void emitConnected()
+    { emit connected(); }
+
+    void emitDisconnected()
+    { emit disconnected(); }
+
+    void emitMessageProduced(const Message & message)
+    { emit messageProduced(message); }
+
+signals:
+
+    void connected();
+
+    void disconnected();
+
+    void messageProduced(Message);
+};
+
+#endif //PCGUI_SIGNALPRODUCER_H
diff --git a/modules/catkin_ws/src/PCGui/PCGui/include/SortFilterProxyModel.h b/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/SortFilterProxyModel.h
similarity index 100%
rename from modules/catkin_ws/src/PCGui/PCGui/include/SortFilterProxyModel.h
rename to modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/SortFilterProxyModel.h
diff --git a/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/Utils.h b/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/Utils.h
new file mode 100644
index 00000000..f74c5a18
--- /dev/null
+++ b/modules/catkin_ws/src/PCGui/PCGui/include/MessageGui/Utils.h
@@ -0,0 +1,31 @@
+//
+// Created by philipp on 15.05.18.
+//
+
+#ifndef PCGUI_UTILS_H
+#define PCGUI_UTILS_H
+
+#include <unordered_map>
+#include <vector>
+
+namespace utils
+{
+
+template<template<typename...> class Map, typename Key, typename Value>
+std::vector<Key> keys(const Map<Key, Value> & map)
+{
+    std::vector<Key> mapKeys;
+    for (const auto & i : map)
+        mapKeys.emplace_back(i.first);
+    return mapKeys;
+};
+
+template<typename Container, typename Key>
+bool contains(const Container & container, const Key & key)
+{
+    return container.find(key) != container.end();
+};
+
+}
+
+#endif //PCGUI_UTILS_H
diff --git a/modules/catkin_ws/src/PCGui/PCGui/include/MessageList.h b/modules/catkin_ws/src/PCGui/PCGui/include/MessageList.h
deleted file mode 100644
index 06ada7ef..00000000
--- a/modules/catkin_ws/src/PCGui/PCGui/include/MessageList.h
+++ /dev/null
@@ -1,32 +0,0 @@
-//
-// 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
diff --git a/modules/catkin_ws/src/PCGui/PCGui/include/MessageProducer.h b/modules/catkin_ws/src/PCGui/PCGui/include/MessageProducer.h
deleted file mode 100644
index 04d36010..00000000
--- a/modules/catkin_ws/src/PCGui/PCGui/include/MessageProducer.h
+++ /dev/null
@@ -1,23 +0,0 @@
-//
-// 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
diff --git a/modules/catkin_ws/src/PCGui/PCGui/src/CommandGui.cpp b/modules/catkin_ws/src/PCGui/PCGui/src/CommandGui.cpp
deleted file mode 100644
index 04741d3d..00000000
--- a/modules/catkin_ws/src/PCGui/PCGui/src/CommandGui.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#include <QGuiApplication>
-#include <QQmlApplicationEngine>
-
-int main(int argc, char *argv[])
-{
-    QGuiApplication app(argc, argv);
-
-    QQmlApplicationEngine engine;
-    engine.load(QUrl(QStringLiteral("qrc:/CommandGui.qml")));
-    if (engine.rootObjects().isEmpty())
-        return -1;
-
-    return app.exec();
-}
diff --git a/modules/catkin_ws/src/PCGui/PCGui/src/CommandGui/CommandGui.cpp b/modules/catkin_ws/src/PCGui/PCGui/src/CommandGui/CommandGui.cpp
new file mode 100644
index 00000000..2f81c9cf
--- /dev/null
+++ b/modules/catkin_ws/src/PCGui/PCGui/src/CommandGui/CommandGui.cpp
@@ -0,0 +1,97 @@
+#include "include/QtQuickControlsApplication.h"
+#include <QQmlApplicationEngine>
+#include <QtGui/qsurfaceformat.h>
+#include <QtQml/qqml.h>
+#include <QtQml/QQmlContext>
+#include <NetworkingLib/Networking.h>
+#include "../include/CommandGui/SignalConsumer.h"
+#include "PC2CarLib/CommandSender.h"
+
+void registerTypes()
+{
+    qmlRegisterUncreatableType<SignalConsumer>(
+        "car.pcgui", 1, 0, "SignalConsumer", QStringLiteral("SignalConsumer should not be created in QML"));
+}
+
+void configureSurfaceFormat()
+{
+    if (QCoreApplication::arguments().contains(QLatin1String("--coreprofile")))
+    {
+        QSurfaceFormat fmt;
+        fmt.setVersion(4, 4);
+        fmt.setProfile(QSurfaceFormat::CoreProfile);
+        QSurfaceFormat::setDefaultFormat(fmt);
+    }
+}
+
+int main(int argc, char * argv[])
+{
+    SignalConsumer consumer;
+    networking::Networking net;
+    pc2car::CommandSender commandSender{net, "127.0.0.1"};
+
+    registerTypes();
+    QtQuickControlsApplication app{argc, argv};
+    configureSurfaceFormat();
+    QQmlApplicationEngine engine{};
+
+    engine.rootContext()->setContextProperty(QStringLiteral("consumer"), &consumer);
+
+    engine.load(QUrl("qrc:/CommandGui.qml"));
+    if (engine.rootObjects().isEmpty())
+        return -1;
+
+    auto root = engine.rootObjects()[0];
+    auto hostTextField = root->findChild<QObject *>("hostTextField");
+    auto setHostButton = root->findChild<QObject *>("setHostButton");
+    auto enablePlatoonCheckBox = root->findChild<QObject *>("enablePlatoonCheckbox");
+    auto platoonSpeedTextField = root->findChild<QObject *>("platoonSpeedTextField");
+    auto setPlatoonSpeedButton = root->findChild<QObject *>("setPlatoonSpeedButton");
+    auto innerPlatoonDistanceTextField = root->findChild<QObject *>("innerPlatoonDistanceTextField");
+    auto setInnerPlatoonDistanceButton = root->findChild<QObject *>("setInnerPlatoonDistanceButton");
+    auto speedTextField = root->findChild<QObject *>("speedTextField");
+    auto setSpeedButton = root->findChild<QObject *>("setSpeedButton");
+
+    QObject::connect(setHostButton, SIGNAL(clicked()), &consumer, SLOT(hostChanged()));
+    QObject::connect(enablePlatoonCheckBox, SIGNAL(clicked()), &consumer, SLOT(enablePlatoonChanged()));
+    QObject::connect(setPlatoonSpeedButton, SIGNAL(clicked()), &consumer, SLOT(platoonSpeedChanged()));
+    QObject::connect(setInnerPlatoonDistanceButton, SIGNAL(clicked()), &consumer, SLOT(innerPlatoonDistanceChanged()));
+    QObject::connect(setSpeedButton, SIGNAL(clicked()), &consumer, SLOT(speedChanged()));
+
+    consumer.setOnHostChanged(
+        [&commandSender, &hostTextField]
+        {
+            auto host = hostTextField->property("text").toString().toStdString();
+            commandSender.setHost(host);
+        });
+
+    consumer.setOnEnablePlatoonChanged(
+        [&commandSender, &enablePlatoonCheckBox]
+        {
+            auto checked = enablePlatoonCheckBox->property("checked").toBool();
+            commandSender.enablePlatoon(checked);
+        });
+
+    consumer.setOnPlatoonSpeedChanged(
+        [&commandSender, &platoonSpeedTextField]
+        {
+            auto platoonSpeed = platoonSpeedTextField->property("text").toFloat();
+            commandSender.setPlatoonSpeed(platoonSpeed);
+        });
+
+    consumer.setOnInnerPlatoonDistanceChanged(
+        [&commandSender, &innerPlatoonDistanceTextField]
+        {
+            auto innerPlatoonDistance = innerPlatoonDistanceTextField->property("text").toFloat();
+            commandSender.setInnerPlatoonDistance(innerPlatoonDistance);
+        });
+
+    consumer.setOnSpeedChanged(
+        [&commandSender, &speedTextField]
+        {
+            auto speed = speedTextField->property("text").toFloat();
+            commandSender.setSpeed(speed);
+        });
+
+    return app.exec();
+}
diff --git a/modules/catkin_ws/src/PCGui/PCGui/src/MessageGui.cpp b/modules/catkin_ws/src/PCGui/PCGui/src/MessageGui.cpp
deleted file mode 100644
index 7dcf04af..00000000
--- a/modules/catkin_ws/src/PCGui/PCGui/src/MessageGui.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-#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();
-}
diff --git a/modules/catkin_ws/src/PCGui/PCGui/src/MessageGui/MessageGui.cpp b/modules/catkin_ws/src/PCGui/PCGui/src/MessageGui/MessageGui.cpp
new file mode 100644
index 00000000..4db67206
--- /dev/null
+++ b/modules/catkin_ws/src/PCGui/PCGui/src/MessageGui/MessageGui.cpp
@@ -0,0 +1,119 @@
+#include "include/QtQuickControlsApplication.h"
+#include "include/MessageGui/SortFilterProxyModel.h"
+#include <QtQml/qqmlapplicationengine.h>
+#include <QtGui/qsurfaceformat.h>
+#include <QtQml/qqml.h>
+#include <QtQml/QQmlContext>
+#include <include/MessageGui/MessageModel.h>
+#include "NetworkingLib/Networking.h"
+#include "MessageLib/Client.h"
+#include "include/MessageGui/SignalProducer.h"
+#include "include/MessageGui/SignalConsumer.h"
+#include <QDebug>
+#include "include/MessageGui/MostRecentMessageFiltertProxyModel.h"
+
+static int currId = 0;
+
+void registerTypes()
+{
+    qmlRegisterType<SortFilterProxyModel>("car.pcgui", 1, 0, "SortFilterProxyModel");
+    qmlRegisterType<MostRecentMessageFilterProxyModel>("car.pcgui", 1, 0, "MostRecentMessageFilterProxyModel");
+    qmlRegisterType<MessageModel>("car.pcgui", 1, 0, "MessageModel");
+    qRegisterMetaType<Message>();
+    qmlRegisterUncreatableType<MessageCollection>(
+        "car.pcgui", 1, 0, "MessageCollection", QStringLiteral("MessageCollection should not be created in QML"));
+    qmlRegisterUncreatableType<MessageList>(
+        "car.pcgui", 1, 0, "MessageList", QStringLiteral("MessageList should not be created in QML"));
+    qmlRegisterUncreatableType<SignalConsumer>(
+        "car.pcgui", 1, 0, "SignalConsumer", QStringLiteral("SignalConsumer should not be created in QML"));
+}
+
+void configureSurfaceFormat()
+{
+    if (QCoreApplication::arguments().contains(QLatin1String("--coreprofile")))
+    {
+        QSurfaceFormat fmt;
+        fmt.setVersion(4, 4);
+        fmt.setProfile(QSurfaceFormat::CoreProfile);
+        QSurfaceFormat::setDefaultFormat(fmt);
+    }
+}
+
+void requestMessages(message::Client::Ptr & messageClient,
+                     SignalProducer & producer,
+                     const std::string & host)
+{
+    using namespace std::chrono_literals;
+    messageClient->requestMessagesPeriodically(
+        host, 10ms, 3s,
+        [&producer](const auto & message)
+        {
+            producer.emitMessageProduced(Message{currId++, message});
+        },
+        [&producer](const auto & error)
+        {
+            if (error)
+                producer.emitDisconnected();
+            else
+                producer.emitConnected();
+        });
+}
+
+int main(int argc, char * argv[])
+{
+    networking::Networking net;
+    auto messageClient = message::Client::create(net, 10207);
+    MessageList messageList;
+    SignalProducer producer;
+    SignalConsumer consumer;
+
+    registerTypes();
+    QtQuickControlsApplication app{argc, argv};
+    configureSurfaceFormat();
+    QQmlApplicationEngine engine{};
+
+    engine.rootContext()->setContextProperty(QStringLiteral("messageList_"), &messageList);
+    engine.rootContext()->setContextProperty(QStringLiteral("consumer"), &consumer);
+
+    engine.load(QUrl("qrc:/MessageGui.qml"));
+    if (engine.rootObjects().isEmpty())
+        return -1;
+
+    auto root = engine.rootObjects()[0];
+    auto hostTextField = root->findChild<QObject *>("hostTextField");
+    auto connectButton = root->findChild<QObject *>("connectButton");
+    auto statusTextLabel = root->findChild<QObject *>("statusTextLabel");
+
+    QObject::connect(&producer, SIGNAL(messageProduced(Message)),
+                     &messageList, SLOT(insert(const Message &)));
+    QObject::connect(&producer, SIGNAL(connected()), &consumer, SLOT(showConnected()));
+    QObject::connect(&producer, SIGNAL(disconnected()), &consumer, SLOT(showDisconnected()));
+    QObject::connect(connectButton, SIGNAL(clicked()), &consumer, SLOT(doConnect()));
+
+    consumer.setOnShowConnected(
+        [statusTextLabel]
+        {
+            statusTextLabel->setProperty("text", QStringLiteral("Connected"));
+            statusTextLabel->setProperty("color", QStringLiteral("green"));
+        });
+
+    consumer.setOnShowDisconnected(
+        [statusTextLabel]
+        {
+            statusTextLabel->setProperty("text", QStringLiteral("Disconnected"));
+            statusTextLabel->setProperty("color", QStringLiteral("red"));
+        });
+
+    consumer.setOnDoConnect(
+        [hostTextField, &messageClient, &producer, &net]
+        {
+            auto host = hostTextField->property("text").toString().toStdString();
+            messageClient->stop();
+            net.waitWhileBusy(*messageClient);
+            requestMessages(messageClient, producer, host);
+        });
+
+    requestMessages(messageClient, producer, "127.0.0.1");
+
+    return app.exec();
+}
diff --git a/modules/catkin_ws/src/PCGui/PCGui/src/MessageGui/MessageList.cpp b/modules/catkin_ws/src/PCGui/PCGui/src/MessageGui/MessageList.cpp
new file mode 100644
index 00000000..770c9809
--- /dev/null
+++ b/modules/catkin_ws/src/PCGui/PCGui/src/MessageGui/MessageList.cpp
@@ -0,0 +1,33 @@
+//
+// Created by philipp on 13.05.18.
+//
+
+#include "include/MessageGui/MessageList.h"
+
+MessageList::MessageList(QObject * parent) : MessageCollection(parent)
+{
+}
+
+Message & MessageList::getItem(int index)
+{
+    return items[index];
+}
+
+int MessageList::getSize() const noexcept
+{
+    return items.size();
+}
+
+void MessageList::insert(const Message & message)
+{
+    emit preMessageInserted();
+    items.append(message);
+    emit postMessageInserted();
+}
+
+void MessageList::clear()
+{
+    emit preMessagesCleared();
+    items.clear();
+    emit postMessagesCleared();
+}
\ No newline at end of file
diff --git a/modules/catkin_ws/src/PCGui/PCGui/src/MessageGui/MessageModel.cpp b/modules/catkin_ws/src/PCGui/PCGui/src/MessageGui/MessageModel.cpp
new file mode 100644
index 00000000..c7b6ffc8
--- /dev/null
+++ b/modules/catkin_ws/src/PCGui/PCGui/src/MessageGui/MessageModel.cpp
@@ -0,0 +1,87 @@
+#include "include/MessageGui/MessageModel.h"
+#include "include/MessageGui/MessageRole.h"
+
+MessageModel::MessageModel(QObject * parent)
+    : QAbstractListModel(parent)
+      , messageCollection(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() || !messageCollection)
+        return 0;
+
+    return messageCollection->getSize();
+}
+
+QVariant MessageModel::data(const QModelIndex & index, int role) const
+{
+    if (!index.isValid() || !messageCollection)
+        return QVariant{};
+
+    auto message = messageCollection->getItem(index.row());
+    switch (role)
+    {
+        case messageRole::id:
+            return QVariant{message.id};
+
+        case messageRole::module:
+            return QVariant{QString::fromStdString(message.data.module)};
+
+        case messageRole::key:
+            return QVariant{QString::fromStdString(message.data.key)};
+
+        case messageRole::value:
+            return QVariant{QString::fromStdString(message.data.value)};
+    }
+
+    return QVariant{};
+}
+
+QHash<int, QByteArray> MessageModel::roleNames() const
+{
+    return messageRole::roleNames();
+}
+
+MessageCollection * MessageModel::getMessageCollection() const noexcept
+{
+    return messageCollection;
+}
+
+void MessageModel::setMessageCollection(MessageCollection * newMessageCollection)
+{
+    beginResetModel();
+
+    if (messageCollection)
+    {
+        messageCollection->disconnect(this);
+        removeRows(0, rowCount());
+    }
+
+    messageCollection = newMessageCollection;
+
+    if (messageCollection)
+    {
+        insertRows(0, messageCollection->getSize());
+
+        connect(messageCollection, &MessageCollection::preMessageInserted, this, [this]
+        {
+            int index = messageCollection->getSize();
+            beginInsertRows(QModelIndex{}, index, index);
+        });
+
+        connect(messageCollection, &MessageCollection::postMessageInserted, this, [this]
+        { endInsertRows(); });
+
+        connect(messageCollection, &MessageCollection::preMessagesCleared, this, [this]()
+        { beginRemoveRows(QModelIndex{}, 0, rowCount()); });
+
+        connect(messageCollection, &MessageCollection::postMessagesCleared, this, [this]
+        { endRemoveRows(); });
+    }
+
+    endResetModel();
+}
diff --git a/modules/catkin_ws/src/PCGui/PCGui/src/MessageGui/MostRecentMessageFilterProxyModel.cpp b/modules/catkin_ws/src/PCGui/PCGui/src/MessageGui/MostRecentMessageFilterProxyModel.cpp
new file mode 100644
index 00000000..e135b950
--- /dev/null
+++ b/modules/catkin_ws/src/PCGui/PCGui/src/MessageGui/MostRecentMessageFilterProxyModel.cpp
@@ -0,0 +1,103 @@
+//
+// Created by philipp on 15.05.18.
+//
+
+#include "include/MessageGui/MostRecentMessageFiltertProxyModel.h"
+#include "include/MessageGui/MessageRole.h"
+
+MostRecentMessageFilterProxyModel::MostRecentMessageFilterProxyModel(QObject * parent)
+    : QSortFilterProxyModel(parent)
+{
+    connect(this, SIGNAL(rowsInserted(QModelIndex, int, int)), this, SIGNAL(countChanged()));
+    connect(this, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SIGNAL(countChanged()));
+}
+
+QObject * MostRecentMessageFilterProxyModel::source() const
+{
+    return sourceModel();
+}
+
+void MostRecentMessageFilterProxyModel::setSource(QObject * source)
+{
+    beginResetModel();
+
+    if (this->source())
+        disconnect(this->source());
+
+    setSourceModel(qobject_cast<QAbstractItemModel *>(source));
+
+    connect(this, SIGNAL(rowsInserted(QModelIndex, int, int)),
+            this, SLOT(onRowsInserted(const QModelIndex &, int, int)));
+    connect(this, SIGNAL(rowsRemoved(QModelIndex, int, int)),
+            this, SLOT(onRowsRemoved(const QModelIndex &, int, int)));
+
+    endResetModel();
+}
+
+int MostRecentMessageFilterProxyModel::count() const
+{
+    return rowCount();
+}
+
+void MostRecentMessageFilterProxyModel::enable(bool flag)
+{
+    enabledFlag = flag;
+    invalidateFilter();
+}
+
+bool MostRecentMessageFilterProxyModel::enabled() const noexcept
+{
+    return enabledFlag;
+}
+
+QHash<int, QByteArray> MostRecentMessageFilterProxyModel::roleNames() const
+{
+    return messageRole::roleNames();
+}
+
+void MostRecentMessageFilterProxyModel::onRowsInserted(const QModelIndex & parent, int first, int last)
+{
+    for (int i = first; i <= last; i++)
+    {
+        auto key = messageKeyFromRow(i, parent);
+        mostRecent[key] = idFromRow(i, parent);
+    }
+    invalidateFilter();
+}
+
+#include <QDebug>
+
+void MostRecentMessageFilterProxyModel::onRowsRemoved(const QModelIndex & parent, int first, int last)
+{
+    for (int i = first; i <= last; i++)
+        qDebug() << "ID to remove: " << idFromRow(i, parent);
+}
+
+MessageKey MostRecentMessageFilterProxyModel::messageKeyFromRow(int row, const QModelIndex & parent) const
+{
+    auto model = sourceModel();
+    auto module = model->data(model->index(row, 0, parent), messageRole::module).toString().toStdString();
+    auto key = model->data(model->index(row, 0, parent), messageRole::key).toString().toStdString();
+    return MessageKey{module, key};
+}
+
+int MostRecentMessageFilterProxyModel::idFromRow(int row, const QModelIndex & parent) const
+{
+    auto model = sourceModel();
+    return model->data(model->index(row, 0, parent), messageRole::id).toInt();
+}
+
+bool MostRecentMessageFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const
+{
+    if (!enabled() || !sourceModel()->index(sourceRow, 0, sourceParent).isValid() ||
+        sourceRow < 0 || sourceRow >= rowCount())
+        return true;
+
+    auto key = messageKeyFromRow(sourceRow, sourceParent);
+    auto id = idFromRow(sourceRow, sourceParent);
+
+    if (id != mostRecent.at(key))
+        qDebug() << "ID not accepted: " << id;
+
+    return id == mostRecent.at(key);
+}
diff --git a/modules/catkin_ws/src/PCGui/PCGui/src/SortFilterProxyModel.cpp b/modules/catkin_ws/src/PCGui/PCGui/src/MessageGui/SortFilterProxyModel.cpp
similarity index 96%
rename from modules/catkin_ws/src/PCGui/PCGui/src/SortFilterProxyModel.cpp
rename to modules/catkin_ws/src/PCGui/PCGui/src/MessageGui/SortFilterProxyModel.cpp
index 4baa931f..5d688ef7 100644
--- a/modules/catkin_ws/src/PCGui/PCGui/src/SortFilterProxyModel.cpp
+++ b/modules/catkin_ws/src/PCGui/PCGui/src/MessageGui/SortFilterProxyModel.cpp
@@ -48,7 +48,7 @@
 **
 ****************************************************************************/
 
-#include "../include/SortFilterProxyModel.h"
+#include "include/MessageGui/SortFilterProxyModel.h"
 #include <QtDebug>
 #include <QtQml>
 
diff --git a/modules/catkin_ws/src/PCGui/PCGui/src/MessageList.cpp b/modules/catkin_ws/src/PCGui/PCGui/src/MessageList.cpp
deleted file mode 100644
index 9fc693b9..00000000
--- a/modules/catkin_ws/src/PCGui/PCGui/src/MessageList.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-//
-// 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();
-}
diff --git a/modules/catkin_ws/src/PCGui/PCGui/src/MessageModel.cpp b/modules/catkin_ws/src/PCGui/PCGui/src/MessageModel.cpp
deleted file mode 100644
index b305119a..00000000
--- a/modules/catkin_ws/src/PCGui/PCGui/src/MessageModel.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-#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();
-}
diff --git a/modules/catkin_ws/src/car/src/ultrasonic/Ultrasonic.cpp b/modules/catkin_ws/src/car/src/ultrasonic/Ultrasonic.cpp
index 847e7b17..4137e638 100644
--- a/modules/catkin_ws/src/car/src/ultrasonic/Ultrasonic.cpp
+++ b/modules/catkin_ws/src/car/src/ultrasonic/Ultrasonic.cpp
@@ -22,14 +22,16 @@ void Ultrasonic::onInit()
     messageOStream.write("onInit", "START");
 
     ussData = nh.advertise<ussDataMsg>("ussData", 1);
-    sensor.init();
+    //sensor.init();
     timer = networking::time::Timer::create(net);
     timer->startPeriodicTimeout(
         std::chrono::milliseconds(UltrasonicSensor::DELAY),
         [&]
         {
             ussDataMsg msg;
-            auto distance = streamMedianFilter.moveWindow(sensor.getDistance());
+            //auto distance = streamMedianFilter.moveWindow(sensor.getDistance());
+            static int distance = 0;
+            distance++;
             msg.distance = distance;
             msg.timestamp = ros::Time::now();
             ussData.publish(msg);
-- 
GitLab