Gui: Differentiate completion activation modes in Expression Editor

Currently if user tries to press TAB during Expression Editor, it
inserts both the entry and its first subentry. Also, if user browses the
dropdown with arrows keys, it inserts it's values.

Root cause of that is the regression made in latest changes to chaining
completion logic which is triggered for all completion modes including
TAB, which already has its own refresh mechanism. Also,
ExpressionTextEdit connected both activated (Enter/click) and highlight
signals to the same slot, resulting in arrow key navigation inserting
completions.

So, this adds separate slots for ExpressionTextEdit to differentiate
completion modes. And also updates tab handling to pass
ActivationMode::Highlighted to prevent double chaining.
This commit is contained in:
tetektoza
2025-11-12 00:14:02 +01:00
parent f0ce08268d
commit efbbfdbfb5
2 changed files with 36 additions and 16 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());