Skip to content
Snippets Groups Projects
MemoryViewer.cpp 9.02 KiB
#include "MemoryViewer.h"

#include <RobotAPI/libraries/armem/core/ice_conversions.h>
#include <RobotAPI/libraries/armem_gui/gui_utils.h>

#include <ArmarXGui/libraries/SimpleConfigDialog/SimpleConfigDialog.h>

#include <ArmarXCore/core/ManagedIceObject.h>
#include <ArmarXCore/core/time/TimeUtil.h>
#include <ArmarXCore/observers/variant/Variant.h>

#include <SimoxUtility/algorithm/get_map_keys_values.h>

#include <QBoxLayout>
#include <QDialog>
#include <QCheckBox>
#include <QGroupBox>
#include <QLabel>
#include <QLayout>
#include <QSettings>


namespace armarx::armem::gui
{

    MemoryViewer::MemoryViewer(
        QBoxLayout* updateWidgetLayout,
        QGroupBox* _memoryGroupBox, QLayout* memoryGroupBoxParentLayout,
        QGroupBox* _instanceGroupBox, QLayout* instanceGroupBoxParentLayout,
        QLabel* statusLabel)
    {
        Logging::setTag("MemoryViewer");

        this->statusLabel = statusLabel;
        this->statusLabel->clear();

        // Update timer
        this->updateWidgetLayout = updateWidgetLayout;
        updateWidget = new armem::gui::PeriodicUpdateWidget(2.0, 60);
        updateWidgetLayout->insertWidget(0, updateWidget);

        memoryGroup = new armem::gui::MemoryGroupBox();
        armarx::gui::replaceWidget(_memoryGroupBox, memoryGroup, memoryGroupBoxParentLayout);
        ARMARX_CHECK_NULL(_memoryGroupBox);

        this->instanceGroup = new armem::gui::InstanceGroupBox();
        armarx::gui::replaceWidget(_instanceGroupBox, instanceGroup, instanceGroupBoxParentLayout);
        this->instanceGroup->setStatusLabel(statusLabel);
        ARMARX_CHECK_NULL(_instanceGroupBox);


        connect(this, &This::connected, this, &This::updateMemories);
        connect(updateWidget, &armem::gui::PeriodicUpdateWidget::update, this, &This::updateMemories);

        connect(this, &This::memoryDataChanged, this, &This::updateMemoryTree);
        connect(memoryGroup->tree(), &armem::gui::MemoryTreeWidget::selectedItemChanged, this, &This::updateInstanceTree);

        connect(memoryGroup->tree(), &armem::gui::MemoryTreeWidget::updated, this, &This::memoryTreeUpdated);
        connect(instanceGroup, &armem::gui::InstanceGroupBox::viewUpdated, this, &This::instanceTreeUpdated);
    }

    void MemoryViewer::setLogTag(const std::string& tag)
    {
        Logging::setTag(tag);
    }

    void MemoryViewer::onInit(ManagedIceObject& component)
    {
        if (mnsName.size() > 0)
        {
            component.usingProxy(mnsName);
        }
        if (debugObserverName.size() > 0)
        {
            component.usingProxy(debugObserverName);
        }

        emit initialized();
    }

    void MemoryViewer::onConnect(ManagedIceObject& component)
    {
        if (!mnsName.empty())
        {
            component.getProxy(mns, mnsName);
            auto res = mns->getAllRegisteredMemories();
            for (auto& [name, proxy] : res.proxies)
            {
                armem::client::Reader memoryReader{proxy};
                memoryReaders[name] = memoryReader;
            }
        }
        // DebugObserver is optional (check for null on every call)
        if (!debugObserverName.empty())
        {
            component.getProxy(debugObserver, debugObserverName, false, "", false);
        }
        updateWidget->startTimerIfEnabled();

        emit connected();
    }

    void MemoryViewer::onDisconnect(ManagedIceObject&)
    {
        updateWidget->stopTimer();

        emit disconnected();
    }


    void MemoryViewer::updateMemories()
    {
        memoryReaders.clear();
        memoryData.clear();

        for (auto& [name, proxy] : mns->getAllRegisteredMemories().proxies)
        {
            armem::client::Reader memoryReader{proxy};
            memoryReaders[name] = memoryReader;
        }

        bool dataChanged = false;

        for (auto& [name, reader] : memoryReaders)
        {
            TIMING_START(MemoryQuery);
            {
                armem::client::QueryInput input = memoryGroup->queryWidget()->queryInput();
                armem::client::QueryResult result = reader.query(input);
                if (result)
                {
                    memoryData[name] = std::move(result.memory);
                }
                else
                {
                    if (statusLabel)
                    {
                        statusLabel->setText(QString::fromStdString(result.errorMessage));
                    }
                }
            }
            TIMING_END_STREAM(MemoryQuery, ARMARX_VERBOSE);

            if (debugObserver)
            {
                debugObserver->setDebugDatafield(Logging::tag.tagName, "Memory Query [ms]", new Variant(MemoryQuery.toMilliSecondsDouble()));
            }

            if (memoryData[name])
            {
                dataChanged = true;
            }
            else
            {
                if (statusLabel)
                {
                    statusLabel->setText("No query result.");
                }
            }
        }

        if (dataChanged)
        {
            emit memoryDataChanged();
        }
    }


    void MemoryViewer::updateInstanceTree(const armem::MemoryID& selectedID)
    {
        if (memoryData.find(selectedID.memoryName) == memoryData.end())
        {
            std::stringstream ss;
            ss << "Memory name '" << selectedID.memoryName << "' is unknown. Known are: "
               << simox::alg::get_keys(memoryData);
            statusLabel->setText(QString::fromStdString(ss.str()));
            return;
        }

        const std::optional<armem::Memory>& data = memoryData.at(selectedID.memoryName);

        if (data)
        {
            if (!selectedID.hasEntityName())
            {
                return;
            }
            armem::MemoryID id = selectedID;
            const armem::EntitySnapshot* snapshot = nullptr;
            if (!id.hasTimestamp())
            {
                const armem::Entity& entity = data->getEntity(id);
                if (entity.empty())
                {
                    return;
                }
                snapshot = &entity.getLatestSnapshot();
                id.timestamp = snapshot->time();
            }
            if (!id.hasInstanceIndex())
            {
                if (!snapshot)
                {
                    try
                    {
                        snapshot = &data->getEntitySnapshot(id);
                    }
                    catch (const armem::error::ArMemError& e)
                    {
                        if (statusLabel)
                        {
                            statusLabel->setText(e.what());
                        }
                    }
                }
                if (snapshot && snapshot->size() > 0)
                {
                    id.instanceIndex = 0;
                }
            }
            if (id.hasInstanceIndex())
            {
                instanceGroup->view->update(id, *data);
            }
        }
    }

    void MemoryViewer::updateMemoryTree()
    {
        std::map<std::string, const armem::Memory*> convMap;
        for (auto& [name, data] : memoryData)
        {
            if (data.has_value())
            {
                convMap[name] = &data.value();
            }
        }

        if (convMap.empty())
        {
            return;
        }

        TIMING_START(GuiUpdate);
        memoryGroup->tree()->update(convMap);
        TIMING_END_STREAM(GuiUpdate, ARMARX_VERBOSE);

        if (debugObserver)
        {
            debugObserver->setDebugDatafield(Logging::tag.tagName, "GUI Update [ms]", new Variant(GuiUpdate.toMilliSecondsDouble()));
        }
    }


    const static std::string CONFIG_KEY_MEMORY = "MemoryViewer.MemoryNameSystem";
    const static std::string CONFIG_KEY_DEBUG_OBSERVER = "MemoryViewer.DebugObserverName";

    void MemoryViewer::loadSettings(QSettings* settings)
    {
        mnsName = settings->value(QString::fromStdString(CONFIG_KEY_MEMORY), "MemoryNameSystem").toString().toStdString();
        debugObserverName = settings->value(QString::fromStdString(CONFIG_KEY_DEBUG_OBSERVER), "DebugObserver").toString().toStdString();
    }
    void MemoryViewer::saveSettings(QSettings* settings)
    {
        settings->setValue(QString::fromStdString(CONFIG_KEY_MEMORY), QString::fromStdString(mnsName));
        settings->setValue(QString::fromStdString(CONFIG_KEY_DEBUG_OBSERVER), QString::fromStdString(debugObserverName));
    }

    void MemoryViewer::writeConfigDialog(SimpleConfigDialog* dialog)
    {
        dialog->addProxyFinder<armarx::armem::mns::MemoryNameSystemInterfacePrx>({CONFIG_KEY_MEMORY, "MemoryNameSystem", "*"});
        dialog->addProxyFinder<armarx::DebugObserverInterfacePrx>({CONFIG_KEY_DEBUG_OBSERVER, "Debug Observer", "DebugObserver"});
    }
    void MemoryViewer::readConfigDialog(SimpleConfigDialog* dialog)
    {
        mnsName = dialog->getProxyName(CONFIG_KEY_MEMORY);
        ARMARX_IMPORTANT << VAROUT(mnsName);
        if (mnsName.empty())
        {
            mnsName = "MemoryNameSystem";
        }
        ARMARX_IMPORTANT << VAROUT(mnsName);
        debugObserverName = dialog->getProxyName(CONFIG_KEY_DEBUG_OBSERVER);
    }

}