Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
it returns only the modules that are part of the data model of the current project. - #630
- Fixed a crash when creating a calculator with missing author information in a Python Task - #627

### Changed
- Python Task and Calculator wizards now automatically transfer changes from the editor to
the corresponding data model object whenever the wizard loses focus or is closed.
- Removed the `Save` and `Cancel` buttons as well as the "Do you want to save..." message box,
since manual saving is no longer required. All changes can be undone via GTlab's Undo/Redo system. - #86
- The script editor in the wizard now updates automatically when Undo/Redo is performed in the main GUI.

## [1.8.0] - 2025-07-11

### Fixed
Expand Down
6 changes: 6 additions & 0 deletions src/module/processcomponents/gtpy_abstractscriptcomponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,12 @@ GtpyAbstractScriptComponent::outputArg(const QString& argName) const
}
#endif

const GtStringProperty&
GtpyAbstractScriptComponent::scriptProp() const
{
return m_script;
}

bool
GtpyAbstractScriptComponent::evalScript(int contextId)
{
Expand Down
6 changes: 6 additions & 0 deletions src/module/processcomponents/gtpy_abstractscriptcomponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ class GtpyAbstractScriptComponent
QVariant outputArg(const QString& argName) const;
#endif

/**
* @brief Returns the script property.
* @return Constant reference to the script property.
*/
const GtStringProperty& scriptProp() const;

protected:
/**
* @brief GtpyComponentAssistant
Expand Down
195 changes: 52 additions & 143 deletions src/module/wizards/gtpy_abstractscriptingwizardpage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@
#include "gtpy_editorsettingsdialog.h"
#include "gtpy_packageiteration.h"
#include "gtpy_transfer.h"
#include "gtpy_abstractscriptcomponent.h"

// GTlab framework includes
#include "gt_object.h"
#include "gt_project.h"
#include "gt_datamodel.h"
#include "gt_filedialog.h"
#include "gt_saveprojectmessagebox.h"

#include "gt_pyhighlighter.h"
#include "gt_searchwidget.h"
Expand All @@ -57,7 +57,6 @@ GtpyAbstractScriptingWizardPage::GtpyAbstractScriptingWizardPage(
m_editorSettings(nullptr),
m_isEvaluating(false),
m_runnable(nullptr),
m_savingEnabled(true),
m_componentUuid(QString())
{
setTitle(tr("Python Script Editor"));
Expand Down Expand Up @@ -156,7 +155,6 @@ GtpyAbstractScriptingWizardPage::GtpyAbstractScriptingWizardPage(
fontClearOutput.setItalic(true);
fontClearOutput.setPointSize(7);
shortCutClearOutput->setFont(fontClearOutput);
shortCutClearOutput->installEventFilter(this);

QVBoxLayout* clearButtonLay = new QVBoxLayout;

Expand Down Expand Up @@ -185,25 +183,6 @@ GtpyAbstractScriptingWizardPage::GtpyAbstractScriptingWizardPage(

toolBarLayout->addStretch(1);

//Save Button
m_shortCutSave = new QLabel("<font color='grey'> Ctrl+S</font>");
QFont fontSave = m_shortCutSave->font();
fontSave.setItalic(true);
fontSave.setPointSize(7);
m_shortCutSave->setFont(fontSave);

m_saveButton = new QPushButton;
m_saveButton->setIcon(GTPY_ICON(save));
m_saveButton->setToolTip(tr("Save Script"));

QVBoxLayout* saveButtonLay = new QVBoxLayout;
saveButtonLay->addWidget(m_saveButton);
saveButtonLay->addWidget(m_shortCutSave);

toolBarLayout->addLayout(saveButtonLay);

enableSaveButton(false);

//Import Button
QLabel* shortCutImport = new QLabel("<font color='grey'></font>");
QFont fontImport = shortCutImport->font();
Expand Down Expand Up @@ -311,12 +290,11 @@ void
GtpyAbstractScriptingWizardPage::initializePage()
{
// we want to react, when the wizard should be closed
if (wizard()) wizard()->installEventFilter(this);

/// Can not be connected in the constructor because onSaveButtonClicked()
/// calls the pure virtual function saveScript()
connect(m_saveButton, SIGNAL(clicked(bool)), this,
SLOT(onSaveButtonClicked()));
if (auto* wiz = wizard())
{
wiz->setOption(QWizard::NoCancelButton, true);
wiz->installEventFilter(this);
}

setWizardNonModal();

Expand All @@ -332,20 +310,22 @@ GtpyAbstractScriptingWizardPage::initializePage()

loadPackages();

GtObject* component = gtDataModel->objectByUuid(m_componentUuid);
GtObject* obj = gtDataModel->objectByUuid(m_componentUuid);
if (!obj) return;

if (!component)
{
enableSaving(false);
}
else
{
setTitle(component->objectName());
connect(component, SIGNAL(objectNameChanged(QString)), this,
SLOT(componentRenamed(QString)));
}
setTitle(obj->objectName());

connect(obj, &GtObject::objectNameChanged, this,
&GtpyAbstractScriptingWizardPage::componentRenamed);

auto* comp = dynamic_cast<GtpyAbstractScriptComponent*>(obj);
if (!comp) return;

connect(m_editor, SIGNAL(textChanged()), this, SLOT(onTextChanged()));
using DataChanged = void (GtObject::*)(GtObject*, GtAbstractProperty*);
connect(obj, static_cast<DataChanged>(&GtObject::dataChanged),
this, [this, c = comp](GtObject* obj, GtAbstractProperty* prop) {
if (c && prop == &c->scriptProp()) setPlainTextToEditor(c->script());
});
}

bool
Expand All @@ -365,16 +345,6 @@ GtpyAbstractScriptingWizardPage::keyPressEvent(QKeyEvent* e)
// Ignore return
return;

case Qt::Key_Escape:

if (m_saveButton->isEnabled())
{
saveMessageBox();
return;
}

break;

default:
break;
}
Expand All @@ -400,14 +370,6 @@ GtpyAbstractScriptingWizardPage::keyPressEvent(QKeyEvent* e)
return;
}

// Save shortcut
if (((e->modifiers() & Qt::ControlModifier) &&
e->key() == Qt::Key_S))
{
onSaveButtonClicked();
return;
}

GtProcessWizardPage::keyPressEvent(e);
}

Expand Down Expand Up @@ -457,16 +419,16 @@ GtpyAbstractScriptingWizardPage::defaultFrameStyle()
void
GtpyAbstractScriptingWizardPage::setPlainTextToEditor(const QString& text)
{
if (!m_editor)
{
return;
}
assert(m_editor);
assert(m_searchWidget);

m_editor->setPlainText(text);
m_editor->setExtraSelections({});
m_editor->searchHighlighting(m_searchWidget->text());
}

QString
GtpyAbstractScriptingWizardPage::editorText()
GtpyAbstractScriptingWizardPage::editorText() const
{
if (!m_editor)
{
Expand Down Expand Up @@ -710,21 +672,6 @@ GtpyAbstractScriptingWizardPage::onEvalShortCutTriggered()
}
}

void
GtpyAbstractScriptingWizardPage::onSaveButtonClicked()
{
connect(m_editor, SIGNAL(textChanged()), this, SLOT(onTextChanged()));
saveScript();
enableSaveButton(false);
}

void
GtpyAbstractScriptingWizardPage::onTextChanged()
{
enableSaveButton(true);
disconnect(m_editor, SIGNAL(textChanged()), this, SLOT(onTextChanged()));
}

void
GtpyAbstractScriptingWizardPage::initialization()
{
Expand All @@ -738,66 +685,26 @@ GtpyAbstractScriptingWizardPage::validation()
}

void
GtpyAbstractScriptingWizardPage::enableSaveButton(bool enable)
GtpyAbstractScriptingWizardPage::saveScript()
{
if (!m_savingEnabled)
{
enable = false;
}

m_saveButton->setEnabled(enable);

if (enable)
{
m_shortCutSave->setText("<font color='grey'> Ctrl+S</font>");
}
else
{
m_shortCutSave->setText("");
}
storeScriptInDataModel();
}

int
GtpyAbstractScriptingWizardPage::saveMessageBox()
void
GtpyAbstractScriptingWizardPage::storeScriptInDataModel() const
{
QWidget* wiz = wizard();

if (!wiz)
{
return QMessageBox::Cancel;
}

QString text =
tr("Do you want to ") +
tr("save your changes before closing the wizard?");

GtSaveProjectMessageBox mb(text);

mb.setWindowFlags(mb.windowFlags() | Qt::WindowStaysOnTopHint);
GtObject* obj = gtDataModel->objectByUuid(componentUuid());
if (!obj) return;

int ret;
auto* comp = dynamic_cast<GtpyAbstractScriptComponent*>(obj);
if (!comp) return;

ret = mb.exec();
const QString script = editorText();
if (comp->script() == script) return;

switch (ret)
{
case QMessageBox::Yes:
onSaveButtonClicked();
wiz->close();
break;

case QMessageBox::No:
wiz->close();
break;

case QMessageBox::Cancel:
break;

default:
break;
}

return ret;
auto _ = gtApp->makeCommand(obj, tr("%1 code changed")
.arg(obj->objectName()));
comp->setScript(script);
}

void
Expand Down Expand Up @@ -961,24 +868,26 @@ GtpyAbstractScriptingWizardPage::cursorToNewLine()
m_editor->setTextCursor(cur);
}

void
GtpyAbstractScriptingWizardPage::enableSaving(bool enable)
{
m_savingEnabled = enable;
}


bool
GtpyAbstractScriptingWizardPage::eventFilter(QObject *watched, QEvent *event)
GtpyAbstractScriptingWizardPage::eventFilter(QObject* watched, QEvent* event)
{
if (event && event->type() == QEvent::Close && m_saveButton->isEnabled())
if (!watched || !event)
{
return GtProcessWizardPage::eventFilter(watched, event);
}

switch (event->type())
{
if (saveMessageBox() == QMessageBox::Cancel) event->ignore();
// this event occurs when the wizard loses focus
case QEvent::WindowDeactivate:
if (watched == wizard()) storeScriptInDataModel();
break;

return true;
default:
break;
}

return QObject::eventFilter(watched, event);
return GtProcessWizardPage::eventFilter(watched, event);
}

void
Expand Down
Loading