Merge pull request #25244 from tetektoza/fix/25232_exp_editor_regressions

Gui: Differentiate completion activation modes in Expression Editor
This commit is contained in:
Chris Hennes
2025-11-18 10:10:00 -06:00
committed by GitHub
3 changed files with 42 additions and 17 deletions

View File

@@ -1013,7 +1013,7 @@ void ExpressionLineEdit::slotTextChanged(const QString& text)
}
}
void ExpressionLineEdit::slotCompleteText(const QString& completionPrefix, bool isActivated)
void ExpressionLineEdit::slotCompleteText(const QString& completionPrefix, ActivationMode mode)
{
int start, end;
completer->getPrefixRange(start, end);
@@ -1030,7 +1030,7 @@ void ExpressionLineEdit::slotCompleteText(const QString& completionPrefix, bool
// chain completions if we select an entry from the completer drop down
// and that entry ends with '.' or '#'
if (isActivated) {
if (mode == ActivationMode::Activated) {
std::string textToComplete = completionPrefix.toUtf8().constData();
if (textToComplete.size()
&& (*textToComplete.crbegin() == '.' || *textToComplete.crbegin() == '#')) {
@@ -1042,12 +1042,12 @@ void ExpressionLineEdit::slotCompleteText(const QString& completionPrefix, bool
void ExpressionLineEdit::slotCompleteTextHighlighted(const QString& completionPrefix)
{
slotCompleteText(completionPrefix, false);
slotCompleteText(completionPrefix, ActivationMode::Highlighted);
}
void ExpressionLineEdit::slotCompleteTextSelected(const QString& completionPrefix)
{
slotCompleteText(completionPrefix, true);
slotCompleteText(completionPrefix, ActivationMode::Activated);
}
@@ -1116,13 +1116,13 @@ void ExpressionTextEdit::setDocumentObject(const App::DocumentObject* currentDoc
completer,
qOverload<const QString&>(&QCompleter::activated),
this,
&ExpressionTextEdit::slotCompleteText
&ExpressionTextEdit::slotCompleteTextSelected
);
connect(
completer,
qOverload<const QString&>(&QCompleter::highlighted),
this,
&ExpressionTextEdit::slotCompleteText
&ExpressionTextEdit::slotCompleteTextHighlighted
);
connect(this, &ExpressionTextEdit::textChanged2, completer, &ExpressionCompleter::slotUpdate);
connect(
@@ -1155,7 +1155,7 @@ void ExpressionTextEdit::slotTextChanged()
}
}
void ExpressionTextEdit::slotCompleteText(const QString& completionPrefix)
void ExpressionTextEdit::slotCompleteText(const QString& completionPrefix, ActivationMode mode)
{
QTextCursor cursor = textCursor();
int start, end;
@@ -1165,17 +1165,31 @@ void ExpressionTextEdit::slotCompleteText(const QString& completionPrefix)
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, end - pos);
}
cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, end - start);
Base::FlagToggler<bool> flag(block, false);
cursor.insertText(completionPrefix);
completer->updatePrefixEnd(cursor.positionInBlock());
std::string textToComplete = completionPrefix.toUtf8().constData();
if (textToComplete.size()
&& (*textToComplete.crbegin() == '.' || *textToComplete.crbegin() == '#')) {
completer->slotUpdate(cursor.block().text(), cursor.positionInBlock());
// chain completions only when activated (Enter/Click), not when highlighted (arrow keys)
if (mode == ActivationMode::Activated) {
std::string textToComplete = completionPrefix.toUtf8().constData();
if (!textToComplete.empty()
&& (*textToComplete.crbegin() == '.' || *textToComplete.crbegin() == '#')) {
completer->slotUpdate(cursor.block().text(), cursor.positionInBlock());
}
}
}
void ExpressionTextEdit::slotCompleteTextHighlighted(const QString& completionPrefix)
{
slotCompleteText(completionPrefix, ActivationMode::Highlighted);
}
void ExpressionTextEdit::slotCompleteTextSelected(const QString& completionPrefix)
{
slotCompleteText(completionPrefix, ActivationMode::Activated);
}
void ExpressionTextEdit::keyPressEvent(QKeyEvent* e)
{
Base::FlagToggler<bool> flag(block, true);
@@ -1208,9 +1222,8 @@ void ExpressionTextEdit::keyPressEvent(QKeyEvent* e)
if (!completer->popup()->currentIndex().isValid()) {
completer->popup()->setCurrentIndex(completer->popup()->model()->index(0, 0));
}
// insert completion
completer->setCurrentRow(completer->popup()->currentIndex().row());
slotCompleteText(completer->currentCompletion());
slotCompleteText(completer->currentCompletion(), ActivationMode::Highlighted);
// refresh completion list
completer->setCompletionPrefix(completer->currentCompletion());

View File

@@ -44,6 +44,12 @@ class ObjectIdentifier;
namespace Gui
{
enum class ActivationMode
{
Highlighted, // browsing with arrow keys
Activated // confirmed selection (Enter/Click)
};
class GuiExport ExpressionValidator: public QValidator
{
Q_OBJECT
@@ -123,8 +129,7 @@ Q_SIGNALS:
void textChanged2(QString text, int pos);
public Q_SLOTS:
void slotTextChanged(const QString& text);
// activated == pressed enter on the completion item
void slotCompleteText(const QString& completionPrefix, bool isActivated);
void slotCompleteText(const QString& completionPrefix, ActivationMode mode);
void slotCompleteTextHighlighted(const QString& completionPrefix);
void slotCompleteTextSelected(const QString& completionPrefix);
@@ -159,7 +164,9 @@ Q_SIGNALS:
void textChanged2(QString text, int pos);
public Q_SLOTS:
void slotTextChanged();
void slotCompleteText(const QString& completionPrefix);
void slotCompleteText(const QString& completionPrefix, ActivationMode mode);
void slotCompleteTextHighlighted(const QString& completionPrefix);
void slotCompleteTextSelected(const QString& completionPrefix);
void adjustCompleterToCursor();
private:

View File

@@ -1577,7 +1577,12 @@ bool ExpLineEdit::apply(const std::string& propName)
if (!ExpressionBinding::apply(propName)) {
if (!autoClose) {
QString val = QString::fromUtf8(Base::Interpreter().strToPython(text().toUtf8()).c_str());
Gui::Command::doCommand(Gui::Command::Doc, "%s = \"%s\"", propName.c_str(), val.constData());
Gui::Command::doCommand(
Gui::Command::Doc,
"%s = \"%s\"",
propName.c_str(),
val.toUtf8().constData()
);
}
return true;
}