diff --git a/kate/CMakeLists.txt b/kate/CMakeLists.txt --- a/kate/CMakeLists.txt +++ b/kate/CMakeLists.txt @@ -27,7 +27,7 @@ katesavemodifieddialog.cpp katemwmodonhddialog.cpp katecolorschemechooser.cpp - + katequickopenmodel.cpp katetabbutton.cpp katetabbar.cpp diff --git a/kate/katequickopen.h b/kate/katequickopen.h --- a/kate/katequickopen.h +++ b/kate/katequickopen.h @@ -29,6 +29,7 @@ class QStandardItemModel; class QSortFilterProxyModel; class QTreeView; +class KateQuickOpenModel; class KateQuickOpen : public QWidget { @@ -61,7 +62,7 @@ /** * our model we search in */ - QStandardItemModel *m_base_model; + KateQuickOpenModel *m_base_model; /** * filtered model we search in diff --git a/kate/katequickopen.cpp b/kate/katequickopen.cpp --- a/kate/katequickopen.cpp +++ b/kate/katequickopen.cpp @@ -18,14 +18,17 @@ */ #include "katequickopen.h" +#include "katequickopenmodel.h" #include "katemainwindow.h" #include "kateviewmanager.h" #include "kateapp.h" #include #include +#include + #include #include #include @@ -46,10 +49,6 @@ Q_DECLARE_METATYPE(QPointer) -static const int DocumentRole = Qt::UserRole + 1; -static const int UrlRole = Qt::UserRole + 2; -static const int SortFilterRole = Qt::UserRole + 3; - KateQuickOpen::KateQuickOpen(QWidget *parent, KateMainWindow *mainWindow) : QWidget(parent) , m_mainWindow(mainWindow) @@ -69,11 +68,11 @@ layout->addWidget(m_listView, 1); m_listView->setTextElideMode(Qt::ElideLeft); - m_base_model = new QStandardItemModel(0, 2, this); + m_base_model = new KateQuickOpenModel(m_mainWindow, this); m_model = new QSortFilterProxyModel(this); - m_model->setFilterRole(SortFilterRole); - m_model->setSortRole(SortFilterRole); + m_model->setFilterRole(Qt::DisplayRole); + m_model->setSortRole(Qt::DisplayRole); m_model->setFilterCaseSensitivity(Qt::CaseInsensitive); m_model->setSortCaseSensitivity(Qt::CaseInsensitive); @@ -144,161 +143,15 @@ void KateQuickOpen::update() { - /** - * new base mode creation - * remove from proxy model before populating to avoid wasting time - * with repeatedly sorting it - */ - m_base_model->clear(); - m_model->setSourceModel(nullptr); - - /** - * remember local file names to avoid dupes with project files - */ - QSet alreadySeenFiles; - QSet alreadySeenDocs; - - /** - * get views in lru order - */ - const QList sortedViews(m_mainWindow->viewManager()->sortedViews()); - - /** - * now insert them in order - */ - QModelIndex idxToSelect; - int linecount = 0; - foreach (KTextEditor::View *view, sortedViews) { - KTextEditor::Document *doc = view->document(); - - if (alreadySeenDocs.contains(doc)) { - continue; - } - - alreadySeenDocs.insert(doc); - - //QStandardItem *item=new QStandardItem(i18n("%1: %2",doc->documentName(),doc->url().toString())); - QStandardItem *itemName = new QStandardItem(doc->documentName()); - - itemName->setData(qVariantFromValue(QPointer (doc)), DocumentRole); - itemName->setData(QString::fromLatin1("%1: %2").arg(doc->documentName()).arg(doc->url().toString()), SortFilterRole); - itemName->setEditable(false); - QFont font = itemName->font(); - font.setBold(true); - itemName->setFont(font); - - QStandardItem *itemUrl = new QStandardItem(doc->url().toString()); - itemUrl->setEditable(false); - m_base_model->setItem(linecount, 0, itemName); - m_base_model->setItem(linecount, 1, itemUrl); - linecount++; - - if (!doc->url().isEmpty() && doc->url().isLocalFile()) { - alreadySeenFiles.insert(doc->url().toLocalFile()); - } - - // select second document, that is the last used (beside the active one) - if (linecount == 2) { - idxToSelect = itemName->index(); - } - } - - /** - * get all open documents - */ - QList docs = KateApp::self()->documentManager()->documentList(); - foreach(KTextEditor::Document * doc, docs) { - /** - * skip docs already open - */ - if (alreadySeenDocs.contains(doc)) { - continue; - } - - //QStandardItem *item=new QStandardItem(i18n("%1: %2",doc->documentName(),doc->url().toString())); - QStandardItem *itemName = new QStandardItem(doc->documentName()); - - itemName->setData(qVariantFromValue(QPointer (doc)), DocumentRole); - itemName->setData(QString::fromLatin1("%1: %2").arg(doc->documentName()).arg(doc->url().toString()), SortFilterRole); - itemName->setEditable(false); - QFont font = itemName->font(); - font.setBold(true); - itemName->setFont(font); - - QStandardItem *itemUrl = new QStandardItem(doc->url().toString()); - itemUrl->setEditable(false); - m_base_model->setItem(linecount, 0, itemName); - m_base_model->setItem(linecount, 1, itemUrl); - linecount++; - - if (!doc->url().isEmpty() && doc->url().isLocalFile()) { - alreadySeenFiles.insert(doc->url().toLocalFile()); - } - } - - /** - * insert all project files, if any project around - */ - if (QObject *projectView = m_mainWindow->pluginView(QStringLiteral("kateprojectplugin"))) { - QStringList projectFiles = projectView->property("projectFiles").toStringList(); - foreach(const QString & file, projectFiles) { - /** - * skip files already open - */ - if (alreadySeenFiles.contains(file)) { - continue; - } - - QFileInfo fi(file); - QStandardItem *itemName = new QStandardItem(fi.fileName()); - - itemName->setData(qVariantFromValue(QUrl::fromLocalFile(file)), UrlRole); - itemName->setData(QString::fromLatin1("%1: %2").arg(fi.fileName()).arg(file), SortFilterRole); - itemName->setEditable(false); - - QStandardItem *itemUrl = new QStandardItem(file); - itemUrl->setEditable(false); - m_base_model->setItem(linecount, 0, itemName); - m_base_model->setItem(linecount, 1, itemUrl); - linecount++; - } - } - - if (idxToSelect.isValid()) { - m_listView->setCurrentIndex(m_model->mapFromSource(idxToSelect)); - } else { - reselectFirst(); - } - - m_model->setSourceModel(m_base_model); - - /** - * adjust view - */ + m_base_model->refresh(); m_listView->resizeColumnToContents(0); } void KateQuickOpen::slotReturnPressed() { - /** - * open document for first element, if possible - * prefer to use the document pointer - */ - // our data is in column 0 (clicking on column 1 results in no data, therefore, create new index) - const QModelIndex index = m_listView->model()->index(m_listView->currentIndex().row(), 0); - KTextEditor::Document *doc = index.data(DocumentRole).value >(); - if (doc) { - m_mainWindow->wrapper()->activateView(doc); - } else { - QUrl url = index.data(UrlRole).value(); - if (!url.isEmpty()) { - m_mainWindow->wrapper()->openUrl(url); - } - } - - /** - * in any case, switch back to view manager - */ + const auto index = m_listView->model()->index(m_listView->currentIndex().row(), KateQuickOpenModel::Columns::FilePath); + auto url = QUrl(index.data(Qt::DisplayRole).toString()); + m_mainWindow->wrapper()->openUrl(url); m_mainWindow->slotWindowActivated(); m_inputLine->clear(); } diff --git a/kate/katequickopenmodel.h b/kate/katequickopenmodel.h new file mode 100644 --- /dev/null +++ b/kate/katequickopenmodel.h @@ -0,0 +1,32 @@ +#ifndef KATEQUICKOPENMODEL_H +#define KATEQUICKOPENMODEL_H + +#include +#include +#include +#include + +#include "katemainwindow.h" + +class KateQuickOpenModel : public QAbstractTableModel { + Q_OBJECT +public: + enum Columns : int { FileName, FilePath, Count }; + explicit KateQuickOpenModel(KateMainWindow *mainWindow, QObject *parent=nullptr); + int rowCount(const QModelIndex& parent) const override; + int columnCount(const QModelIndex& parent) const override; + QVariant data(const QModelIndex& idx, int role) const override; + void refresh(); + +private: + QVector> m_modelEntries; + + /* TODO: don't rely in a pointer to the main window. + * this is bad enginering, but current code is too tigth + * on this and it's hard to untangle without breaking existing + * code. + */ + KateMainWindow *m_mainWindow; +}; + +#endif diff --git a/kate/katequickopenmodel.cpp b/kate/katequickopenmodel.cpp new file mode 100644 --- /dev/null +++ b/kate/katequickopenmodel.cpp @@ -0,0 +1,88 @@ +#include "katequickopenmodel.h" + +#include "katemainwindow.h" +#include "kateviewmanager.h" +#include "kateapp.h" + +#include +#include + +KateQuickOpenModel::KateQuickOpenModel(KateMainWindow *mainWindow, QObject *parent) : + QAbstractTableModel (parent), m_mainWindow(mainWindow) +{ +} + +int KateQuickOpenModel::rowCount(const QModelIndex& parent) const +{ + Q_UNUSED(parent); + return m_modelEntries.size(); +} + +int KateQuickOpenModel::columnCount(const QModelIndex& parent) const +{ + Q_UNUSED(parent); + return static_cast(Columns::Count); +} + +QVariant KateQuickOpenModel::data(const QModelIndex& idx, int role) const +{ + if(! idx.isValid()) { + return {}; + } + + if (role != Qt::DisplayRole) { + return {}; + } + + switch(idx.column()) { + case Columns::FileName: return m_modelEntries.at(idx.row()).first; + case Columns::FilePath: return m_modelEntries.at(idx.row()).second; + } + + return {}; +} + +void KateQuickOpenModel::refresh() +{ + QObject *projectView = m_mainWindow->pluginView(QStringLiteral("kateprojectplugin")); + const QList sortedViews = m_mainWindow->viewManager()->sortedViews(); + const QList openDocs = KateApp::self()->documentManager()->documentList(); + const QStringList projectDocs = projectView ? projectView->property("projectFiles").toStringList() : QStringList(); + + using DocumentTuple = QPair; + + QVector allDocuments; + allDocuments.resize(sortedViews.size() + openDocs.size() + projectDocs.size()); + + for (auto *view : qAsConst(sortedViews)) { + auto doc = view->document(); + allDocuments.push_back({ doc->documentName(), doc->url().toString(QUrl::NormalizePathSegments) }); + } + + for (auto *doc : qAsConst(openDocs)) { + allDocuments.push_back({ doc->documentName(), doc->url().toString(QUrl::NormalizePathSegments) }); + } + + for (const auto& file : qAsConst(projectDocs)) { + QFileInfo fi(file); + allDocuments.push_back({ fi.fileName(), QUrl::fromLocalFile(file).toString(QUrl::NormalizePathSegments) }); + } + + /** Sort the arrays via Url. */ + std::sort(std::begin(allDocuments), std::end(allDocuments), + [](const DocumentTuple& a, const DocumentTuple& b) { + return a.second < b.second; + }); + + /** remove Duplicates. */ + allDocuments.erase( + std::unique(allDocuments.begin(), allDocuments.end(), + [](const DocumentTuple& a, const DocumentTuple& b) { + return a.second == b.second; + }), + std::end(allDocuments)); + + beginResetModel(); + m_modelEntries = allDocuments; + endResetModel(); +}