* even setModel can trigger focus events. So move also those into

asynchronous handlers.


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@23438 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Stefan Schimanski 2008-03-04 12:44:48 +00:00
parent 6e3e2ae19b
commit de518abff5
2 changed files with 45 additions and 14 deletions

View File

@ -173,7 +173,8 @@ private:
GuiCompleter::GuiCompleter(GuiWorkArea * gui, QObject * parent) GuiCompleter::GuiCompleter(GuiWorkArea * gui, QObject * parent)
: QCompleter(parent), gui_(gui), updateLock_(0), : QCompleter(parent), gui_(gui), updateLock_(0),
inlineVisible_(false), popupVisible_(false) inlineVisible_(false), popupVisible_(false),
modelActive_(false)
{ {
// Setup the completion popup // Setup the completion popup
setModel(new GuiCompletionModel(this, 0)); setModel(new GuiCompletionModel(this, 0));
@ -250,6 +251,9 @@ bool GuiCompleter::inlinePossible(Cursor const & cur) const
bool GuiCompleter::completionAvailable() const bool GuiCompleter::completionAvailable() const
{ {
if (!modelActive_)
return false;
size_t n = popup()->model()->rowCount(); size_t n = popup()->model()->rowCount();
// if there is exactly one, we have to check whether it is a // if there is exactly one, we have to check whether it is a
@ -308,7 +312,7 @@ void GuiCompleter::updateVisibility(Cursor & cur, bool start, bool keep, bool cu
inline_timer_.start(int(lyxrc.completion_inline_delay * 1000)); inline_timer_.start(int(lyxrc.completion_inline_delay * 1000));
// update prefix if any completion is possible // update prefix if any completion is possible
bool modelActive = model()->rowCount() > 0; bool modelActive = modelActive_ && model()->rowCount() > 0;
if (possiblePopupState || possibleInlineState) { if (possiblePopupState || possibleInlineState) {
if (modelActive) if (modelActive)
updatePrefix(cur); updatePrefix(cur);
@ -402,14 +406,11 @@ void GuiCompleter::updatePopup(Cursor & cur)
return; return;
} }
// show asynchronously to avoid lookups before the metrics QTimer::singleShot(0, this, SLOT(asyncUpdatePopup()));
// have been computed. This can happen because we might be in
// the middle of a dispatch.
QTimer::singleShot(0, this, SLOT(asyncCompletePopup()));
} }
void GuiCompleter::asyncCompletePopup() void GuiCompleter::asyncUpdatePopup()
{ {
Cursor cur = gui_->bufferView().cursor(); Cursor cur = gui_->bufferView().cursor();
if (!cur.inset().completionSupported(cur)) { if (!cur.inset().completionSupported(cur)) {
@ -482,6 +483,7 @@ void GuiCompleter::updateModel(Cursor & cur, bool popupUpdate, bool inlineUpdate
// set new model // set new model
Inset::CompletionList const * list = cur.inset().createCompletionList(cur); Inset::CompletionList const * list = cur.inset().createCompletionList(cur);
setModel(new GuiCompletionModel(this, list)); setModel(new GuiCompletionModel(this, list));
modelActive_ = true;
if (list->sorted()) if (list->sorted())
setModelSorting(QCompleter::CaseSensitivelySortedModel); setModelSorting(QCompleter::CaseSensitivelySortedModel);
else else
@ -528,16 +530,25 @@ void GuiCompleter::hidePopup(Cursor & cur)
{ {
popupVisible_ = false; popupVisible_ = false;
if (popup_timer_.isActive())
popup_timer_.stop();
// hide popup asynchronously because we might be here inside of // hide popup asynchronously because we might be here inside of
// LFUN dispatchers. Hiding a popup can trigger a focus event on the // LFUN dispatchers. Hiding a popup can trigger a focus event on the
// workarea which then redisplays the cursor. But the metrics are not // workarea which then redisplays the cursor. But the metrics are not
// yet up to date such that the coord cache has not all insets yet. The // yet up to date such that the coord cache has not all insets yet. The
// cursorPos methods would triggers asserts in the coord cache then. // cursorPos methods would triggers asserts in the coord cache then.
QTimer::singleShot(0, popup(), SLOT(hide())); QTimer::singleShot(0, this, SLOT(asyncHidePopup()));
if (popup_timer_.isActive()) // mark that the asynchronous part will reset the model
popup_timer_.stop(); if (!inlineVisible())
modelActive_ = false;
}
void GuiCompleter::asyncHidePopup()
{
popup()->hide();
if (!inlineVisible()) if (!inlineVisible())
setModel(new GuiCompletionModel(this, 0)); setModel(new GuiCompletionModel(this, 0));
} }
@ -560,6 +571,19 @@ void GuiCompleter::hideInline(Cursor & cur)
if (inline_timer_.isActive()) if (inline_timer_.isActive())
inline_timer_.stop(); inline_timer_.stop();
// Trigger asynchronous part of hideInline. We might be
// in a dispatcher here and the setModel call might
// trigger focus events which is are not healthy here.
QTimer::singleShot(0, this, SLOT(asyncHideModel()));
// mark that the asynchronous part will reset the model
if (!popupVisible())
modelActive_ = false;
}
void GuiCompleter::asyncHideInline()
{
if (!popupVisible()) if (!popupVisible())
setModel(new GuiCompletionModel(this, 0)); setModel(new GuiCompletionModel(this, 0));
} }

View File

@ -88,8 +88,12 @@ private Q_SLOTS:
void popupHighlighted(const QString & completion); void popupHighlighted(const QString & completion);
/// ///
void updateAvailability(); void updateAvailability();
/// /// the asynchronous part of updatePopup(cur)
void asyncCompletePopup(); void asyncUpdatePopup();
/// the asynchronous part of hidePopup(cur)
void asyncHidePopup();
/// the asynchronous part of hideInline(cur)
void asyncHideInline();
private: private:
/// ///
@ -131,6 +135,9 @@ private:
bool inlineVisible_; bool inlineVisible_;
/// ///
bool popupVisible_; bool popupVisible_;
/// the model reset is asynchronous in hidePopup/Inline. So let's mark
/// a coming reset here by setting it to false.
bool modelActive_;
/// ///
RtlItemDelegate * rtlItemDelegate_; RtlItemDelegate * rtlItemDelegate_;
}; // GuiCompleter }; // GuiCompleter