Skip to content

Commit

Permalink
Added search filter to the Objects view
Browse files Browse the repository at this point in the history
Thanks to @thabetx for working on the initial implementation of this
in pull request #1566. This patch takes some ideas from there, but it's
rewritten from scratch.

The biggest difference is that after changing the implementation of the
ReversingProxyModel to be based on QSortFilterProxyModel, this patch can
now apply the filter directly instead of needing to use another proxy
model. This makes the patch a lot smaller.

Closes #1467
Closes #1566
  • Loading branch information
bjorn committed Jul 17, 2019
1 parent e248604 commit 7fd47c5
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 8 deletions.
7 changes: 7 additions & 0 deletions src/tiled/filteredit.cpp
Expand Up @@ -51,6 +51,13 @@ bool FilterEdit::event(QEvent *event)
QCoreApplication::sendEvent(mFilteredView, event);
return true;
}

if (event->type() == QEvent::KeyPress && key == Qt::Key_Escape) {
if (!text().isEmpty()) {
clear();
return true;
}
}
break;
}
default:
Expand Down
9 changes: 9 additions & 0 deletions src/tiled/objectsdock.cpp
Expand Up @@ -21,6 +21,7 @@
#include "objectsdock.h"

#include "documentmanager.h"
#include "filteredit.h"
#include "grouplayer.h"
#include "map.h"
#include "mapdocument.h"
Expand All @@ -44,6 +45,7 @@ using namespace Tiled;

ObjectsDock::ObjectsDock(QWidget *parent)
: QDockWidget(parent)
, mFilterEdit(new FilterEdit(this))
, mObjectsView(new ObjectsView)
, mMapDocument(nullptr)
{
Expand All @@ -61,8 +63,13 @@ ObjectsDock::ObjectsDock(QWidget *parent)
QVBoxLayout *layout = new QVBoxLayout(widget);
layout->setMargin(0);
layout->setSpacing(0);
layout->addWidget(mFilterEdit);
layout->addWidget(mObjectsView);

mFilterEdit->setFilteredView(mObjectsView);

connect(mFilterEdit, &QLineEdit::textChanged, mObjectsView, &ObjectsView::setFilter);

mActionNewLayer = new QAction(this);
mActionNewLayer->setIcon(QIcon(QLatin1String(":/images/16x16/document-new.png")));
connect(mActionNewLayer, &QAction::triggered,
Expand Down Expand Up @@ -161,6 +168,8 @@ void ObjectsDock::retranslateUi()
{
setWindowTitle(tr("Objects"));

mFilterEdit->setPlaceholderText(tr("Filter"));

mActionNewLayer->setToolTip(tr("Add Object Layer"));
mActionObjectProperties->setToolTip(tr("Object Properties"));
mActionMoveUp->setToolTip(tr("Move Objects Up"));
Expand Down
2 changes: 2 additions & 0 deletions src/tiled/objectsdock.h
Expand Up @@ -28,6 +28,7 @@ class QMenu;
namespace Tiled {

class Document;
class FilterEdit;
class MapDocument;
class ObjectsView;

Expand Down Expand Up @@ -61,6 +62,7 @@ private slots:
QAction *mActionMoveUp;
QAction *mActionMoveDown;

FilterEdit *mFilterEdit;
ObjectsView *mObjectsView;
MapDocument *mMapDocument;
QMenu *mMoveToMenu;
Expand Down
89 changes: 86 additions & 3 deletions src/tiled/objectsview.cpp
Expand Up @@ -41,14 +41,53 @@ namespace Tiled {
static const char FIRST_COLUMN_WIDTH_KEY[] = "ObjectsDock/FirstSectionSize";
static const char VISIBLE_COLUMNS_KEY[] = "ObjectsDock/VisibleSections";

class ObjectsFilterModel : public ReversingProxyModel
{
Q_OBJECT

public:
ObjectsFilterModel(QObject *parent = nullptr)
: ReversingProxyModel(parent)
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
setRecursiveFilteringEnabled(true);
#endif
}

#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
return filterRecursiveAcceptsRow(sourceRow, sourceParent);
}

private:
bool filterRecursiveAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
if (ReversingProxyModel::filterAcceptsRow(sourceRow, sourceParent))
return true;

const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
const int count = sourceModel()->rowCount(index);

for (int i = 0; i < count; ++i)
if (filterRecursiveAcceptsRow(i, index))
return true;

return false;
}
#endif
};

ObjectsView::ObjectsView(QWidget *parent)
: QTreeView(parent)
, mMapDocument(nullptr)
, mProxyModel(new ReversingProxyModel(this))
, mSynching(false)
, mProxyModel(new ObjectsFilterModel(this))
{
setMouseTracking(true);

mProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
mProxyModel->setFilterKeyColumn(-1);

setUniformRowHeights(true);
setModel(mProxyModel);
setItemDelegate(new IconCheckDelegate(IconCheckDelegate::VisibilityIcon, false, this));
Expand Down Expand Up @@ -97,6 +136,9 @@ void ObjectsView::setMapDocument(MapDocument *mapDoc)

restoreVisibleColumns();
synchronizeSelectedItems();

if (mActiveFilter)
expandAll();
} else {
mProxyModel->setSourceModel(nullptr);
}
Expand All @@ -117,8 +159,31 @@ QModelIndex ObjectsView::layerViewIndex(Layer *layer) const
return QModelIndex();
}

void ObjectsView::setFilter(const QString &filter)
{
const bool hadActiveFilter = mActiveFilter;
const bool activeFilter = !filter.isEmpty();

if (!hadActiveFilter && activeFilter)
saveExpandedGroups();

mProxyModel->setFilterFixedString(filter);
mActiveFilter = activeFilter;

if (activeFilter) {
expandAll(); // Expand to see all results
} else if (hadActiveFilter) {
collapseAll();
restoreExpandedGroups();
expandToSelectedObjects();
}
}

void ObjectsView::saveExpandedGroups()
{
if (mActiveFilter)
return;

mExpandedGroups[mMapDocument].clear();

for (Layer *layer : mMapDocument->map()->objectGroups()) {
Expand All @@ -131,6 +196,9 @@ void ObjectsView::saveExpandedGroups()

void ObjectsView::restoreExpandedGroups()
{
if (mActiveFilter)
return;

const auto objectGroups = mExpandedGroups.take(mMapDocument);
for (Layer *layer : objectGroups) {
const QModelIndex sourceIndex = mMapDocument->mapObjectModel()->index(layer);
Expand Down Expand Up @@ -348,6 +416,19 @@ void ObjectsView::synchronizeSelectedItems()
mSynching = false;
}

void ObjectsView::expandToSelectedObjects()
{
const QList<MapObject *> &selectedObjects = mMapDocument->selectedObjects();
for (auto object : selectedObjects) {
auto index = mProxyModel->mapFromSource(mapObjectModel()->index(object));

// Make sure all parents are expanded
for (QModelIndex parent = index.parent(); parent.isValid(); parent = parent.parent())
if (!isExpanded(parent))
expand(parent);
}
}

void ObjectsView::updateRow(MapObject *object)
{
if (!object || !object->objectGroup())
Expand All @@ -361,3 +442,5 @@ void ObjectsView::updateRow(MapObject *object)
}

} // namespace Tiled

#include "objectsview.moc"
13 changes: 8 additions & 5 deletions src/tiled/objectsview.h
Expand Up @@ -23,15 +23,14 @@

#include <QTreeView>

class QAbstractProxyModel;

namespace Tiled {

class Layer;
class MapObject;

class MapDocument;
class MapObjectModel;
class ObjectsFilterModel;

class ObjectsView : public QTreeView
{
Expand All @@ -48,6 +47,8 @@ class ObjectsView : public QTreeView

QModelIndex layerViewIndex(Layer *layer) const;

void setFilter(const QString &filter);

public slots:
void saveExpandedGroups();
void restoreExpandedGroups();
Expand Down Expand Up @@ -77,13 +78,15 @@ private slots:
private:
void restoreVisibleColumns();
void synchronizeSelectedItems();
void expandToSelectedObjects();

void updateRow(MapObject *object);

MapDocument *mMapDocument;
QAbstractProxyModel *mProxyModel;
MapDocument *mMapDocument = nullptr;
ObjectsFilterModel *mProxyModel;
QMap<MapDocument*, QList<Layer*> > mExpandedGroups;
bool mSynching;
bool mSynching = false;
bool mActiveFilter = false;
};

} // namespace Tiled

0 comments on commit 7fd47c5

Please sign in to comment.