diff --git a/source/RobotAPI/interface/armem/server/StoringMemoryInterface.ice b/source/RobotAPI/interface/armem/server/StoringMemoryInterface.ice index 4e369bf259f24eccb36bcd1a2a58373da0fec442..0bd6de79cccc716b90e632876817a3256e22b7d2 100644 --- a/source/RobotAPI/interface/armem/server/StoringMemoryInterface.ice +++ b/source/RobotAPI/interface/armem/server/StoringMemoryInterface.ice @@ -12,6 +12,8 @@ module armarx interface StoringMemoryInterface { data::StoreResult store(data::StoreInput input); + void startRecording(); + void stopRecording(); }; }; }; diff --git a/source/RobotAPI/libraries/armem/client/Reader.cpp b/source/RobotAPI/libraries/armem/client/Reader.cpp index 9fb03536bbef6047d96baf6203893ad9cc9f78ed..e30917a78babed693c4ee06d31be30b5cad12e90 100644 --- a/source/RobotAPI/libraries/armem/client/Reader.cpp +++ b/source/RobotAPI/libraries/armem/client/Reader.cpp @@ -422,6 +422,32 @@ namespace armarx::armem::client } } + void Reader::startRecording() const + { + server::StoringMemoryInterfacePrx storingMemoryPrx = server::StoringMemoryInterfacePrx::checkedCast(readingPrx); + if (storingMemoryPrx) + { + return storingMemoryPrx->startRecording(); + } + else + { + ARMARX_WARNING << "Could not store a query into the LTM. It seems like the Memory does not implement the StoringMemoryInterface."; + } + } + + void Reader::stopRecording() const + { + server::StoringMemoryInterfacePrx storingMemoryPrx = server::StoringMemoryInterfacePrx::checkedCast(readingPrx); + if (storingMemoryPrx) + { + return storingMemoryPrx->stopRecording(); + } + else + { + ARMARX_WARNING << "Could not store a query into the LTM. It seems like the Memory does not implement the StoringMemoryInterface."; + } + } + void Reader::setReadingMemory(server::ReadingMemoryInterfacePrx readingMemory) diff --git a/source/RobotAPI/libraries/armem/client/Reader.h b/source/RobotAPI/libraries/armem/client/Reader.h index 7ecb453c845524edce1a217c49db671efbf3c9e7..e83996499a9c8bc81579a7036a47513f6e0720ae 100644 --- a/source/RobotAPI/libraries/armem/client/Reader.h +++ b/source/RobotAPI/libraries/armem/client/Reader.h @@ -162,8 +162,9 @@ namespace armarx::armem::client getAll(DataMode dataMode = DataMode::WithData) const; - //data::StoreResult readAndStore(data::StoreInputSeq& input); data::StoreResult readAndStore(const data::StoreInput& input) const; + void startRecording() const; + void stopRecording() const; /** * @brief Get a prediction for the state of multiple entity instances in the future. diff --git a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp index a10a398186c73734a841dbf3e40cf8db11987769..f706b90a8698556f3b2a0cb44d5f051042597bb0 100644 --- a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp +++ b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp @@ -335,7 +335,6 @@ namespace armarx::armem::server data::StoreResult MemoryToIceAdapter::store(const armem::data::StoreInput& input) { ARMARX_TRACE; - ARMARX_CHECK_NOT_NULL(workingMemory); ARMARX_CHECK_NOT_NULL(longtermMemory); data::StoreResult output; @@ -359,6 +358,22 @@ namespace armarx::armem::server return output; } + void MemoryToIceAdapter::startRecording() + { + ARMARX_TRACE; + ARMARX_CHECK_NOT_NULL(longtermMemory); + ARMARX_IMPORTANT << "ENABLING THE RECORDING OF MEMORY " << longtermMemory->id().str(); + longtermMemory->enabled = true; + } + + void MemoryToIceAdapter::stopRecording() + { + ARMARX_TRACE; + ARMARX_CHECK_NOT_NULL(longtermMemory); + ARMARX_IMPORTANT << "DISABLING THE RECORDING OF MEMORY " << longtermMemory->id().str(); + longtermMemory->enabled = false; + } + // PREDICTION prediction::data::EngineSupportMap MemoryToIceAdapter::getAvailableEngines() { diff --git a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.h b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.h index 96c1e822d6f4150c6e341bd5c0d234f57efec2b5..37fce327859f5b81bb9cfa0a7ff2a21e37e7043d 100644 --- a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.h +++ b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.h @@ -51,6 +51,8 @@ namespace armarx::armem::server // LTM STORING data::StoreResult store(const armem::data::StoreInput& input); + void startRecording(); + void stopRecording(); // PREDICTION prediction::data::EngineSupportMap getAvailableEngines(); diff --git a/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.cpp b/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.cpp index 44454b87d83b905edff8b925b0aa5831ffd8715e..7f3d8795691029c620232ecee220b4d31dda1baa 100644 --- a/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.cpp +++ b/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.cpp @@ -67,6 +67,16 @@ namespace armarx::armem::server::plugins ARMARX_TRACE; return iceAdapter().store(input); } + void ReadWritePluginUser::startRecording(const Ice::Current&) + { + ARMARX_TRACE; + return iceAdapter().startRecording(); + } + void ReadWritePluginUser::stopRecording(const Ice::Current&) + { + ARMARX_TRACE; + return iceAdapter().stopRecording(); + } Plugin& ReadWritePluginUser::memoryServerPlugin() diff --git a/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.h b/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.h index 8ddf174b172d4eb2fc4fba7f3e89d79553d72b42..db0f2596489265eeed8290b23179f52d2023a2f1 100644 --- a/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.h +++ b/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.h @@ -47,6 +47,8 @@ namespace armarx::armem::server::plugins // StoringInterface interface virtual data::StoreResult store(const data::StoreInput&, const Ice::Current& = Ice::emptyCurrent) override; + virtual void startRecording(const Ice::Current& = Ice::emptyCurrent) override; + virtual void stopRecording(const Ice::Current& = Ice::emptyCurrent) override; // ActionsInterface interface virtual armem::actions::GetActionsOutputSeq getActions(const armem::actions::GetActionsInputSeq& inputs); diff --git a/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp b/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp index bfe6a2b3ceb3bf52788cf009dd97ff40601d16a9..40abd0a585d7793a919207477928520a3b47bfb9 100644 --- a/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp +++ b/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp @@ -71,9 +71,9 @@ namespace armarx::armem::gui updateWidget = new armem::gui::PeriodicUpdateWidget(2.0, 60); updateWidgetLayout->insertWidget(0, updateWidget); - processQueryResultTimer = new QTimer(this); - processQueryResultTimer->setInterval(1000 / 60); // Keep this stable. - processQueryResultTimer->start(); + periodicUpdateTimer = new QTimer(this); + periodicUpdateTimer->setInterval(1000 / 60); // Keep this stable. + periodicUpdateTimer->start(); // Memory View auto retrieveEntityInfo = [this](const MemoryID& entityID) -> PredictionWidget::EntityInfo @@ -149,9 +149,14 @@ namespace armarx::armem::gui connect(this, &This::connected, this, &This::startQueries); connect(updateWidget, &armem::gui::PeriodicUpdateWidget::update, this, &This::startQueries); - connect(processQueryResultTimer, &QTimer::timeout, this, &This::processQueryResults); - connect(memoryGroup->queryWidget(), &armem::gui::QueryWidget::storeInLTM, this, &This::storeInLTM); + connect(periodicUpdateTimer, &QTimer::timeout, this, &This::updateAvailableMemories); + connect(periodicUpdateTimer, &QTimer::timeout, this, &This::processQueryResults); + + connect(memoryGroup->queryWidget(), &armem::gui::QueryWidget::storeInLTM, this, &This::queryAndStoreInLTM); + connect(memoryGroup->queryWidget(), &armem::gui::QueryWidget::startRecording, this, &This::startLTMRecording); + connect(memoryGroup->queryWidget(), &armem::gui::QueryWidget::stopRecording, this, &This::stopLTMRecording); + connect(memoryGroup->predictionWidget(), &armem::gui::PredictionWidget::makePrediction, this, @@ -269,12 +274,18 @@ namespace armarx::armem::gui void - MemoryViewer::storeInLTM() + MemoryViewer::queryAndStoreInLTM() { TIMING_START(MemoryStore); + auto enabledMemories = memoryGroup->queryWidget()->enabledMemories(); for (auto& [name, reader] : memoryReaders) { + // skip if memory should not be queried + if (std::find(enabledMemories.begin(), enabledMemories.end(), name) == enabledMemories.end()) + { + continue; + } data::StoreInput input; input.query = memoryGroup->queryInput().toIce(); reader.readAndStore(input); @@ -283,6 +294,44 @@ namespace armarx::armem::gui TIMING_END_STREAM(MemoryStore, ARMARX_VERBOSE); } + void + MemoryViewer::startLTMRecording() + { + TIMING_START(MemoryStartRecording); + + auto enabledMemories = memoryGroup->queryWidget()->enabledMemories(); + for (auto& [name, reader] : memoryReaders) + { + // skip if memory should not be queried + if (std::find(enabledMemories.begin(), enabledMemories.end(), name) == enabledMemories.end()) + { + continue; + } + reader.startRecording(); + } + + TIMING_END_STREAM(MemoryStartRecording, ARMARX_VERBOSE); + } + + void + MemoryViewer::stopLTMRecording() + { + TIMING_START(MemoryStopRecording); + + auto enabledMemories = memoryGroup->queryWidget()->enabledMemories(); + for (auto& [name, reader] : memoryReaders) + { + // skip if memory should not be queried + if (std::find(enabledMemories.begin(), enabledMemories.end(), name) == enabledMemories.end()) + { + continue; + } + reader.stopRecording(); + } + + TIMING_END_STREAM(MemoryStopRecording, ARMARX_VERBOSE); + } + void MemoryViewer::commit() { TIMING_START(Commit); @@ -418,8 +467,15 @@ namespace armarx::armem::gui // Can't use a structured binding here because you can't capture those in a lambda // according to the C++ standard. + auto enabledMemories = memoryGroup->queryWidget()->enabledMemories(); for (const auto& pair : readers) { + // skip if memory should not be queried + if (std::find(enabledMemories.begin(), enabledMemories.end(), pair.first) == enabledMemories.end()) + { + continue; + } + const auto& name = pair.first; const auto& reader = pair.second; if (queries.count(name) == 0) @@ -515,18 +571,40 @@ namespace armarx::armem::gui } } - // Drop all entries in memoryData which are not in memoryReaders anymore. + // Perhaps remove entries + auto enabledMemories = memoryGroup->queryWidget()->enabledMemories(); for (auto it = memoryData.begin(); it != memoryData.end();) { - auto name = it->second.name(); + // Drop all entries in memoryData which are not in memoryReaders anymore. if (memoryReaders.count(it->first) == 0) { - it = memoryData.erase(it); + if (memoryGroup->queryWidget()->dropRemovedMemories()) + { + it = memoryData.erase(it); + } + else + { + ++it; + } + continue; } - else + + // Drop all entries that are not enabled by user (which means that there is no query result) + if (std::find(enabledMemories.begin(), enabledMemories.end(), it->first) == enabledMemories.end()) { - ++it; + if (memoryGroup->queryWidget()->dropDisabledMemories()) + { + it = memoryData.erase(it); + } + else + { + ++it; + } + continue; } + + // Memory found + ++it; } TIMING_END_STREAM(tProcessQueryResults, ARMARX_VERBOSE) @@ -665,6 +743,34 @@ namespace armarx::armem::gui } + void + MemoryViewer::updateAvailableMemories() + { + if (mns) // mns must be initialized + { + try + { + std::vector<std::string> convVec; + memoryReaders = mns.getAllReaders(true); // we only need the readers + std::transform(memoryReaders.begin(), memoryReaders.end(), std::back_inserter(convVec), [](const auto& p){return p.first;}); + + TIMING_START(GuiUpdateAvailableMemories); + memoryGroup->queryWidget()->update(convVec); + TIMING_END_STREAM(GuiUpdateAvailableMemories, ARMARX_VERBOSE); + } + catch (const std::exception& e) + { + // MNS was killed/stopped + // ignore?! + } + } + else + { + ARMARX_VERBOSE << deactivateSpam() << "MNS not ready yet. Skip update of available memories in query widget."; + } + } + + void MemoryViewer::updateMemoryTree() { @@ -674,9 +780,9 @@ namespace armarx::armem::gui convMap[name] = &data; } - TIMING_START(GuiUpdate) + TIMING_START(GuiUpdateMemoryTree) memoryGroup->tree()->update(convMap); - TIMING_END_STREAM(GuiUpdate, ARMARX_VERBOSE) + TIMING_END_STREAM(GuiUpdateMemoryTree, ARMARX_VERBOSE) if (debugObserver) { @@ -684,7 +790,7 @@ namespace armarx::armem::gui { debugObserver->setDebugDatafield(Logging::tag.tagName, "GUI Update [ms]", - new Variant(GuiUpdate.toMilliSecondsDouble())); + new Variant(GuiUpdateMemoryTree.toMilliSecondsDouble())); } catch (const Ice::Exception&) { diff --git a/source/RobotAPI/libraries/armem_gui/MemoryViewer.h b/source/RobotAPI/libraries/armem_gui/MemoryViewer.h index 34562204b070f763084b6d0d0a2946b99b2b8dc0..8cc41498c27cb0b88fd60f238a2202fc3cfc2d12 100644 --- a/source/RobotAPI/libraries/armem_gui/MemoryViewer.h +++ b/source/RobotAPI/libraries/armem_gui/MemoryViewer.h @@ -85,7 +85,10 @@ namespace armarx::armem::gui void storeOnDisk(QString directory); void loadFromDisk(QString directory); - void storeInLTM(); + void queryAndStoreInLTM(); + void startLTMRecording(); + void stopLTMRecording(); + void commit(); @@ -106,6 +109,7 @@ namespace armarx::armem::gui void processQueryResults(); void updateMemoryTree(); + void updateAvailableMemories(); signals: @@ -149,8 +153,9 @@ namespace armarx::armem::gui std::map<std::string, armem::wm::Memory> memoryData; std::map<std::string, std::future<armem::query::data::Result>> runningQueries; - /// Periodically triggers query result collection. - QTimer* processQueryResultTimer; + + /// Periodically triggers query result collection and updates the available memories + QTimer* periodicUpdateTimer; QLayout* updateWidgetLayout = nullptr; diff --git a/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.cpp b/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.cpp index d8755bbfd2e640842b4342c55330a761ce8a362d..fe443952ce26bf9546c9238eaf1fa234f13368f6 100644 --- a/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.cpp +++ b/source/RobotAPI/libraries/armem_gui/disk/ControlWidget.cpp @@ -24,7 +24,7 @@ namespace armarx::armem::gui::disk _loadFromDiskButton = new QPushButton(" Load Query from Disk into WM", this); _loadFromDiskButton->setIcon(QIcon(":/icons/document-open.svg")); - _storeOnDiskButton = new QPushButton(" Store Query from WM on Disk", this); + _storeOnDiskButton = new QPushButton(" Store shown Data on Disk", this); _storeOnDiskButton->setIcon(QIcon(":/icons/document-save.svg")); // Allow horizontal shrinking of buttons diff --git a/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.cpp b/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.cpp index ad07dc5b0de991b1e3296a94c66418caa20bf011..f5645fb2e48efb6ea28ac9e45c8701414633db32 100644 --- a/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.cpp +++ b/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.cpp @@ -1,6 +1,7 @@ #include "QueryWidget.h" #include <limits> +#include <mutex> #include <QCheckBox> #include <QGroupBox> @@ -11,6 +12,7 @@ #include <QTabWidget> #include <QVBoxLayout> #include <QWidget> +#include <QScrollArea> #include <ArmarXCore/core/exceptions/local/ExpressionException.h> @@ -21,38 +23,131 @@ namespace armarx::armem::gui QueryWidget::QueryWidget() { auto* vlayout = new QVBoxLayout(); + auto* hlayout = new QHBoxLayout(); - _dataCheckBox = new QCheckBox("Get Data"); - _dataCheckBox->setChecked(true); - vlayout->addWidget(_dataCheckBox); - - auto* recDepthHLayout = new QHBoxLayout(); - vlayout->addLayout(recDepthHLayout); - - _recursionDepthSpinner = new QSpinBox(); // NOLINT - _recursionDepthSpinner->setRange(-1, std::numeric_limits<int>::max()); - _recursionDepthSpinner->setValue(0); - _recursionDepthSpinner->setEnabled(_dataCheckBox->isChecked()); - _recursionDepthSpinner->setSpecialValueText(QString("Unlimited")); - recDepthHLayout->addWidget(_recursionDepthSpinner); + { + _availableMemoriesGroupBox = new QGroupBox("Available memories"); + auto vboxlayout = new QVBoxLayout(); + vboxlayout->setMargin(1); + vboxlayout->setSizeConstraint(QLayout::SizeConstraint::SetMinAndMaxSize); + vboxlayout->setAlignment(Qt::AlignTop); + _availableMemoriesGroupBox->setLayout(vboxlayout); + hlayout->addWidget(_availableMemoriesGroupBox); + } - _recursionDepthLabel = new QLabel("Link resolution depth"); - recDepthHLayout->addWidget(_recursionDepthLabel); - recDepthHLayout->addStretch(); + QFrame* vFrame = new QFrame; + vFrame->setFrameShape(QFrame::VLine); + hlayout->addWidget(vFrame); - _storeInLTMButton = new QPushButton("Store query result in LTM"); - vlayout->addWidget(_storeInLTMButton); + { + _additionalSettingsGroupBox = new QGroupBox("Additional query settings"); + auto vboxlayout = new QVBoxLayout(); + vboxlayout->setMargin(1); + vboxlayout->setSizeConstraint(QLayout::SizeConstraint::SetMinAndMaxSize); + vboxlayout->setAlignment(Qt::AlignTop); + _additionalSettingsGroupBox->setLayout(vboxlayout); + + _dataCheckBox = new QCheckBox("Get Data"); + _dataCheckBox->setChecked(true); + vboxlayout->addWidget(_dataCheckBox); + + _dropRemovedCheckBox = new QCheckBox("Drop disconnected memories"); + _dropRemovedCheckBox->setChecked(true); + vboxlayout->addWidget(_dropRemovedCheckBox); + + _dropDisabledCheckBox = new QCheckBox("Drop disabled memories"); + _dropDisabledCheckBox->setChecked(false); + vboxlayout->addWidget(_dropDisabledCheckBox); + + auto* recDepthHLayout = new QHBoxLayout(); + _recursionDepthSpinner = new QSpinBox(); // NOLINT + _recursionDepthSpinner->setRange(-1, std::numeric_limits<int>::max()); + _recursionDepthSpinner->setValue(0); + _recursionDepthSpinner->setEnabled(_dataCheckBox->isChecked()); + _recursionDepthSpinner->setSpecialValueText(QString("Unlimited")); + recDepthHLayout->addWidget(_recursionDepthSpinner); + + _recursionDepthLabel = new QLabel("Link resolution depth"); + recDepthHLayout->addWidget(_recursionDepthLabel); + recDepthHLayout->addStretch(); + vboxlayout->addLayout(recDepthHLayout); + + auto ltmButtonsLayout = new QVBoxLayout(); + _storeInLTMButton = new QPushButton("Query and store in LTM"); + ltmButtonsLayout->addWidget(_storeInLTMButton); + + auto* ltmRecHLayout = new QHBoxLayout(); + _startLTMRecordingButton = new QPushButton("Start LTM Recording"); + _stopLTMRecordingButton = new QPushButton("Stop LTM Recording"); + + ltmRecHLayout->addWidget(_startLTMRecordingButton); + ltmRecHLayout->addWidget(_stopLTMRecordingButton); + ltmButtonsLayout->addLayout(ltmRecHLayout); + + vboxlayout->addLayout(ltmButtonsLayout); + + hlayout->addWidget(_additionalSettingsGroupBox); + } + vlayout->addLayout(hlayout); // Public connections. connect(_storeInLTMButton, &QPushButton::pressed, this, &This::storeInLTM); + connect(_startLTMRecordingButton, &QPushButton::pressed, this, &This::startRecording); + connect(_stopLTMRecordingButton, &QPushButton::pressed, this, &This::stopRecording); // Private connections. - connect( - _dataCheckBox, &QCheckBox::stateChanged, this, &This::setRecursionDepthSpinnerEnabled); + connect(_dataCheckBox, &QCheckBox::stateChanged, this, &This::setRecursionDepthSpinnerEnabled); setLayout(vlayout); } + void QueryWidget::update(const std::vector<std::string>& activeMemoryNames) + { + // since this is the only method that adds or hides elements of the groupbox after initialization, + // we can use a static mutex, only available to this method + //static std::mutex m; + + //std::scoped_lock l(m); + std::vector<std::string> alreadyPresentMemoryCheckboxes; + + // get information about memories already present and activate inactive ones if necessary + int maxIndex = _availableMemoriesGroupBox->layout()->count(); + for (int i = 0; i < maxIndex; ++i) + { + auto w = _availableMemoriesGroupBox->layout()->itemAt(i)->widget(); + QCheckBox* box = static_cast<QCheckBox*>(w); + std::string memoryName = box->text().toStdString(); + if (box->isEnabled() && std::find(activeMemoryNames.begin(), activeMemoryNames.end(), memoryName) == activeMemoryNames.end()) + { + // checkbox is enabled but memory is not available anymore + box->setVisible(false); + box->setChecked(false); + box->setEnabled(false); + } + if (not(box->isEnabled()) && std::find(activeMemoryNames.begin(), activeMemoryNames.end(), memoryName) != activeMemoryNames.end()) + { + // checkbox is disabled but memory is available again + box->setVisible(true); + box->setChecked(true); + box->setEnabled(true); + } + alreadyPresentMemoryCheckboxes.push_back(memoryName); + } + + // Add checkboxes for new memories + for (const auto& memoryName : activeMemoryNames) + { + if (std::find(alreadyPresentMemoryCheckboxes.begin(), alreadyPresentMemoryCheckboxes.end(), memoryName) == alreadyPresentMemoryCheckboxes.end()) + { + // new memory available + auto box = new QCheckBox(QString::fromStdString(memoryName)); + box->setChecked(true); + box->setVisible(true); + box->setEnabled(true); + _availableMemoriesGroupBox->layout()->addWidget(box); + } + } + } armem::DataMode QueryWidget::dataMode() const { @@ -61,6 +156,35 @@ namespace armarx::armem::gui : armem::DataMode::NoData; } + bool QueryWidget::dropRemovedMemories() const + { + return _dropRemovedCheckBox->isChecked(); + } + + bool QueryWidget::dropDisabledMemories() const + { + return _dropDisabledCheckBox->isChecked(); + } + + + std::vector<std::string> QueryWidget::enabledMemories() const + { + std::vector<std::string> enabledMemoryCheckboxes; + int maxIndex = _availableMemoriesGroupBox->layout()->count(); + for (int i = 0; i < maxIndex; ++i) + { + auto w = _availableMemoriesGroupBox->layout()->itemAt(i)->widget(); + QCheckBox* box = static_cast<QCheckBox*>(w); + std::string memoryName = box->text().toStdString(); + if (box->isEnabled() && box->isChecked()) + { + // Invisible ones are always unchecked if set to invisible from update method + enabledMemoryCheckboxes.push_back(memoryName); + } + } + return enabledMemoryCheckboxes; + } + int QueryWidget::queryLinkRecursionDepth() const { return _recursionDepthSpinner->value(); diff --git a/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.h b/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.h index e7a98a8026786a7c8e0c2acbfd8dc834cb72f16a..4988e5d6795e348a7c12a0d30bb4388be194dfe6 100644 --- a/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.h +++ b/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.h @@ -8,6 +8,7 @@ class QWidget; class QTabWidget; class QPushButton; +class QGroupBox; namespace armarx::armem::gui { @@ -23,13 +24,22 @@ namespace armarx::armem::gui armem::DataMode dataMode() const; + bool dropRemovedMemories() const; + bool dropDisabledMemories() const; + int queryLinkRecursionDepth() const; + std::vector<std::string> enabledMemories() const; + + void update(const std::vector<std::string>& memoryNames); + public slots: signals: void storeInLTM(); + void startRecording(); + void stopRecording(); // ToDo: // void queryChanged(armem::query::data::Input query); @@ -45,10 +55,19 @@ namespace armarx::armem::gui private: QCheckBox* _dataCheckBox; + + QCheckBox* _dropRemovedCheckBox; + QCheckBox* _dropDisabledCheckBox; + QLabel* _recursionDepthLabel; QSpinBox* _recursionDepthSpinner; + QPushButton* _storeInLTMButton; + QPushButton* _startLTMRecordingButton; + QPushButton* _stopLTMRecordingButton; + QGroupBox* _additionalSettingsGroupBox; + QGroupBox* _availableMemoriesGroupBox; }; } diff --git a/source/RobotAPI/libraries/armem_gui/query_widgets/SnapshotSelectorWidget.cpp b/source/RobotAPI/libraries/armem_gui/query_widgets/SnapshotSelectorWidget.cpp index 6b38efdddb30e67d1abfb3190d88508dff72258a..1d8c4ecadd7b482e523730370afbe95ad7cb9664 100644 --- a/source/RobotAPI/libraries/armem_gui/query_widgets/SnapshotSelectorWidget.cpp +++ b/source/RobotAPI/libraries/armem_gui/query_widgets/SnapshotSelectorWidget.cpp @@ -4,6 +4,7 @@ #include <QComboBox> #include <QHBoxLayout> #include <QVBoxLayout> +#include <QPushButton> #include <ArmarXCore/core/exceptions/local/ExpressionException.h> @@ -69,7 +70,6 @@ namespace armarx::armem::gui _WMQueryTargetCheckBox->setChecked(true); typeLayout->addLayout(queryTargetLayout); - _pageLayout->addLayout(typeLayout); } diff --git a/source/RobotAPI/libraries/armem_gui/query_widgets/SnapshotSelectorWidget.h b/source/RobotAPI/libraries/armem_gui/query_widgets/SnapshotSelectorWidget.h index e7ec233c896133beb1b675baf37e2d0e2f53489c..d57cf80fd8e6fb39b14de646c175bae9cc29992b 100644 --- a/source/RobotAPI/libraries/armem_gui/query_widgets/SnapshotSelectorWidget.h +++ b/source/RobotAPI/libraries/armem_gui/query_widgets/SnapshotSelectorWidget.h @@ -13,6 +13,7 @@ class QCheckBox; class QComboBox; class QVBoxLayout; +class QPushButton; namespace armarx::armem::gui