Commit c41abd2b authored by Friedemann Kleint's avatar Friedemann Kleint

DocSettingsPage: Add a filter line edit for the registered documentation.

Change the item view to a QListView and use a model derived from
QAbstractListModel keeping a QVector of entries. Use a QSortFilterProxyModel
for filtering.

This makes cleaning old documentation easier.

Change-Id: I3a0781e0ddff3d0c00126a1b4effe1e1c93e354b
Reviewed-by: default avatarEike Ziller <eike.ziller@theqtcompany.com>
parent caf2ca0a
...@@ -28,13 +28,104 @@ ...@@ -28,13 +28,104 @@
#include <coreplugin/helpmanager.h> #include <coreplugin/helpmanager.h>
#include <QCoreApplication>
#include <QFileDialog> #include <QFileDialog>
#include <QKeyEvent> #include <QKeyEvent>
#include <QMessageBox> #include <QMessageBox>
#include <QAbstractListModel>
#include <QCoreApplication>
#include <QDir>
#include <QSortFilterProxyModel>
#include <QVariant>
#include <QVector>
#include <algorithm>
using namespace Core; using namespace Core;
namespace Help {
namespace Internal {
class DocEntry
{
public:
QString name;
QString fileName;
QString nameSpace;
};
static bool operator<(const DocEntry &d1, const DocEntry &d2)
{ return d1.name < d2.name; }
static DocEntry createEntry(const QString &nameSpace, const QString &fileName, bool userManaged)
{
DocEntry result;
result.name = userManaged ? nameSpace : DocSettingsPage::tr("%1 (auto-detected)").arg(nameSpace);
result.fileName = fileName;
result.nameSpace = nameSpace;
return result;
}
class DocModel : public QAbstractListModel {
public:
typedef QVector<DocEntry> DocEntries;
explicit DocModel(const DocEntries &e = DocEntries(), QObject *parent = nullptr)
: QAbstractListModel(parent), m_docEntries(e) {}
int rowCount(const QModelIndex & = QModelIndex()) const override { return m_docEntries.size(); }
QVariant data(const QModelIndex &index, int role) const override;
void insertEntry(const DocEntry &e);
void removeAt(int row);
const DocEntry &entryAt(int row) const { return m_docEntries.at(row); }
private:
DocEntries m_docEntries;
};
QVariant DocModel::data(const QModelIndex &index, int role) const
{
QVariant result;
const int row = index.row();
if (index.isValid() && row < m_docEntries.size()) {
switch (role) {
case Qt::DisplayRole:
result = QVariant(m_docEntries.at(row).name);
break;
case Qt::ToolTipRole:
result = QVariant(QDir::toNativeSeparators(m_docEntries.at(row).fileName));
break;
case Qt::UserRole:
result = QVariant(m_docEntries.at(row).nameSpace);
break;
default:
break;
}
}
return result;
}
void DocModel::insertEntry(const DocEntry &e)
{
const auto it = std::lower_bound(m_docEntries.begin(), m_docEntries.end(), e);
const int index = int(it - m_docEntries.begin());
beginInsertRows(QModelIndex(), index, index);
m_docEntries.insert(it, e);
endInsertRows();
}
void DocModel::removeAt(int row)
{
beginRemoveRows(QModelIndex(), row, row);
m_docEntries.removeAt(row);
endRemoveRows();
}
} // namespace Internal
} // namespace Help
using namespace Help::Internal; using namespace Help::Internal;
DocSettingsPage::DocSettingsPage() DocSettingsPage::DocSettingsPage()
...@@ -49,25 +140,36 @@ DocSettingsPage::DocSettingsPage() ...@@ -49,25 +140,36 @@ DocSettingsPage::DocSettingsPage()
QWidget *DocSettingsPage::widget() QWidget *DocSettingsPage::widget()
{ {
if (!m_widget) { if (!m_widget) {
m_widget = new QWidget;
m_ui.setupUi(m_widget);
connect(m_ui.addButton, SIGNAL(clicked()), this, SLOT(addDocumentation()));
connect(m_ui.removeButton, SIGNAL(clicked()), this, SLOT(removeDocumentation()));
m_ui.docsListWidget->installEventFilter(this);
const QStringList nameSpaces = HelpManager::registeredNamespaces(); const QStringList nameSpaces = HelpManager::registeredNamespaces();
const QSet<QString> userDocumentationPaths = HelpManager::userDocumentationPaths(); const QSet<QString> userDocumentationPaths = HelpManager::userDocumentationPaths();
DocModel::DocEntries entries;
entries.reserve(nameSpaces.size());
foreach (const QString &nameSpace, nameSpaces) { foreach (const QString &nameSpace, nameSpaces) {
const QString filePath = HelpManager::fileFromNamespace(nameSpace); const QString filePath = HelpManager::fileFromNamespace(nameSpace);
bool user = userDocumentationPaths.contains(filePath); bool user = userDocumentationPaths.contains(filePath);
addItem(nameSpace, filePath, user); entries.append(createEntry(nameSpace, filePath, user));
m_filesToRegister.insert(nameSpace, filePath); m_filesToRegister.insert(nameSpace, filePath);
m_filesToRegisterUserManaged.insert(nameSpace, user); m_filesToRegisterUserManaged.insert(nameSpace, user);
} }
std::stable_sort(entries.begin(), entries.end());
m_filesToUnregister.clear(); m_filesToUnregister.clear();
m_widget = new QWidget;
m_ui.setupUi(m_widget);
m_model = new DocModel(entries, m_ui.docsListView);
m_proxyModel = new QSortFilterProxyModel(m_ui.docsListView);
m_proxyModel->setSourceModel(m_model);
m_ui.docsListView->setModel(m_proxyModel);
m_ui.filterLineEdit->setFiltering(true);
connect(m_ui.filterLineEdit, &QLineEdit::textChanged,
m_proxyModel, &QSortFilterProxyModel::setFilterFixedString);
connect(m_ui.addButton, &QAbstractButton::clicked, this, &DocSettingsPage::addDocumentation);
connect(m_ui.removeButton, &QAbstractButton::clicked, this,
[this] () { removeDocumentation(currentSelection()); });
m_ui.docsListView->installEventFilter(this);
} }
return m_widget; return m_widget;
} }
...@@ -97,7 +199,8 @@ void DocSettingsPage::addDocumentation() ...@@ -97,7 +199,8 @@ void DocSettingsPage::addDocumentation()
continue; continue;
} }
addItem(nameSpace, file, true/*user managed*/); m_model->insertEntry(createEntry(nameSpace, file, true /* user managed */));
m_filesToRegister.insert(nameSpace, filePath); m_filesToRegister.insert(nameSpace, filePath);
m_filesToRegisterUserManaged.insert(nameSpace, true/*user managed*/); m_filesToRegisterUserManaged.insert(nameSpace, true/*user managed*/);
...@@ -142,11 +245,6 @@ void DocSettingsPage::addDocumentation() ...@@ -142,11 +245,6 @@ void DocSettingsPage::addDocumentation()
} }
} }
void DocSettingsPage::removeDocumentation()
{
removeDocumentation(m_ui.docsListWidget->selectedItems());
}
void DocSettingsPage::apply() void DocSettingsPage::apply()
{ {
HelpManager::unregisterDocumentation(m_filesToUnregister.keys()); HelpManager::unregisterDocumentation(m_filesToUnregister.keys());
...@@ -169,14 +267,14 @@ void DocSettingsPage::finish() ...@@ -169,14 +267,14 @@ void DocSettingsPage::finish()
bool DocSettingsPage::eventFilter(QObject *object, QEvent *event) bool DocSettingsPage::eventFilter(QObject *object, QEvent *event)
{ {
if (object != m_ui.docsListWidget) if (object != m_ui.docsListView)
return IOptionsPage::eventFilter(object, event); return IOptionsPage::eventFilter(object, event);
if (event->type() == QEvent::KeyPress) { if (event->type() == QEvent::KeyPress) {
QKeyEvent *ke = static_cast<QKeyEvent*>(event); QKeyEvent *ke = static_cast<QKeyEvent*>(event);
switch (ke->key()) { switch (ke->key()) {
case Qt::Key_Delete: case Qt::Key_Delete:
removeDocumentation(m_ui.docsListWidget->selectedItems()); removeDocumentation(currentSelection());
break; break;
default: break; default: break;
} }
...@@ -185,32 +283,32 @@ bool DocSettingsPage::eventFilter(QObject *object, QEvent *event) ...@@ -185,32 +283,32 @@ bool DocSettingsPage::eventFilter(QObject *object, QEvent *event)
return IOptionsPage::eventFilter(object, event); return IOptionsPage::eventFilter(object, event);
} }
void DocSettingsPage::removeDocumentation(const QList<QListWidgetItem*> &items) void DocSettingsPage::removeDocumentation(const QList<QModelIndex> &items)
{ {
if (items.isEmpty()) if (items.isEmpty())
return; return;
int row = 0; for (int i = items.size() - 1; i >= 0; --i) {
foreach (QListWidgetItem* item, items) { const int row = items.at(i).row();
const QString nameSpace = item->data(Qt::UserRole).toString(); const QString nameSpace = m_model->entryAt(row).nameSpace;
m_filesToRegister.remove(nameSpace); m_filesToRegister.remove(nameSpace);
m_filesToRegisterUserManaged.remove(nameSpace); m_filesToRegisterUserManaged.remove(nameSpace);
m_filesToUnregister.insertMulti(nameSpace, QDir::cleanPath(HelpManager::fileFromNamespace(nameSpace))); m_filesToUnregister.insertMulti(nameSpace, QDir::cleanPath(HelpManager::fileFromNamespace(nameSpace)));
row = m_ui.docsListWidget->row(item); m_model->removeAt(row);
delete m_ui.docsListWidget->takeItem(row);
} }
m_ui.docsListWidget->setCurrentRow(qMax(row - 1, 0), const int newlySelectedRow = qMax(items.constFirst().row() - 1, 0);
QItemSelectionModel::ClearAndSelect); const QModelIndex index = m_proxyModel->mapFromSource(m_model->index(newlySelectedRow));
m_ui.docsListView->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
} }
void DocSettingsPage::addItem(const QString &nameSpace, const QString &fileName, bool userManaged) QList<QModelIndex> DocSettingsPage::currentSelection() const
{ {
const QString name = userManaged ? nameSpace : tr("%1 (auto-detected)").arg(nameSpace); QModelIndexList result;
QListWidgetItem* item = new QListWidgetItem(name); Q_ASSERT(!m_widget.isNull());
item->setToolTip(fileName); foreach (const QModelIndex &index, m_ui.docsListView->selectionModel()->selectedRows())
item->setData(Qt::UserRole, nameSpace); result.append(m_proxyModel->mapToSource(index));
m_ui.docsListWidget->addItem(item); return result;
} }
...@@ -29,11 +29,17 @@ ...@@ -29,11 +29,17 @@
#include "ui_docsettingspage.h" #include "ui_docsettingspage.h"
#include <coreplugin/dialogs/ioptionspage.h> #include <coreplugin/dialogs/ioptionspage.h>
#include <QList>
#include <QPointer> #include <QPointer>
QT_FORWARD_DECLARE_CLASS(QSortFilterProxyModel)
QT_FORWARD_DECLARE_CLASS(QModelIndex)
namespace Help { namespace Help {
namespace Internal { namespace Internal {
class DocModel;
class DocSettingsPage : public Core::IOptionsPage class DocSettingsPage : public Core::IOptionsPage
{ {
Q_OBJECT Q_OBJECT
...@@ -47,14 +53,14 @@ public: ...@@ -47,14 +53,14 @@ public:
private slots: private slots:
void addDocumentation(); void addDocumentation();
void removeDocumentation();
private: private:
bool eventFilter(QObject *object, QEvent *event); bool eventFilter(QObject *object, QEvent *event);
void removeDocumentation(const QList<QListWidgetItem *> &items); void removeDocumentation(const QList<QModelIndex> &items);
void addItem(const QString &nameSpace, const QString &fileName, bool userManaged);
private: private:
QList<QModelIndex> currentSelection() const;
Ui::DocSettingsPage m_ui; Ui::DocSettingsPage m_ui;
QPointer<QWidget> m_widget; QPointer<QWidget> m_widget;
...@@ -64,6 +70,9 @@ private: ...@@ -64,6 +70,9 @@ private:
NameSpaceToPathHash m_filesToRegister; NameSpaceToPathHash m_filesToRegister;
QHash<QString, bool> m_filesToRegisterUserManaged; QHash<QString, bool> m_filesToRegisterUserManaged;
NameSpaceToPathHash m_filesToUnregister; NameSpaceToPathHash m_filesToUnregister;
QSortFilterProxyModel *m_proxyModel = nullptr;
DocModel *m_model = nullptr;
}; };
} // namespace Help } // namespace Help
......
...@@ -21,17 +21,21 @@ ...@@ -21,17 +21,21 @@
</property> </property>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
<item> <item>
<widget class="QListWidget" name="docsListWidget"> <layout class="QVBoxLayout" name="verticalLayout_2">
<property name="selectionMode"> <item>
<enum>QAbstractItemView::ExtendedSelection</enum> <widget class="Utils::FancyLineEdit" name="filterLineEdit"/>
</property> </item>
<property name="uniformItemSizes"> <item>
<bool>true</bool> <widget class="QListView" name="docsListView">
</property> <property name="selectionMode">
<property name="sortingEnabled"> <enum>QAbstractItemView::ExtendedSelection</enum>
<bool>true</bool> </property>
</property> <property name="uniformItemSizes">
</widget> <bool>true</bool>
</property>
</widget>
</item>
</layout>
</item> </item>
<item> <item>
<layout class="QVBoxLayout" name="_4"> <layout class="QVBoxLayout" name="_4">
...@@ -69,6 +73,13 @@ ...@@ -69,6 +73,13 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets>
<customwidget>
<class>Utils::FancyLineEdit</class>
<extends>QLineEdit</extends>
<header location="global">utils/fancylineedit.h</header>
</customwidget>
</customwidgets>
<resources/> <resources/>
<connections/> <connections/>
</ui> </ui>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment