Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set/reset the world modified flag and 'DEF' fields #6686

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
18 changes: 11 additions & 7 deletions src/webots/nodes/utils/WbWorld.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,17 +225,21 @@ bool WbWorld::needSaving() const {
}

void WbWorld::setModifiedFromSceneTree() {
if (!mIsModifiedFromSceneTree) {
mIsModifiedFromSceneTree = true;
setModified();
mIsModifiedFromSceneTree = true;

if (isModifiedFromSceneTreeRestarted) {
mIsModifiedFromSceneTree = false;
isModifiedFromSceneTreeRestarted = false;
}
}

void WbWorld::resetModifiedFromSceneTree() {
mIsModifiedFromSceneTree = false;
isModifiedFromSceneTreeRestarted = true;
}

void WbWorld::setModified(bool isModified) {
if (mIsModified != isModified) {
mIsModified = isModified;
emit modificationChanged(isModified);
}
emit checkDefDiff();
}

bool WbWorld::saveAs(const QString &fileName) {
Expand Down
3 changes: 3 additions & 0 deletions src/webots/nodes/utils/WbWorld.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,12 +158,14 @@ class WbWorld : public QObject {
void robotAdded(WbRobot *robot);
void robotRemoved(WbRobot *robot);
void resetRequested(bool restartControllers);
void checkDefDiff();

public slots:
void awake();
void updateVideoRecordingStatus(int status) {
mIsVideoRecording = (status == WB_SUPERVISOR_MOVIE_RECORDING || status == WB_SUPERVISOR_MOVIE_SAVING);
}
void resetModifiedFromSceneTree();

protected:
// collecting contact and immersion geometries
Expand Down Expand Up @@ -199,6 +201,7 @@ protected slots:
bool mIsLoading;
bool mIsCleaning;
bool mIsVideoRecording;
bool isModifiedFromSceneTreeRestarted = false;

void checkPresenceOfMandatoryNodes();
WbNode *findTopLevelNode(const QString &modelName, int preferredPosition) const;
Expand Down
13 changes: 12 additions & 1 deletion src/webots/scene_tree/WbFieldEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,18 @@ WbFieldEditor::WbFieldEditor(QWidget *parent) :
WbNodePane *const nodePane = new WbNodePane(this);
const WbNodeEditor *nodeEditor = nodePane->nodeEditor();
connect(nodeEditor, &WbNodeEditor::dictionaryUpdateRequested, this, &WbFieldEditor::dictionaryUpdateRequested);

connect(nodeEditor, &WbNodeEditor::defNameChanged, WbActionManager::instance()->action(WbAction::SAVE_WORLD),
&QAction::setEnabled);
connect(WbActionManager::instance()->action(WbAction::SAVE_WORLD), &QAction::setEnabled, nodeEditor,
&WbNodeEditor::resetDefNamesToInitial);
connect(WbActionManager::instance()->action(WbAction::SAVE_WORLD_AS), &QAction::setEnabled, nodeEditor,
&WbNodeEditor::resetDefNamesToInitial);
connect(WbActionManager::instance()->action(WbAction::SAVE_WORLD), &QAction::triggered, nodeEditor,
&WbNodeEditor::switchInitialCurrentDef);
connect(WbActionManager::instance()->action(WbAction::SAVE_WORLD_AS), &QAction::triggered, nodeEditor,
&WbNodeEditor::switchInitialCurrentDef);
connect(WbActionManager::instance()->action(WbAction::RELOAD_WORLD), &QAction::triggered, nodeEditor,
&WbNodeEditor::startTimer);
// create editors
mEditors.insert(WB_NO_FIELD, new WbEmptyEditor(this));
mEditors.insert(WB_SF_BOOL, new WbBoolEditor(this));
Expand Down
103 changes: 103 additions & 0 deletions src/webots/scene_tree/WbNodeEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "WbNodeEditor.hpp"

#include "WbActionManager.hpp"
#include "WbBaseNode.hpp"
#include "WbField.hpp"
#include "WbFieldLineEdit.hpp"
Expand All @@ -32,9 +33,11 @@
#include "WbTransform.hpp"
#include "WbViewpoint.hpp"
#include "WbVrmlNodeUtilities.hpp"
#include "WbWorld.hpp"
#include "WbWorldInfo.hpp"

#include <QtCore/QDir>
#include <QtCore/QTimer>
#include <QtWidgets/QCheckBox>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QFileDialog>
Expand All @@ -52,6 +55,7 @@ WbNodeEditor::WbNodeEditor(QWidget *parent) :
mNbTriangles(new QLabel(this)),
mStackedWidget(new QStackedWidget(this)),
mMessageBox(false),
worldCheckTimer(new QTimer(this)),
mShowResizeHandlesLabel(new QLabel(tr("3D tools:"), this)),
mShowResizeHandlesCheckBox(new QCheckBox(tr("show resize handles"), this)) {
mShowResizeHandlesCheckBox->setChecked(false);
Expand Down Expand Up @@ -87,6 +91,25 @@ WbNodeEditor::WbNodeEditor(QWidget *parent) :
connect(mPrintUrl, &QPushButton::pressed, this, &WbNodeEditor::printUrl);
connect(mShowResizeHandlesCheckBox, &QAbstractButton::toggled, WbSelection::instance(),
&WbSelection::showResizeManipulatorFromSceneTree, Qt::UniqueConnection);
connect(worldCheckTimer, &QTimer::timeout, this, &WbNodeEditor::tryConnectToWorld);
worldCheckTimer->start(500);
}

void WbNodeEditor::tryConnectToWorld() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot have a timer here, we need a cleaner solution

world = WbWorld::instance();
state = WbSimulationState::instance();
if (oldWorld != world) {
connect(world, &WbWorld::checkDefDiff, this, &WbNodeEditor::resetDefNamesToInitial);
connect(this, &WbNodeEditor::resetModifiedFromSceneTree, world, &WbWorld::resetModifiedFromSceneTree);
oldWorld = const_cast<WbWorld *>(world);
mInitialCurrentDefMap.clear();
worldCheckTimer->stop();
}
}

void WbNodeEditor::startTimer() {
disconnect(world, &WbWorld::checkDefDiff, this, &WbNodeEditor::resetDefNamesToInitial);
worldCheckTimer->start(500);
}

void WbNodeEditor::printUrl() {
Expand Down Expand Up @@ -131,6 +154,9 @@ void WbNodeEditor::edit(bool copyOriginalValue) {
mShowResizeHandlesCheckBox->setChecked(g->isResizeManipulatorAttached());
}
}

if (mNode && !mInitialCurrentDefMap.contains(mNode))
mInitialCurrentDefMap[mNode] = QPair<QString, QString>(mNode->defName(), QString());
}

update();
Expand Down Expand Up @@ -198,6 +224,12 @@ void WbNodeEditor::apply() {
QString newDef = mDefEdit->text();
const QString &previousDef = mNode->defName();

mInitialCurrentDefMap[mNode].second = newDef;

bool hasStarted = state->hasStarted();
if (!hasStarted)
this->compareInitialCurrentDef();

if (newDef == previousDef)
return;

Expand Down Expand Up @@ -259,3 +291,74 @@ void WbNodeEditor::apply() {
if (dictionaryUpdateRequest)
emit dictionaryUpdateRequested();
}

void WbNodeEditor::compareInitialCurrentDef() {
if (!mInitialCurrentDefMap.isEmpty()) {
bool foundDifference = false;
// Iterate through the QMap
for (auto it = mInitialCurrentDefMap.constBegin(); it != mInitialCurrentDefMap.constEnd(); ++it) {
const QString &initialDef = it.value().first; // First QString (initial)
const QString &currentDef = it.value().second; // Second QString (current)

// Compare the two QStrings
if (initialDef != currentDef) {
foundDifference = true; // Mark that a difference is found
break;
}
}
if (foundDifference)
emit defNameChanged(true); // Emit true if any difference is found
else {
emit resetModifiedFromSceneTree();
emit defNameChanged(false); // Emit false if no differences were found
}
} else
emit defNameChanged(false); // If all QStrings are the same, return false
}

void WbNodeEditor::resetDefNamesToInitial() {
// Check if the map is empty
if (mInitialCurrentDefMap.isEmpty()) {
emit defNameChanged(false);
return;
}

// Iterate through the map and reset each node's DEF name to its initial value
for (auto it = mInitialCurrentDefMap.begin(); it != mInitialCurrentDefMap.end(); ++it) {
WbNode *node = it.key();
const QString &initialDef = it.value().first; // Access initial DEF name

// Only reset if node exists and the current DEF differs from the initial one
if (node && node->defName() != initialDef)
node->setDefName(initialDef); // Set the DEF name back to the initial one
}

update();

emit defNameChanged(false);
emit resetModifiedFromSceneTree();
}

void WbNodeEditor::switchInitialCurrentDef() {
// Check if the map is empty
if (mInitialCurrentDefMap.isEmpty()) {
emit defNameChanged(false);
return;
}

// Iterate through the map and switch the initial DEF to the current one
for (auto it = mInitialCurrentDefMap.begin(); it != mInitialCurrentDefMap.end(); ++it) {
const WbNode *node = it.key();

// Switch the initial DEF to the current DEF
if (node) {
QString &initialDef = it.value().first; // Reference to initial DEF name
const QString &currentDef = node->defName(); // Get the current DEF name of the node
initialDef = currentDef; // Update the initial DEF with the current one
}
}

update();

emit defNameChanged(false);
}
14 changes: 14 additions & 0 deletions src/webots/scene_tree/WbNodeEditor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
// Description: editor for editing a WbSFNode or a WbMFNode item
//

#include "WbSimulationState.hpp"
#include "WbValueEditor.hpp"
#include "WbWorld.hpp"

class WbFieldLineEdit;
class WbNode;
Expand Down Expand Up @@ -47,10 +49,15 @@ class WbNodeEditor : public WbValueEditor {

signals:
void dictionaryUpdateRequested();
void defNameChanged(bool changed);
void resetModifiedFromSceneTree();

public slots:
void apply() override;
void cleanValue() override;
void resetDefNamesToInitial();
void switchInitialCurrentDef();
void startTimer();

protected:
enum PaneType { DEF_PANE, EMPTY_PANE };
Expand All @@ -63,6 +70,11 @@ public slots:
QLabel *mNbTriangles;
QStackedWidget *mStackedWidget;
bool mMessageBox;
QMap<WbNode *, QPair<QString, QString>> mInitialCurrentDefMap;
QTimer *worldCheckTimer;
const WbWorld *world = nullptr;
WbWorld *oldWorld = nullptr;
WbSimulationState *state = nullptr;

// actions buttons
QLabel *mShowResizeHandlesLabel;
Expand All @@ -71,6 +83,8 @@ public slots:
void setTransformActionVisibile(bool visible);
void takeKeyboardFocus() override {}
void printUrl();
void tryConnectToWorld();
void compareInitialCurrentDef();
};

#endif
Loading