explicit RtlItemDelegate(QObject * parent = 0)
: QItemDelegate(parent) {}
+ void setEnabled(bool enabled = true)
+ {
+ enabled_ = enabled;
+ }
+
protected:
virtual void drawDisplay(QPainter * painter,
QStyleOptionViewItem const & option,
QRect const & rect, QString const & text) const
{
+ if (!enabled_)
+ return QItemDelegate::drawDisplay(painter, option, rect, text);
+
// FIXME: do this more elegantly
docstring stltext = qstring_to_ucs4(text);
reverse(stltext.begin(), stltext.end());
QItemDelegate::drawDisplay(painter, option, rect, toqstr(stltext));
}
+
+private:
+ bool enabled_;
};
QPixmap p = QPixmap(name);
if (!p.isNull()) {
// scale it to 16x16 or smaller
- scaled
- = p.scaled(min(16, p.width()), min(16, p.height()),
+ scaled = p.scaled(min(16, p.width()), min(16, p.height()),
Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
setPopup(listView);
popup()->setItemDelegateForColumn(1, new PixmapItemDelegate(this));
rtlItemDelegate_ = new RtlItemDelegate(this);
-
+ popup()->setItemDelegateForColumn(0, rtlItemDelegate_);
+
// create timeout timers
popup_timer_.setSingleShot(true);
inline_timer_.setSingleShot(true);
}
+bool GuiCompleter::completionAvailable() const
+{
+ size_t n = popup()->model()->rowCount();
+
+ // if there is exactly one, we have to check whether it is a
+ // real completion, i.e. longer than the current prefix.
+ if (n == 1 && completionPrefix() == currentCompletion())
+ return false;
+
+ return n > 0;
+}
+
+
bool GuiCompleter::popupVisible() const
{
return popup()->isVisible();
bool possibleInlineState = inlinePossible(cur) && cursorInView;
// we moved or popup state is not ok for popup?
- if ((moved && !keep) || !possiblePopupState) {
- // stop an old completion timer
- if (popup_timer_.isActive())
- popup_timer_.stop();
-
- // hide old popup
- if (popupVisible())
- popup()->hide();
- }
+ if ((moved && !keep) || !possiblePopupState)
+ hidePopup(cur);
// we moved or inline state is not ok for inline completion?
- if ((moved && !keep) || !possibleInlineState) {
- // stop an old completion timer
- if (inline_timer_.isActive())
- inline_timer_.stop();
-
- // hide old inline completion
- if (inlineVisible()) {
- gui_->bufferView().setInlineCompletion(cur, DocIterator(), docstring());
- inlineVisible_ = false;
- }
- }
+ if ((moved && !keep) || !possibleInlineState)
+ hideInline(cur);
// we inserted something and are in a possible popup state?
if (!popupVisible() && possiblePopupState && start
&& cur.inset().automaticInlineCompletion())
inline_timer_.start(int(lyxrc.completion_inline_delay * 1000));
- // update prefix if popup is visible or if it will be visible soon
- if (popupVisible() || inlineVisible()
- || popup_timer_.isActive() || inline_timer_.isActive())
- updatePrefix(cur);
+ // update prefix if any completion is possible
+ bool modelActive = model()->rowCount() > 0;
+ if (possiblePopupState || possibleInlineState) {
+ if (modelActive)
+ updatePrefix(cur);
+ else
+ updateAvailability();
+ }
}
// update completer to new prefix
setCompletionPrefix(newPrefix);
-
+
// update popup because its size might have changed
if (popupVisible())
updatePopup(cur);
// if popup is not empty, the new selection will
// be our last valid one
QString const & s = currentCompletion();
- if (s.length() > 0)
- last_selection_ = s;
- else
- last_selection_ = old;
-
+ if (popupVisible() || inlineVisible()) {
+ if (s.length() > 0)
+ last_selection_ = s;
+ else
+ last_selection_ = old;
+ }
+
// update inline completion because the default
// completion string might have changed
if (inlineVisible())
rect = QRect(x, y - dim.ascent() - 3, 200, dim.height() + 6);
// show/update popup
- complete(rect);
QTreeView * p = static_cast<QTreeView *>(popup());
p->setColumnWidth(0, popup()->width() - 22 - p->verticalScrollBar()->width());
+
+ complete(rect);
}
+void GuiCompleter::updateAvailability()
+{
+ // this should really only be of interest if no completion is
+ // visible yet, i.e. especially if automatic completion is disabled.
+ if (inlineVisible() || popupVisible())
+ return;
+ Cursor & cur = gui_->bufferView().cursor();
+ if (!popupPossible(cur) && !inlinePossible(cur))
+ return;
+
+ updateModel(cur, false, false);
+}
+
+
void GuiCompleter::updateModel(Cursor & cur, bool popupUpdate, bool inlineUpdate)
{
// value which should be kept selected
// turn the direction of the strings in the popup.
// Qt does not do that itself.
- popup()->setItemDelegateForColumn(0, rtl ? rtlItemDelegate_ : 0);
+ rtlItemDelegate_->setEnabled(rtl);
// set new model
- Inset::CompletionList const * list
- = cur.inset().createCompletionList(cur);
+ Inset::CompletionList const * list = cur.inset().createCompletionList(cur);
setModel(new GuiCompletionModel(this, list));
if (list->sorted())
setModelSorting(QCompleter::CaseSensitivelySortedModel);
else
setModelSorting(QCompleter::UnsortedModel);
+ // set prefix
+ QString newPrefix = toqstr(cur.inset().completionPrefix(cur));
+ if (newPrefix != completionPrefix())
+ setCompletionPrefix(newPrefix);
+
// show popup
if (popupUpdate)
updatePopup(cur);
// if popup is not empty, the new selection will
// be our last valid one
- QString const & s = currentCompletion();
- if (s.length() > 0)
- last_selection_ = s;
- else
- last_selection_ = old;
-
+ if (popupVisible() || inlineVisible()) {
+ QString const & s = currentCompletion();
+ if (s.length() > 0)
+ last_selection_ = s;
+ else
+ last_selection_ = old;
+ }
+
// show inline completion
if (inlineUpdate)
updateInline(cur, currentCompletion());
return;
updateModel(cur, true, inlineVisible());
- updatePrefix(cur);
}
+
+
+void GuiCompleter::hidePopup(Cursor & cur)
+{
+ popup()->hide();
+ if (popup_timer_.isActive())
+ popup_timer_.stop();
+ if (!inlineVisible())
+ setModel(new GuiCompletionModel(this, 0));
+}
+
void GuiCompleter::showInline(Cursor & cur)
{
return;
updateModel(cur, popupVisible(), true);
- updatePrefix(cur);
+}
+
+
+void GuiCompleter::hideInline(Cursor & cur)
+{
+ gui_->bufferView().setInlineCompletion(cur, DocIterator(), docstring());
+ inlineVisible_ = false;
+
+ if (!popupVisible())
+ setModel(new GuiCompletionModel(this, 0));
}
}
+void GuiCompleter::hidePopup()
+{
+ Cursor cur = gui_->bufferView().cursor();
+ cur.updateFlags(Update::None);
+
+ hidePopup(cur);
+
+ // redraw if needed
+ if (cur.disp_.update())
+ gui_->bufferView().processUpdateFlags(cur.disp_.update());
+}
+
+
+void GuiCompleter::hideInline()
+{
+ Cursor cur = gui_->bufferView().cursor();
+ cur.updateFlags(Update::None);
+
+ hideInline(cur);
+
+ // redraw if needed
+ if (cur.disp_.update())
+ gui_->bufferView().processUpdateFlags(cur.disp_.update());
+}
+
+
void GuiCompleter::activate()
{
if (!popupVisible() && !inlineVisible())
return;
- // Complete with current selection in the popup.
- QString s = currentCompletion();
- popup()->hide();
- popupActivated(s);
+ popupActivated(currentCompletion());
}
cur.inset().insertCompletion(cur, docstring(), true);
// hide popup and inline completion
- popup()->hide();
- gui_->bufferView().setInlineCompletion(cur, DocIterator(), docstring());
- inlineVisible_ = false;
+ hidePopup(cur);
+ hideInline(cur);
updateVisibility(false, false);
return;
}
}
} else {
// In sorted models, do binary search for s.
- i = 0;
- size_t r = n - 1;
- do {
- size_t mid = (r + i) / 2;
+ int l = 0;
+ int r = n - 1;
+ while (r >= l && l < int(n)) {
+ size_t mid = (r + l) / 2;
QString const & mids
= model.data(model.index(mid, 0),
Qt::EditRole).toString();
// from the CompletionList has?
int c = s.compare(mids, Qt::CaseSensitive);
if (c == 0) {
- i = mid;
+ l = mid;
+ break;
+ } else if (l == r) {
+ l = n;
break;
} else if (c > 0)
// middle is not far enough
- i = mid + 1;
+ l = mid + 1;
else
// middle is too far
r = mid - 1;
+ }
- } while (r - i > 0 && i < n);
+ // loop was left without finding anything
+ if (r < l)
+ i = n;
+ else
+ i = l;
+ BOOST_ASSERT(0 <= i && i <= n);
}
// select the first if none was found
docstring GuiCompleter::longestUniqueCompletion() const
{
QAbstractItemModel const & model = *popup()->model();
- QString s = currentCompletion();
size_t n = model.rowCount();
-
+ if (n == 0)
+ return docstring();
+ QString s = model.data(model.index(0, 0), Qt::EditRole).toString();
+
if (modelSorting() == QCompleter::UnsortedModel) {
// For unsorted model we cannot do more than iteration.
// Iterate through the completions and cut off where s differs
QString const & mids
= model.data(model.index(mid, 0),
Qt::EditRole).toString();
- int sn = s.length();
- s = commonPrefix(mids, s);
+ size_t oldLen = s.length();
+ size_t len = commonPrefix(mids, s);
+ s = s.left(len);
// left or right?
- if (s.length() == sn) {
+ if (oldLen == len) {
// middle is not far enough
i = mid + 1;
} else {
docstring prefix = cur.inset().completionPrefix(cur);
docstring postfix = from_utf8(fromqstr(completion.mid(prefix.length())));
cur.inset().insertCompletion(cur, postfix, true);
- updateVisibility(cur, false);
+ hidePopup(cur);
+ hideInline(cur);
if (cur.disp_.update())
gui_->bufferView().processUpdateFlags(cur.disp_.update());
Cursor cur = gui_->bufferView().cursor();
cur.updateFlags(Update::None);
- updateInline(cur, completion);
+ if (inlineVisible())
+ updateInline(cur, completion);
if (cur.disp_.update())
gui_->bufferView().processUpdateFlags(cur.disp_.update());