File 2003-better-quick-open-window.patch of Package kate
diff --git a/apps/lib/katemainwindow.cpp b/apps/lib/katemainwindow.cpp
index 1e292c3084746f93eeba15e391d6437df4592017..180fdb4c0c3aaf67c158bcf87903a93ff9edd2d2 100644
--- a/apps/lib/katemainwindow.cpp
+++ b/apps/lib/katemainwindow.cpp
@@ -1614,8 +1614,6 @@ void KateMainWindow::slotQuickOpen()
* show quick open and pass focus to it
*/
KateQuickOpen *quickOpen = new KateQuickOpen(this);
- centralWidget()->setFocusProxy(quickOpen);
- quickOpen->raise();
quickOpen->show();
}
diff --git a/apps/lib/quickopen/katequickopen.cpp b/apps/lib/quickopen/katequickopen.cpp
index 6960ed52f3a00294f1fa14c215d06682a16ae41c..161ed9d3ba7554639958f12473630c570a97d57c 100644
--- a/apps/lib/quickopen/katequickopen.cpp
+++ b/apps/lib/quickopen/katequickopen.cpp
@@ -20,16 +20,18 @@
#include <QCoreApplication>
#include <QEvent>
+#include <QGraphicsEffect>
+#include <QLabel>
#include <QPainter>
#include <QPointer>
#include <QSortFilterProxyModel>
+#include <QStatusBar>
#include <QStyledItemDelegate>
#include <QToolBar>
#include <QTreeView>
#include <drawing_utils.h>
#include <kfts_fuzzy_match.h>
-#include <qgraphicseffect.h>
class QuickOpenFilterProxyModel final : public QSortFilterProxyModel
{
@@ -194,8 +196,7 @@ public:
}
QTextCharFormat fmt;
- fmt.setForeground(options.palette.link().color());
- fmt.setFontWeight(QFont::Bold);
+ fmt.setForeground(options.palette.link());
const int nameLen = name.length();
// space between name and path
@@ -215,15 +216,11 @@ public:
auto nameFormats = kfts::get_fuzzy_match_formats(m_filterString, name, 0, fmt);
formats.append(nameFormats);
}
- QTextCharFormat boldFmt;
- boldFmt.setFontWeight(QFont::Bold);
- boldFmt.setFontPointSize(options.font.pointSize() - 1);
- pathFormats = kfts::get_fuzzy_match_formats(m_filterString, path, nameLen + space, boldFmt);
+ pathFormats = kfts::get_fuzzy_match_formats(m_filterString, path, nameLen + space, fmt);
}
QTextCharFormat gray;
- gray.setForeground(Qt::gray);
- gray.setFontPointSize(options.font.pointSize() - 1);
+ gray.setForeground(option.palette.placeholderText());
formats.append({.start = nameLen + space, .length = static_cast<int>(path.length()), .format = gray});
if (!pathFormats.isEmpty()) {
formats.append(pathFormats);
@@ -232,14 +229,11 @@ public:
painter->save();
// paint background
- if (option.state & QStyle::State_Selected) {
- painter->fillRect(option.rect, option.palette.highlight());
- } else {
- painter->fillRect(option.rect, option.palette.base());
- }
+ QStyle *style = option.widget->style();
+ style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter);
options.text = QString(); // clear old text
- options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter, options.widget);
+ style->drawControl(QStyle::CE_ItemViewItem, &options, painter, options.widget);
// space for icon
painter->translate(25, 0);
@@ -269,23 +263,17 @@ private:
Q_DECLARE_METATYPE(QPointer<KTextEditor::Document>)
KateQuickOpen::KateQuickOpen(KateMainWindow *mainWindow)
- : QFrame(mainWindow)
+ : QFrame(mainWindow, Qt::Popup)
, m_mainWindow(mainWindow)
{
+ setAttribute(Qt::WA_DeleteOnClose);
+ setAttribute(Qt::WA_TranslucentBackground);
setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
setProperty("_breeze_force_frame", true);
-
- QGraphicsDropShadowEffect *e = new QGraphicsDropShadowEffect(this);
- e->setColor(palette().color(QPalette::Dark));
- e->setOffset(0, 4);
- e->setBlurRadius(8);
- setGraphicsEffect(e);
-
- // handle resizing
- mainWindow->installEventFilter(this);
+ setProperty("_KDE_NET_WM_FORCE_SHADOW", true);
// ensure the components have some proper frame
- QVBoxLayout *layout = new QVBoxLayout();
+ QVBoxLayout *layout = new QVBoxLayout;
layout->setSpacing(0);
layout->setContentsMargins(QMargins());
setLayout(layout);
@@ -295,104 +283,118 @@ KateQuickOpen::KateQuickOpen(KateMainWindow *mainWindow)
m_inputLine->addAction(QIcon::fromTheme(QStringLiteral("search")), QLineEdit::LeadingPosition);
m_inputLine->setFrame(false);
m_inputLine->setTextMargins(QMargins() + style()->pixelMetric(QStyle::PM_ButtonMargin));
- setFocusProxy(m_inputLine);
-
layout->addWidget(m_inputLine);
+ setFocusProxy(m_inputLine);
m_listView = new QTreeView(this);
- layout->addWidget(m_listView, 1);
- m_listView->setProperty("_breeze_borders_sides", QVariant::fromValue(QFlags(Qt::TopEdge)));
+ m_listView->setFocusPolicy(Qt::NoFocus);
m_listView->setTextElideMode(Qt::ElideLeft);
m_listView->setUniformRowHeights(true);
+ m_listView->setProperty("_breeze_borders_sides", QVariant::fromValue(QFlags(Qt::TopEdge)));
+ layout->addWidget(m_listView);
m_model = new KateQuickOpenModel(this);
m_styleDelegate = new QuickOpenStyleDelegate(this);
m_listView->setItemDelegate(m_styleDelegate);
- connect(m_inputLine, &QuickOpenLineEdit::returnPressed, this, &KateQuickOpen::slotReturnPressed);
connect(m_inputLine, &QuickOpenLineEdit::listModeChanged, this, &KateQuickOpen::slotListModeChanged);
connect(m_inputLine, &QuickOpenLineEdit::filterModeChanged, this, &KateQuickOpen::setFilterMode);
connect(m_listView, &QTreeView::activated, this, &KateQuickOpen::slotReturnPressed);
- connect(m_listView, &QTreeView::clicked, this, &KateQuickOpen::slotReturnPressed); // for single click
+ connect(m_listView, &QTreeView::clicked, m_listView, &QTreeView::activated); // for single click
m_inputLine->installEventFilter(this);
- m_listView->installEventFilter(this);
+
m_listView->setHeaderHidden(true);
m_listView->setRootIsDecorated(false);
m_listView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- m_listView->setModel(m_model);
- connect(m_inputLine, &QuickOpenLineEdit::textChanged, this, [this](const QString &text) {
- // We init the proxy model when there is something to filter
- bool didFilter = false;
- if (!m_proxyModel) {
- m_proxyModel = new QuickOpenFilterProxyModel(this);
- m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
- m_proxyModel->setFilterMode(m_inputLine->filterMode());
- didFilter = m_proxyModel->setFilterText(text);
- m_proxyModel->setSourceModel(m_model);
- m_listView->setModel(m_proxyModel);
+ m_proxyModel = new QuickOpenFilterProxyModel(this);
+ m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
+ m_proxyModel->setFilterMode(m_inputLine->filterMode());
+ m_proxyModel->setSourceModel(m_model);
+ m_listView->setModel(m_proxyModel);
+
+ QLabel *placeholderLabel = new QLabel;
+ placeholderLabel->setAlignment(Qt::AlignCenter);
+ placeholderLabel->setTextInteractionFlags(Qt::NoTextInteraction);
+ placeholderLabel->setWordWrap(true);
+ // To match the size of a level 2 Heading/KTitleWidget
+ QFont placeholderLabelFont = placeholderLabel->font();
+ placeholderLabelFont.setPointSize(qRound(placeholderLabelFont.pointSize() * 1.3));
+ placeholderLabel->setFont(placeholderLabelFont);
+ // Match opacity of QML placeholder label component
+ QGraphicsOpacityEffect *opacityEffect = new QGraphicsOpacityEffect(placeholderLabel);
+ opacityEffect->setOpacity(0.5);
+ placeholderLabel->setGraphicsEffect(opacityEffect);
+
+ QHBoxLayout *placeholderLayout = new QHBoxLayout;
+ placeholderLayout->addWidget(placeholderLabel);
+ m_listView->setLayout(placeholderLayout);
+
+ connect(m_proxyModel, &QuickOpenFilterProxyModel::modelReset, this, [this, placeholderLabel]() {
+ if (m_proxyModel->rowCount() > 0) {
+ placeholderLabel->hide();
} else {
- didFilter = m_proxyModel->setFilterText(text);
+ if (m_model->rowCount() == 0) {
+ placeholderLabel->setText(i18n("No items to display"));
+ } else {
+ placeholderLabel->setText(i18n("No items matching the filter"));
+ }
+ placeholderLabel->show();
}
- if (didFilter) {
+ });
+
+ connect(m_inputLine, &QuickOpenLineEdit::textChanged, this, [this](const QString &text) {
+ if (m_proxyModel->setFilterText(text)) {
m_styleDelegate->setFilterString(text);
m_listView->viewport()->update();
reselectFirst();
}
});
- setHidden(true);
-
setFilterMode();
m_model->setListMode(m_inputLine->listMode());
// fill stuff
- updateState();
+ refreshModel();
}
bool KateQuickOpen::eventFilter(QObject *obj, QEvent *event)
{
- // catch key presses + shortcut overrides to allow to have ESC as application wide shortcut, too, see bug 409856
- if (event->type() == QEvent::KeyPress || event->type() == QEvent::ShortcutOverride) {
- QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
- if (obj == m_inputLine) {
- const bool forward2list = (keyEvent->key() == Qt::Key_Up) || (keyEvent->key() == Qt::Key_Down) || (keyEvent->key() == Qt::Key_PageUp)
- || (keyEvent->key() == Qt::Key_PageDown);
- if (forward2list) {
- QCoreApplication::sendEvent(m_listView, event);
- return true;
- }
-
- } else if (obj == m_listView) {
- const bool forward2input = (keyEvent->key() != Qt::Key_Up) && (keyEvent->key() != Qt::Key_Down) && (keyEvent->key() != Qt::Key_PageUp)
- && (keyEvent->key() != Qt::Key_PageDown) && (keyEvent->key() != Qt::Key_Tab) && (keyEvent->key() != Qt::Key_Backtab);
- if (forward2input) {
- QCoreApplication::sendEvent(m_inputLine, event);
- return true;
- }
+ if (obj == m_inputLine && event->type() == QEvent::KeyPress) {
+ const QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
+ if (keyEvent->modifiers() & Qt::MetaModifier) {
+ return true;
}
- if (keyEvent->key() == Qt::Key_Escape) {
- hide();
- deleteLater();
+ switch (keyEvent->key()) {
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ case Qt::Key_PageUp:
+ case Qt::Key_PageDown:
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ QCoreApplication::sendEvent(m_listView, event);
+ return true;
+ case Qt::Key_Escape:
+ close();
return true;
+ default:
+ break;
}
}
- if (event->type() == QEvent::FocusOut && !(m_inputLine->hasFocus() || m_listView->hasFocus())) {
- hide();
- deleteLater();
- return true;
- }
+ return QWidget::eventFilter(obj, event);
+}
- // handle resizing
- if (m_mainWindow == obj && event->type() == QEvent::Resize) {
- updateViewGeometry();
- }
+void KateQuickOpen::showEvent(QShowEvent *event)
+{
+ adjustSizeAndPosition();
- return QWidget::eventFilter(obj, event);
+ QWidget::showEvent(event);
+
+ setFocus(Qt::PopupFocusReason);
}
void KateQuickOpen::reselectFirst()
@@ -407,14 +409,10 @@ void KateQuickOpen::reselectFirst()
m_listView->setCurrentIndex(index);
}
-void KateQuickOpen::updateState()
+void KateQuickOpen::refreshModel()
{
m_model->refresh(m_mainWindow);
reselectFirst();
-
- updateViewGeometry();
- show();
- setFocus();
}
void KateQuickOpen::slotReturnPressed()
@@ -427,15 +425,23 @@ void KateQuickOpen::slotReturnPressed()
// either get view via document pointer or url
const QModelIndex index = m_listView->currentIndex();
- KTextEditor::View *view = nullptr;
+ if (!index.isValid()) {
+ return;
+ }
+
+ KTextEditor::View *view;
if (auto doc = index.data(KateQuickOpenModel::Document).value<KTextEditor::Document *>()) {
view = m_mainWindow->activateView(doc);
} else {
view = m_mainWindow->wrapper()->openUrl(index.data(Qt::UserRole).toUrl());
}
+ if (!view) {
+ return;
+ }
+
const auto strs = m_inputLine->text().split(QLatin1Char(':'));
- if (view && strs.count() > 1) {
+ if (strs.count() > 1) {
// helper to convert String => Number
auto stringToInt = [](const QString &s) {
bool ok = false;
@@ -460,22 +466,19 @@ void KateQuickOpen::slotReturnPressed()
}
}
- hide();
- deleteLater();
+ close();
m_mainWindow->slotWindowActivated();
// store the new position in location history
- if (view) {
- vm->addPositionToHistory(view->document()->url(), view->cursorPosition());
- }
+ vm->addPositionToHistory(view->document()->url(), view->cursorPosition());
}
void KateQuickOpen::slotListModeChanged(KateQuickOpenModel::List mode)
{
m_model->setListMode(mode);
// this changes things again, needs refresh, let's go all the way
- updateState();
+ refreshModel();
}
void KateQuickOpen::setFilterMode()
@@ -489,7 +492,7 @@ void KateQuickOpen::setFilterMode()
m_listView->viewport()->update();
}
-static QRect getQuickOpenBoundingRect(QMainWindow *mainWindow)
+static QRect getQuickOpenBoundingRect(KateMainWindow *mainWindow)
{
QRect boundingRect = mainWindow->contentsRect();
@@ -500,6 +503,13 @@ static QRect getQuickOpenBoundingRect(QMainWindow *mainWindow)
}
}
+ // exclude the status bar from the bounding rect
+ if (const QStatusBar *statusBar = mainWindow->findChild<QStatusBar *>()) {
+ if (!statusBar->isHidden()) {
+ boundingRect.setBottom(boundingRect.bottom() - statusBar->height());
+ }
+ }
+
// exclude any undocked toolbar from the bounding rect
const QList<QToolBar *> toolBars = mainWindow->findChildren<QToolBar *>();
for (QToolBar *toolBar : toolBars) {
@@ -507,15 +517,28 @@ static QRect getQuickOpenBoundingRect(QMainWindow *mainWindow)
continue;
}
- if (mainWindow->toolBarArea(toolBar) == Qt::TopToolBarArea) {
+ switch (mainWindow->toolBarArea(toolBar)) {
+ case Qt::TopToolBarArea:
boundingRect.setTop(std::max(boundingRect.top(), toolBar->geometry().bottom()));
+ break;
+ case Qt::RightToolBarArea:
+ boundingRect.setRight(std::min(boundingRect.right(), toolBar->geometry().left()));
+ break;
+ case Qt::BottomToolBarArea:
+ boundingRect.setBottom(std::min(boundingRect.bottom(), toolBar->geometry().top()));
+ break;
+ case Qt::LeftToolBarArea:
+ boundingRect.setLeft(std::max(boundingRect.left(), toolBar->geometry().right()));
+ break;
+ default:
+ break;
}
}
- return boundingRect;
+ return boundingRect.translated(mainWindow->geometry().topLeft());
}
-void KateQuickOpen::updateViewGeometry()
+void KateQuickOpen::adjustSizeAndPosition()
{
const QRect boundingRect = getQuickOpenBoundingRect(m_mainWindow);
@@ -527,15 +550,13 @@ void KateQuickOpen::updateViewGeometry()
const int maxHeight = boundingRect.height();
const int preferredHeight = maxHeight / 2;
- const QSize size{std::min(maxWidth, std::max(preferredWidth, minWidth)), std::min(maxHeight, std::max(preferredHeight, minHeight))};
+ const QSize size(std::min(maxWidth, std::max(preferredWidth, minWidth)), std::min(maxHeight, std::max(preferredHeight, minHeight)));
- // resize() doesn't work here, so use setFixedSize() instead
- setFixedSize(size);
+ resize(size);
// set the position to the top-center of the parent
// just below the menubar/toolbar (if any)
- const QPoint position{boundingRect.center().x() - size.width() / 2, boundingRect.y() + 6};
- move(position);
+ move(boundingRect.center().x() - size.width() / 2, boundingRect.y() + 6);
}
#include "moc_katequickopen.cpp"
diff --git a/apps/lib/quickopen/katequickopen.h b/apps/lib/quickopen/katequickopen.h
index 592b3c81d0b0e79ae405473675689ef8755263c2..c800b7a678484ed808c3ab3d1f74c65764d6f0ca 100644
--- a/apps/lib/quickopen/katequickopen.h
+++ b/apps/lib/quickopen/katequickopen.h
@@ -27,14 +27,14 @@ public:
KateQuickOpen(KateMainWindow *mainWindow);
/**
- * update state
+ * refresh model
* will fill model with current open documents, project documents, ...
*/
- void updateState();
- void updateViewGeometry();
+ void refreshModel();
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
+ void showEvent(QShowEvent *event) override;
private:
void reselectFirst();
@@ -50,6 +50,8 @@ private:
void setFilterMode();
private:
+ void adjustSizeAndPosition();
+
KateMainWindow *m_mainWindow;
QTreeView *m_listView;
QuickOpenLineEdit *m_inputLine;
diff --git a/apps/lib/quickopen/katequickopenmodel.cpp b/apps/lib/quickopen/katequickopenmodel.cpp
index 83d17848d1080b2369bb3a9bca3e26fdee43050f..87d49bf9f7537b969e808bea2763d8bacf7c235f 100644
--- a/apps/lib/quickopen/katequickopenmodel.cpp
+++ b/apps/lib/quickopen/katequickopenmodel.cpp
@@ -54,14 +54,6 @@ QVariant KateQuickOpenModel::data(const QModelIndex &idx, int role) const
const auto &path = entry.filePath;
return path.startsWith(m_projectBase) ? path.mid(m_projectBase.size()) : path;
}
- case Qt::FontRole: {
- if (entry.document) {
- QFont font;
- font.setBold(true);
- return font;
- }
- return {};
- }
case Qt::DecorationRole:
return QIcon::fromTheme(QMimeDatabase().mimeTypeForFile(entry.fileName, QMimeDatabase::MatchExtension).iconName());
case Qt::UserRole: