Commit d66bd8f3 authored by Tomaz  Canabrava's avatar Tomaz Canabrava
Browse files

WIP: Beginning of the Baloo/Search KCM Rewrite

Summary: Closes T7271

Reviewers: #plasma, mart, ngraham

Reviewed By: #plasma, mart, ngraham

Subscribers: GB_2, nicolasfella, mart, ngraham, plasma-devel

Tags: #plasma

Maniphest Tasks: T7271

Differential Revision: https://phabricator.kde.org/D23718
parent 310bdfd1
......@@ -3,27 +3,25 @@ add_definitions(-DTRANSLATION_DOMAIN=\"kcm5_baloofile\")
set(kcm_file_SRCS
kcm.cpp
fileexcludefilters.cpp
folderselectionwidget.cpp
)
ki18n_wrap_ui(kcm_file_SRCS
configwidget.ui
filteredfoldermodel.cpp
)
add_library(kcm_baloofile MODULE ${kcm_file_SRCS})
target_link_libraries(kcm_baloofile
KF5::KIOWidgets
KF5::CoreAddons
KF5::KCMUtils
KF5::I18n
KF5::Solid
KF5::Baloo
KF5::QuickAddons
Qt5::DBus
Qt5::Widgets
)
kcoreaddons_desktop_to_json(kcm_baloofile "kcm_baloofile.desktop")
install(FILES kcm_baloofile.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR})
install(TARGETS kcm_baloofile DESTINATION ${KDE_INSTALL_PLUGINDIR})
install(TARGETS kcm_baloofile DESTINATION ${KDE_INSTALL_PLUGINDIR}/kcms)
kpackage_install_package(package kcm_baloofile kcms)
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<author>Vishesh Handa</author>
<class>ConfigWidget</class>
<widget class="QWidget" name="ConfigWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>669</width>
<height>671</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="5">
<item>
<widget class="QLabel" name="m_mainLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>File Search helps you quickly locate all your files based on their content</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="m_enableCheckbox">
<property name="text">
<string>Enable File Search</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_enableContentIndexing">
<property name="text">
<string>Also index file content</string>
</property>
</widget>
</item>
<item>
<spacer name="middleSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>1</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="5">
<item>
<widget class="QLabel" name="m_excludeLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Do not search in these locations:</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="FolderSelectionWidget" name="m_excludeFolders_FSW" native="true"/>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>FolderSelectionWidget</class>
<extends>QWidget</extends>
<header>folderselectionwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
/*
* This file is part of the KDE Baloo Project
* Copyright (C) 2014 Vishesh Handa <me@vhanda.in>
* Copyright (C) 2019 Tomaz Canabrava <tcanabrava@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
......@@ -18,67 +19,27 @@
*
*/
#include "folderselectionwidget.h"
#include "filteredfoldermodel.h"
#include <Solid/Device>
#include <Solid/StorageAccess>
#include <Solid/StorageDrive>
#include <QIcon>
#include <QFileDialog>
#include <QDir>
#include <QTimer>
#include <QUrl>
#include <KLocalizedString>
#include <QSpacerItem>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
FolderSelectionWidget::FolderSelectionWidget(QWidget* parent, Qt::WindowFlags f)
: QWidget(parent, f)
{
m_listWidget = new QListWidget(this);
m_listWidget->setAlternatingRowColors(true);
m_messageWidget = new KMessageWidget(this);
m_messageWidget->hide();
QVBoxLayout* layout = new QVBoxLayout(this);
layout->addWidget(m_messageWidget);
layout->addWidget(m_listWidget);
QHBoxLayout* hLayout = new QHBoxLayout;
m_addButton = new QPushButton(this);
m_addButton->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
connect(m_addButton, &QPushButton::clicked, this, &FolderSelectionWidget::slotAddButtonClicked);
m_removeButton = new QPushButton(this);
m_removeButton->setIcon(QIcon::fromTheme(QStringLiteral("list-remove")));
m_removeButton->setEnabled(false);
connect(m_removeButton, &QPushButton::clicked, this, &FolderSelectionWidget::slotRemoveButtonClicked);
connect(m_listWidget, &QListWidget::currentItemChanged, this, &FolderSelectionWidget::slotCurrentItemChanged);
hLayout->addWidget(m_addButton);
hLayout->addWidget(m_removeButton);
QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum);
hLayout->addItem(spacer);
layout->addItem(hLayout);
}
#include <QStringList>
namespace {
QStringList addTrailingSlashes(const QStringList& input) {
QStringList output;
Q_FOREACH (QString str, input) {
QStringList output = input;
for (QString& str : output) {
if (!str.endsWith(QDir::separator()))
str.append(QDir::separator());
output << str;
}
return output;
......@@ -90,105 +51,100 @@ namespace {
return url;
}
}
void FolderSelectionWidget::setDirectoryList(QStringList includeDirs, QStringList exclude)
FilteredFolderModel::FilteredFolderModel(QObject* parent)
: QAbstractListModel(parent)
{
}
void FilteredFolderModel::setDirectoryList(const QStringList& include, const QStringList& exclude)
{
m_listWidget->clear();
beginResetModel();
m_mountPoints.clear();
QList<Solid::Device> devices
= Solid::Device::listFromType(Solid::DeviceInterface::StorageAccess);
QList<Solid::Device> devices = Solid::Device::listFromType(Solid::DeviceInterface::StorageAccess);
Q_FOREACH (const Solid::Device& dev, devices) {
for (const Solid::Device& dev : devices) {
const Solid::StorageAccess* sa = dev.as<Solid::StorageAccess>();
if (!sa->isAccessible())
continue;
QString mountPath = sa->filePath();
const QString mountPath = sa->filePath();
if (!shouldShowMountPoint(mountPath))
continue;
m_mountPoints << mountPath;
m_mountPoints.append(mountPath);
}
m_mountPoints << QDir::homePath();
m_mountPoints.append(QDir::homePath());
m_mountPoints = addTrailingSlashes(m_mountPoints);
includeDirs = addTrailingSlashes(includeDirs);
exclude = addTrailingSlashes(exclude);
QStringList excludeList = exclude;
Q_FOREACH (const QString& mountPath, m_mountPoints) {
if (includeDirs.contains(mountPath))
QStringList includeList = addTrailingSlashes(include);
m_excludeList = addTrailingSlashes(exclude);
// This algorithm seems bogus. verify later.
for (const QString& mountPath : m_mountPoints) {
if (includeList.contains(mountPath))
continue;
if (exclude.contains(mountPath))
continue;
if (!excludeList.contains(mountPath)) {
excludeList << mountPath;
if (!m_excludeList.contains(mountPath)) {
m_excludeList.append(mountPath);
}
}
Q_FOREACH (QString url, excludeList) {
QListWidgetItem* item = new QListWidgetItem(m_listWidget);
QString display = folderDisplayName(url);
item->setData(Qt::DisplayRole, display);
item->setData(Qt::WhatsThisRole, url);
item->setData(UrlRole, url);
item->setData(Qt::DecorationRole, QIcon::fromTheme(iconName(url)));
item->setToolTip(makeHomePretty(url));
m_listWidget->addItem(item);
}
if (m_listWidget->count() == 0) {
m_removeButton->setEnabled(false);
}
endResetModel();
}
QStringList FolderSelectionWidget::includeFolders() const
QVariant FilteredFolderModel::data(const QModelIndex& idx, int role) const
{
QStringList folders;
Q_FOREACH (const QString& mountPath, m_mountPoints) {
bool inExclude = false;
for (int i=0; i<m_listWidget->count(); ++i) {
QListWidgetItem* item = m_listWidget->item(i);
QString url = item->data(UrlRole).toString();
if (mountPath == url) {
inExclude = true;
break;
}
}
if (!idx.isValid() || idx.row() >= m_excludeList.size()) {
return {};
}
if (!inExclude && !folders.contains(mountPath)) {
folders << mountPath;
}
const auto currentUrl = m_excludeList.at(idx.row());
switch (role) {
case Qt::DisplayRole: return folderDisplayName(currentUrl);
case Qt::WhatsThisRole: return currentUrl;
case Qt::DecorationRole: return QIcon::fromTheme(iconName(currentUrl));
case Qt::ToolTipRole: return makeHomePretty(currentUrl);
case Url: return currentUrl;
case Folder: return folderDisplayName(currentUrl);
default:
return {};
}
return folders;
return {};
}
int FilteredFolderModel::rowCount(const QModelIndex& parent) const
{
Q_UNUSED(parent);
return m_excludeList.count();
}
QStringList FolderSelectionWidget::excludeFolders() const
QStringList FilteredFolderModel::includeFolders() const
{
QStringList folders;
for (int i=0; i<m_listWidget->count(); ++i) {
QListWidgetItem* item = m_listWidget->item(i);
QString url = item->data(UrlRole).toString();
const QSet<QString> mountPointSet =
QSet<QString>::fromList(m_mountPoints)
- QSet<QString>::fromList(m_excludeList);
if (!folders.contains(url)) {
folders << url;
}
}
return mountPointSet.toList();
}
return folders;
QStringList FilteredFolderModel::excludeFolders() const
{
return m_excludeList;
}
QString FolderSelectionWidget::fetchMountPoint(const QString& url) const
QString FilteredFolderModel::fetchMountPoint(const QString& url) const
{
QString mountPoint;
Q_FOREACH (const QString& mount, m_mountPoints) {
for (const QString& mount : qAsConst(m_mountPoints)) {
if (url.startsWith(mount) && mount.size() > mountPoint.size())
mountPoint = mount;
}
......@@ -197,98 +153,28 @@ QString FolderSelectionWidget::fetchMountPoint(const QString& url) const
}
void FolderSelectionWidget::slotAddButtonClicked()
void FilteredFolderModel::addFolder(const QString& url)
{
QString url = QFileDialog::getExistingDirectory(this, i18n("Select the folder which should be excluded"));
if (url.isEmpty()) {
if (m_excludeList.contains(url)) {
return;
}
if (!url.endsWith(QDir::separator()))
url.append(QDir::separator());
// We don't care about the root dir
if (url == QLatin1String("/")) {
showMessage(i18n("Not allowed to exclude root folder, please disable File Search if you do not want it"));
return;
}
// Remove any existing folder with that name
// Remove any folder which is a sub-folder
QVector<QListWidgetItem*> deleteList;
for (int i=0; i<m_listWidget->count(); ++i) {
QListWidgetItem* item = m_listWidget->item(i);
QString existingUrl = item->data(UrlRole).toString();
if (existingUrl == url) {
QString name = QUrl::fromLocalFile(url).fileName();
showMessage(i18n("Folder %1 is already excluded", name));
deleteList << item;
continue;
}
QString existingMountPoint = fetchMountPoint(existingUrl);
QString mountPoint = fetchMountPoint(url);
if (existingMountPoint == mountPoint) {
// existingUrl is not required since it comes under url
if (existingUrl.startsWith(url)) {
deleteList << item;
}
else if (url.startsWith(existingUrl)) {
// No point adding ourselves since our parents exists
// we just move the parent to the bottom
url = existingUrl;
deleteList << item;
QString name = QUrl::fromLocalFile(url).adjusted(QUrl::StripTrailingSlash).fileName();
showMessage(i18n("Folder's parent %1 is already excluded", name));
}
}
}
qDeleteAll(deleteList);
QListWidgetItem* item = new QListWidgetItem(m_listWidget);
QString displayName = folderDisplayName(url);
item->setData(Qt::DisplayRole, displayName);
item->setData(Qt::WhatsThisRole, url);
item->setData(UrlRole, url);
item->setData(Qt::DecorationRole, QIcon::fromTheme(iconName(url)));
item->setToolTip(makeHomePretty(url));
m_listWidget->addItem(item);
m_listWidget->setCurrentItem(item);
Q_EMIT changed();
}
void FolderSelectionWidget::slotRemoveButtonClicked()
{
QListWidgetItem* item = m_listWidget->currentItem();
delete item;
Q_EMIT changed();
}
void FolderSelectionWidget::slotCurrentItemChanged(QListWidgetItem* current, QListWidgetItem*)
{
m_removeButton->setEnabled(current != nullptr);
beginResetModel();
m_excludeList.append(QUrl(url).toLocalFile());
std::sort(std::begin(m_excludeList), std::end(m_excludeList));
endResetModel();
Q_EMIT folderAdded();
}
void FolderSelectionWidget::showMessage(const QString& message)
void FilteredFolderModel::removeFolder(int row)
{
m_messageWidget->setText(message);
m_messageWidget->setMessageType(KMessageWidget::Warning);
m_messageWidget->animatedShow();
QTimer::singleShot(3000, m_messageWidget, &KMessageWidget::animatedHide);
beginRemoveRows(QModelIndex(), row, row);
m_excludeList.removeAt(row);
endRemoveRows();
Q_EMIT folderRemoved();
}
QString FolderSelectionWidget::folderDisplayName(const QString& url) const
QString FilteredFolderModel::folderDisplayName(const QString& url) const
{
QString name = url;
......@@ -303,7 +189,7 @@ QString FolderSelectionWidget::folderDisplayName(const QString& url) const
}
else {
// Check Mount allMountPointsExcluded
Q_FOREACH (QString mountPoint, m_mountPoints) {
for (QString mountPoint : m_mountPoints) {
if (url.startsWith(mountPoint)) {
name = QLatin1Char('[') + QDir(mountPoint).dirName() + QLatin1String("]/") + url.mid(mountPoint.length());
break;
......@@ -317,7 +203,7 @@ QString FolderSelectionWidget::folderDisplayName(const QString& url) const
return name;
}
bool FolderSelectionWidget::shouldShowMountPoint(const QString& mountPoint)
bool FilteredFolderModel::shouldShowMountPoint(const QString& mountPoint)
{
if (mountPoint == QLatin1String("/"))
return false;
......@@ -330,13 +216,19 @@ bool FolderSelectionWidget::shouldShowMountPoint(const QString& mountPoint)
// The user's home directory is forcibly added so we can ignore /home
// if /home actually contains the home directory
if (mountPoint.startsWith(QLatin1String("/home")) && QDir::homePath().startsWith(QLatin1String("/home")))
return false;
return !(mountPoint.startsWith(QLatin1String("/home")) || !QDir::homePath().startsWith(QLatin1String("/home")));
}
return true;
QHash<int, QByteArray> FilteredFolderModel::roleNames() const
{
return {
{Url, "url"},
{Folder, "folder"},
{Qt::DecorationRole, "decoration"}
};
}
QString FolderSelectionWidget::iconName(QString path) const
QString FilteredFolderModel::iconName(QString path) const
{
// Ensure paths end with /
if (!path.endsWith(QDir::separator()))
......
......@@ -21,32 +21,32 @@
#ifndef FOLDERSELECTIONWIDGET_H
#define FOLDERSELECTIONWIDGET_H
#include <QWidget>
#include <QListWidget>
#include <QPushButton>
#include <KMessageWidget>
#include <QAbstractListModel>
class FolderSelectionWidget : public QWidget
class FilteredFolderModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit FolderSelectionWidget(QWidget* parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
explicit FilteredFolderModel(QObject* parent);
void setDirectoryList(QStringList includeDirs, QStringList exclude);
void setDirectoryList(const QStringList& includeDirs, const QStringList& exclude);
QStringList includeFolders() const;
QStringList excludeFolders() const;
enum Roles {
UrlRole = Qt::UserRole + 1
Folder = Qt::UserRole + 1,
Url
};
Q_SIGNALS:
void changed();
QVariant data(const QModelIndex& idx, int role) const override;
int rowCount(const QModelIndex& parent) const override;
private Q_SLOTS:
void slotAddButtonClicked();
void slotRemoveButtonClicked();
void slotCurrentItemChanged(QListWidgetItem* current, QListWidgetItem*);
Q_INVOKABLE void addFolder(const QString& folder);
Q_INVOKABLE void removeFolder(int row);
QHash<int, QByteArray> roleNames() const override;
Q_SIGNALS:
void folderAdded();
void folderRemoved();
private:
QString folderDisplayName(const QString& url) const;
......@@ -66,25 +66,8 @@ private:
* @brief Widget with the list of directories.
*
*/
QListWidget* m_listWidget;
QStringList m_mountPoints;
/**
* @brief Button to add a directory to the list.
*
*/
QPushButton* m_addButton;
/**
* @brief Button to remove the selected directory from the list.
*
*/
QPushButton* m_removeButton;
/**
* @brief Information, warning or error message widget.
*
*/
KMessageWidget* m_messageWidget;
QStringList m_excludeList;
};
#endif // FOLDERSELECTIONWIDGET_H
......@@ -19,7 +19,6 @@
#include "kcm.h"
#include "fileexcludefilters.h"