#include "LyX.h"
#include "LyXRC.h"
#include "Paragraph.h"
+#include "qt_helpers.h"
#include "version.h"
#include "support/lassert.h"
+#include "support/lstrings.h"
#include "support/debug.h"
#include <QApplication>
QStyleOptionViewItem opt = setOptions(index, option);
QVariant value = index.data(Qt::DisplayRole);
QPixmap pixmap = qvariant_cast<QPixmap>(value);
-
+
// draw
painter->save();
drawBackground(painter, opt, index);
~GuiCompletionModel() { delete list_; }
///
void setList(CompletionList const * l) {
+ beginResetModel();
delete list_;
list_ = l;
- reset();
+ endResetModel();
}
///
bool sorted() const
if (role != Qt::DisplayRole && role != Qt::EditRole)
return QVariant();
-
+
if (index.column() == 0)
return toqstr(list_->data(index.row()));
if (index.column() != 1)
return QVariant();
-
+
// get icon from cache
QPixmap scaled;
QString const name = ":" + toqstr(list_->icon(index.row()));
+ if (name == ":")
+ return scaled;
if (!QPixmapCache::find("completion" + name, scaled)) {
// load icon from disk
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);
}
QPixmapCache::insert("completion" + name, scaled);
setCompletionMode(QCompleter::PopupCompletion);
setCaseSensitivity(Qt::CaseSensitive);
setWidget(gui_);
-
+
// create the popup
QTreeView *listView = new QTreeView;
listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
listView->setIndentation(0);
listView->setUniformRowHeights(true);
setPopup(listView);
-
+
itemDelegate_ = new CompleterItemDelegate(this);
popup()->setItemDelegate(itemDelegate_);
-
+
// create timeout timers
popup_timer_.setSingleShot(true);
inline_timer_.setSingleShot(true);
default: break;
}
}
-
+
return QCompleter::eventFilter(watched, e);
}
if (n > 1 || n == 0)
return false;
- // 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
// real completion, i.e. longer than the current prefix.
if (completionPrefix() == currentCompletion())
return false;
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
// real completion, i.e. longer than the current prefix.
if (n == 1 && completionPrefix() == currentCompletion())
return false;
// we moved or popup state is not ok for popup?
if ((moved && !keep) || !possiblePopupState)
- hidePopup(cur);
+ hidePopup();
// we moved or inline state is not ok for inline completion?
if ((moved && !keep) || !possibleInlineState)
{
Cursor cur = gui_->bufferView().cursor();
cur.screenUpdateFlags(Update::None);
-
+
updateVisibility(cur, start, keep);
-
+
if (cur.result().screenUpdate())
gui_->bufferView().processUpdateFlags(cur.result().screenUpdate());
}
QString newPrefix = toqstr(cur.inset().completionPrefix(cur));
if (newPrefix == completionPrefix())
return;
-
+
// value which should be kept selected
QString old = currentCompletion();
if (old.length() == 0)
old = last_selection_;
-
+
// update completer to new prefix
setCompletionPrefix(newPrefix);
// restore old selection
setCurrentCompletion(old);
-
+
// if popup is not empty, the new selection will
// be our last valid one
QString const & s = currentCompletion();
{
if (!cur.inset().inlineCompletionSupported(cur))
return;
-
+
// compute postfix
docstring prefix = cur.inset().completionPrefix(cur);
docstring postfix = qstring_to_ucs4(completion.mid(prefix.length()));
-
+
// shorten it if necessary
- if (lyxrc.completion_inline_dots != -1
- && postfix.size() > unsigned(lyxrc.completion_inline_dots))
- postfix = postfix.substr(0, lyxrc.completion_inline_dots - 1) + "...";
+ if (lyxrc.completion_inline_dots != -1)
+ support::truncateWithEllipsis(postfix,
+ unsigned(lyxrc.completion_inline_dots));
// set inline completion at cursor position
size_t uniqueTo = max(longestUniqueCompletion().size(), prefix.size());
{
if (!cur.inset().completionSupported(cur))
return;
-
+
popupVisible_ = true;
if (completionCount() == 0) {
int x;
int y;
cur.inset().completionPosAndDim(cur, x, y, dim);
-
+
// and calculate the rect of the popup
QRect rect;
if (popup()->layoutDirection() == Qt::RightToLeft)
rect = QRect(x + dim.width() - 200, y - dim.ascent() - 3, 200, dim.height() + 6);
else
rect = QRect(x, y - dim.ascent() - 3, 200, dim.height() + 6);
-
+
// Resize the columns in the popup.
// This should really be in the constructor. But somehow the treeview
// has a bad memory about it and we have to tell him again and again.
QTreeView * listView = static_cast<QTreeView *>(popup());
listView->header()->setStretchLastSection(false);
- listView->header()->setResizeMode(0, QHeaderView::Stretch);
- listView->header()->setResizeMode(1, QHeaderView::Fixed);
+ setSectionResizeMode(listView->header(), 0, QHeaderView::Stretch);
+ setSectionResizeMode(listView->header(), 1, QHeaderView::Fixed);
listView->header()->resizeSection(1, 22);
-
+
// show/update popup
complete(rect);
}
Cursor const & cur = gui_->bufferView().cursor();
if (!popupPossible(cur) && !inlinePossible(cur))
return;
-
+
updateModel(cur, false, false);
}
-
+
void GuiCompleter::updateModel(Cursor const & cur, bool popupUpdate, bool inlineUpdate)
{
// restore old selection
setCurrentCompletion(old);
-
+
// if popup is not empty, the new selection will
// be our last valid one
if (popupVisible() || inlineVisible()) {
{
if (!popupPossible(cur))
return;
-
- updateModel(cur, true, inlineVisible());
-}
-
-
-void GuiCompleter::hidePopup(Cursor &)
-{
- popupVisible_ = false;
-
- if (popup_timer_.isActive())
- popup_timer_.stop();
- // hide popup asynchronously because we might be here inside of
- // LFUN dispatchers. Hiding a popup can trigger a focus event on the
- // 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
- // cursorPos methods would triggers asserts in the coord cache then.
- QTimer::singleShot(0, this, SLOT(asyncHidePopup()));
-
- // mark that the asynchronous part will reset the model
- if (!inlineVisible())
- modelActive_ = false;
+ updateModel(cur, true, inlineVisible());
}
{
if (!inlinePossible(cur))
return;
-
+
updateModel(cur, popupVisible(), true);
}
{
gui_->bufferView().setInlineCompletion(cur, DocIterator(cur.buffer()), docstring());
inlineVisible_ = false;
-
+
if (inline_timer_.isActive())
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.
{
Cursor cur = gui_->bufferView().cursor();
cur.screenUpdateFlags(Update::None);
-
+
showPopup(cur);
// redraw if needed
{
Cursor cur = gui_->bufferView().cursor();
cur.screenUpdateFlags(Update::None);
-
+
showInline(cur);
// redraw if needed
void GuiCompleter::hidePopup()
{
- Cursor cur = gui_->bufferView().cursor();
- cur.screenUpdateFlags(Update::None);
-
- hidePopup(cur);
-
- // redraw if needed
- if (cur.result().screenUpdate())
- gui_->bufferView().processUpdateFlags(cur.result().screenUpdate());
+ popupVisible_ = false;
+
+ if (popup_timer_.isActive())
+ popup_timer_.stop();
+
+ // hide popup asynchronously because we might be here inside of
+ // LFUN dispatchers. Hiding a popup can trigger a focus event on the
+ // 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
+ // cursorPos methods would triggers asserts in the coord cache then.
+ QTimer::singleShot(0, this, SLOT(asyncHidePopup()));
+
+ // mark that the asynchronous part will reset the model
+ if (!inlineVisible())
+ modelActive_ = false;
}
{
Cursor cur = gui_->bufferView().cursor();
cur.screenUpdateFlags(Update::None);
-
+
hideInline(cur);
-
+
// redraw if needed
if (cur.result().screenUpdate())
gui_->bufferView().processUpdateFlags(cur.result().screenUpdate());
BufferView * bv = &gui_->bufferView();
Cursor cur = bv->cursor();
cur.screenUpdateFlags(Update::None);
-
+
// check that inline completion is active
if (!inlineVisible() && !uniqueCompletionAvailable()) {
// try to activate the inline completion
if (cur.inset().inlineCompletionSupported(cur)) {
showInline();
-
+
// show popup without delay because the completion was not unique
if (lyxrc.completion_popup_after_complete
&& !popupVisible()
showPopup();
return;
}
-
+
return;
}
-
+
// Make undo possible
cur.beginUndoGroup();
cur.recordUndo();
if (completion.size() <= prefix.size()) {
// finalize completion
cur.inset().insertCompletion(cur, docstring(), true);
-
+
// hide popup and inline completion
- hidePopup(cur);
+ hidePopup();
hideInline(cur);
updateVisibility(false, false);
cur.endUndoGroup();
if (!popup()->selectionModel()->hasSelection())
return QString();
- // Not sure if this is bug in Qt: currentIndex() always
+ // Not sure if this is bug in Qt: currentIndex() always
// return the first element in the list.
QModelIndex idx = popup()->currentIndex();
return popup()->model()->data(idx, Qt::EditRole).toString();
void GuiCompleter::setCurrentCompletion(QString const & s)
-{
+{
QAbstractItemModel const & model = *popup()->model();
size_t n = model.rowCount();
if (n == 0)
i = n;
else
i = l;
- LASSERT(i <= n, /**/);
+ // we can try to recover
+ LASSERT(i <= n, i = 0);
}
// select the first if none was found
// get common prefix with the middle string
size_t mid = (r + i) / 2;
QString const & mids
- = model.data(model.index(mid, 0),
+ = model.data(model.index(mid, 0),
Qt::EditRole).toString();
size_t oldLen = s.length();
size_t len = commonPrefix(mids, s);
docstring prefix = cur.inset().completionPrefix(cur);
docstring postfix = qstring_to_ucs4(completion.mid(prefix.length()));
cur.inset().insertCompletion(cur, postfix, true);
- hidePopup(cur);
+ hidePopup();
hideInline(cur);
-
+
if (cur.result().screenUpdate())
gui_->bufferView().processUpdateFlags(cur.result().screenUpdate());
cur.endUndoGroup();
Cursor cur = gui_->bufferView().cursor();
cur.screenUpdateFlags(Update::None);
-
+
if (inlineVisible())
updateInline(cur, completion);
-
+
if (cur.result().screenUpdate())
gui_->bufferView().processUpdateFlags(cur.result().screenUpdate());
}