A custom completer behaviour with QLineEdit.
-
The default behaviour of QCompleter on QLineEdit set using function QLineEdit::setCompleter() is to take all of the string in QLineEdit::text. So if I want a behaviour where in a QTreeModelCompleter parses parts of QLineEdit::text() [ex: A.B.C && C.D.E] it is not possible with the default behaviour. As A.B.C will work but after it all of the text is given to my Completer and it doesn't work.
To avoid it I decided to have my own LineEdit inheriting from QLineEdit with this format:
@
class LineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit LineEdit(QWidget parent = 0);
protected:
signals:
private slots:
void insertCompletion(QString);
void textEditedSlot(const QString &);
private:
QCompleter completer;
QString textUnderCursor();
};LineEdit::LineEdit(QWidget *parent) : QLineEdit(parent) { completer= new TreeModelCompleter(this);//TreeModelCompleter is my implementation of QCompleter, works ok with qtextedit completer->setWidget(this); QObject::connect(completer, SIGNAL(activated(QString)), this, SLOT(insertCompletion(QString))); QObject::connect(this, SIGNAL(textEdited(QString)), this, SLOT(textEditedSlot(QString))); } void LineEdit::insertCompletion(QString completion) { bool done = false; QString rep; int initPos = cursorPosition(); int pos = initPos; QString t = text(); while(!done){ bool moved=true; if(pos == 0) moved = false; else { --pos; rep = t.at(pos) + rep; } if(!moved) done = true; else if(rep.contains(QRegExp("[\\s+-&!,|<>?/ \\(\\) \\{\\} ]"))) { if(!done) rep.remove(0, 1); done = true; ++pos; } } setText(t.replace(pos, initPos-pos+1, completion)); } void LineEdit::textEditedSlot(const QString &text) { QString completionPrefix = textUnderCursor(); if (completionPrefix != completer->completionPrefix()) { completer->setCompletionPrefix(completionPrefix); completer->popup()->setCurrentIndex(completer->popup()->model()->index(0,0)); } QRect cr = cursorRect(); cr.setWidth(completer->popup()->sizeHintForColumn(0) + completer->popup()->verticalScrollBar()->sizeHint().width()); completer->complete(cr); // popup it up! } QString LineEdit::textUnderCursor() { bool done = false; QString rep; int initPos = cursorPosition(); int pos = initPos; QString t = text(); while(!done){ bool moved=true; if(pos == 0) moved = false; else {--pos;rep = t.at(pos) + rep; } if(!moved) done = true; else if(rep.contains(QRegExp("[\\s+-&!,|<>?/ \\(\\) \\{\\} ]"))) { if(!done) rep.remove(0, 1); done = true; ++pos; } } if(!thisString.isEmpty() && rep.contains(QString("this"))){ rep = rep.replace(QString("this"), thisString); } return rep; }
@
Now the Problem is after typing in say A no event is taken in by LineEdit. I tried checking with implementing event functions of LineEdit and MyCompleter. So a QKeyEvent of '.' comes to LineEdit but no editchanged signal arrives! LineEdit is rejecting QKeyEvents of '.' For if LineEdit is receiving the event of '.' it should result in text() being changed, leading to fire of textEdited() signal. But is not happening. I don't get it.
-
Hmm, doesn't the textEdited() signal only come when done editing? So losing focus (after something else is selected or an enter is given?)
-
The only difference between textEdited() and textChanged() signals of QLineEdit is that while textEdited() is not fired programmatically. So setText() wouldn't fire textEdited() however, textChanged() does fire.
Besides, AFAIK, it is a qt bug. QLineEdit even if not subclassed and its setCompleter() function is used, the problem persists. The model and QCompleter subclass I know is good because it works with QTextEdit. And.. it used to work with previous versions(4.7.x).
The bug is inside qt code. I debugged a little and found that '.' was told to insert in qlineedit_p.cpp file. But didn't updated text(). Didn't had time to debug more.
Have created a bug too. But you know, with Qt, bugs are rare.. hence the question.