From 679ccc3b74c1908f6720a7b98bcfabdc79e3d567 Mon Sep 17 00:00:00 2001
From: Kai Koehne <kai.koehne@nokia.com>
Date: Wed, 14 Jul 2010 16:46:54 +0200
Subject: [PATCH] QmlOutline: Add filter for hiding bindings (properties)

---
 src/plugins/coreplugin/core.qrc               |   1 +
 .../images/filtericon.png                     | Bin
 src/plugins/cppeditor/cppoutline.cpp          |   5 ++
 src/plugins/cppeditor/cppoutline.h            |   1 +
 .../projectexplorer/projectexplorer.qrc       |   1 -
 .../projectexplorer/projecttreewidget.cpp     |   2 +-
 src/plugins/projectexplorer/taskwindow.cpp    |   2 +-
 src/plugins/qmljseditor/qmljsoutline.cpp      |  57 +++++++++++++++++-
 src/plugins/qmljseditor/qmljsoutline.h        |  21 +++++++
 src/plugins/qmljseditor/qmloutlinemodel.cpp   |  18 ++++++
 src/plugins/qmljseditor/qmloutlinemodel.h     |   8 ++-
 src/plugins/texteditor/ioutlinewidget.h       |   1 +
 src/plugins/texteditor/outlinefactory.cpp     |  25 ++++++++
 src/plugins/texteditor/outlinefactory.h       |   5 ++
 14 files changed, 141 insertions(+), 6 deletions(-)
 rename src/plugins/{projectexplorer => coreplugin}/images/filtericon.png (100%)

diff --git a/src/plugins/coreplugin/core.qrc b/src/plugins/coreplugin/core.qrc
index 20e9cfb9a85..a06cdbf3c89 100644
--- a/src/plugins/coreplugin/core.qrc
+++ b/src/plugins/coreplugin/core.qrc
@@ -65,5 +65,6 @@
         <file>images/category_cpp.png</file>
         <file>images/category_vcs.png</file>
         <file>images/category_qml.png</file>
+	<file>images/filtericon.png</file>
     </qresource>
 </RCC>
diff --git a/src/plugins/projectexplorer/images/filtericon.png b/src/plugins/coreplugin/images/filtericon.png
similarity index 100%
rename from src/plugins/projectexplorer/images/filtericon.png
rename to src/plugins/coreplugin/images/filtericon.png
diff --git a/src/plugins/cppeditor/cppoutline.cpp b/src/plugins/cppeditor/cppoutline.cpp
index 146b060ae68..4e9fcfdbdaf 100644
--- a/src/plugins/cppeditor/cppoutline.cpp
+++ b/src/plugins/cppeditor/cppoutline.cpp
@@ -81,6 +81,11 @@ CppOutlineWidget::CppOutlineWidget(CPPEditor *editor) :
             this, SLOT(updateSelectionInText(QItemSelection)));
 }
 
+QList<QAction*> CppOutlineWidget::filterMenuActions() const
+{
+    return QList<QAction*>();
+}
+
 void CppOutlineWidget::setCursorSynchronization(bool syncWithCursor)
 {
     m_enableCursorSync = syncWithCursor;
diff --git a/src/plugins/cppeditor/cppoutline.h b/src/plugins/cppeditor/cppoutline.h
index 3eea8b3c65f..d007b9689de 100644
--- a/src/plugins/cppeditor/cppoutline.h
+++ b/src/plugins/cppeditor/cppoutline.h
@@ -37,6 +37,7 @@ public:
     CppOutlineWidget(CPPEditor *editor);
 
     // IOutlineWidget
+    virtual QList<QAction*> filterMenuActions() const;
     virtual void setCursorSynchronization(bool syncWithCursor);
 
 private slots:
diff --git a/src/plugins/projectexplorer/projectexplorer.qrc b/src/plugins/projectexplorer/projectexplorer.qrc
index 68c6d21728d..09cb165d569 100644
--- a/src/plugins/projectexplorer/projectexplorer.qrc
+++ b/src/plugins/projectexplorer/projectexplorer.qrc
@@ -6,7 +6,6 @@
         <file>images/closetab.png</file>
         <file>images/debugger_start.png</file>
         <file>images/debugger_start_small.png</file>
-        <file>images/filtericon.png</file>
         <file>images/projectexplorer.png</file>
         <file>images/rebuild.png</file>
         <file>images/rebuild_small.png</file>
diff --git a/src/plugins/projectexplorer/projecttreewidget.cpp b/src/plugins/projectexplorer/projecttreewidget.cpp
index 65179a51804..56495cf6394 100644
--- a/src/plugins/projectexplorer/projecttreewidget.cpp
+++ b/src/plugins/projectexplorer/projecttreewidget.cpp
@@ -396,7 +396,7 @@ Core::NavigationView ProjectTreeWidgetFactory::createWidget()
     n.widget = ptw;
 
     QToolButton *filter = new QToolButton;
-    filter->setIcon(QIcon(":/projectexplorer/images/filtericon.png"));
+    filter->setIcon(QIcon(":/core/images/filtericon.png"));
     filter->setToolTip(tr("Filter tree"));
     filter->setPopupMode(QToolButton::InstantPopup);
     QMenu *filterMenu = new QMenu(filter);
diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp
index e654f842c28..f71f3cb23fd 100644
--- a/src/plugins/projectexplorer/taskwindow.cpp
+++ b/src/plugins/projectexplorer/taskwindow.cpp
@@ -560,7 +560,7 @@ TaskWindow::TaskWindow(TaskHub *taskhub) : d(new TaskWindowPrivate)
     connect(d->m_categoriesMenu, SIGNAL(triggered(QAction*)), this, SLOT(filterCategoryTriggered(QAction*)));
 
     d->m_categoriesButton = new QToolButton;
-    d->m_categoriesButton->setIcon(QIcon(":/projectexplorer/images/filtericon.png"));
+    d->m_categoriesButton->setIcon(QIcon(":/core/images/filtericon.png"));
     d->m_categoriesButton->setToolTip(tr("Filter by categories"));
     d->m_categoriesButton->setAutoRaise(true);
     d->m_categoriesButton->setPopupMode(QToolButton::InstantPopup);
diff --git a/src/plugins/qmljseditor/qmljsoutline.cpp b/src/plugins/qmljseditor/qmljsoutline.cpp
index 4c018a5b6ed..7831670eec7 100644
--- a/src/plugins/qmljseditor/qmljsoutline.cpp
+++ b/src/plugins/qmljseditor/qmljsoutline.cpp
@@ -3,6 +3,7 @@
 
 #include <coreplugin/ifile.h>
 #include <coreplugin/editormanager/editormanager.h>
+#include <QtGui/QAction>
 #include <QtGui/QVBoxLayout>
 
 #include <QDebug>
@@ -29,18 +30,57 @@ QmlJSOutlineTreeView::QmlJSOutlineTreeView(QWidget *parent) :
     setExpandsOnDoubleClick(false);
 }
 
+QmlJSOutlineFilterModel::QmlJSOutlineFilterModel(QObject *parent) :
+    QSortFilterProxyModel(parent)
+{
+}
+
+bool QmlJSOutlineFilterModel::filterAcceptsRow(int sourceRow,
+                                               const QModelIndex &sourceParent) const
+{
+    if (m_filterBindings) {
+        QModelIndex sourceIndex = sourceModel()->index(sourceRow, 0, sourceParent);
+        if (sourceIndex.data(QmlOutlineModel::ItemTypeRole) == QmlOutlineModel::PropertyType) {
+            return false;
+        }
+    }
+    return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
+}
+
+bool QmlJSOutlineFilterModel::filterBindings() const
+{
+    return m_filterBindings;
+}
+
+void QmlJSOutlineFilterModel::setFilterBindings(bool filterBindings)
+{
+    if (m_filterBindings != filterBindings) {
+        m_filterBindings = filterBindings;
+        invalidateFilter();
+    }
+}
+
 QmlJSOutlineWidget::QmlJSOutlineWidget(QWidget *parent) :
     TextEditor::IOutlineWidget(parent),
     m_treeView(new QmlJSOutlineTreeView(this)),
+    m_filterModel(new QmlJSOutlineFilterModel(this)),
     m_enableCursorSync(true),
     m_blockCursorSync(false)
 {
+    m_treeView->setModel(m_filterModel);
+
     QVBoxLayout *layout = new QVBoxLayout;
 
     layout->setMargin(0);
     layout->setSpacing(0);
     layout->addWidget(m_treeView);
 
+    m_showBindingsAction = new QAction(this);
+    m_showBindingsAction->setText(tr("Show bindings"));
+    m_showBindingsAction->setCheckable(true);
+    m_showBindingsAction->setChecked(true);
+    connect(m_showBindingsAction, SIGNAL(triggered(bool)), this, SLOT(setShowBindings(bool)));
+
     setLayout(layout);
 }
 
@@ -48,7 +88,7 @@ void QmlJSOutlineWidget::setEditor(QmlJSTextEditor *editor)
 {
     m_editor = editor;
 
-    m_treeView->setModel(m_editor.data()->outlineModel());
+    m_filterModel->setSourceModel(m_editor.data()->outlineModel());
     modelUpdated();
 
     connect(m_treeView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
@@ -60,6 +100,13 @@ void QmlJSOutlineWidget::setEditor(QmlJSTextEditor *editor)
             this, SLOT(modelUpdated()));
 }
 
+QList<QAction*> QmlJSOutlineWidget::filterMenuActions() const
+{
+    QList<QAction*> list;
+    list.append(m_showBindingsAction);
+    return list;
+}
+
 void QmlJSOutlineWidget::setCursorSynchronization(bool syncWithCursor)
 {
     m_enableCursorSync = syncWithCursor;
@@ -78,7 +125,7 @@ void QmlJSOutlineWidget::updateSelectionInTree(const QModelIndex &index)
         return;
 
     m_blockCursorSync = true;
-    m_treeView->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
+    m_treeView->selectionModel()->select(m_filterModel->mapFromSource(index), QItemSelectionModel::ClearAndSelect);
     m_treeView->scrollTo(index);
     m_blockCursorSync = false;
 }
@@ -105,6 +152,12 @@ void QmlJSOutlineWidget::updateSelectionInText(const QItemSelection &selection)
     }
 }
 
+void QmlJSOutlineWidget::setShowBindings(bool showBindings)
+{
+    m_filterModel->setFilterBindings(!showBindings);
+    modelUpdated();
+}
+
 bool QmlJSOutlineWidget::syncCursor()
 {
     return m_enableCursorSync && !m_blockCursorSync;
diff --git a/src/plugins/qmljseditor/qmljsoutline.h b/src/plugins/qmljseditor/qmljsoutline.h
index c42685dd8d6..15221210cb9 100644
--- a/src/plugins/qmljseditor/qmljsoutline.h
+++ b/src/plugins/qmljseditor/qmljsoutline.h
@@ -6,6 +6,7 @@
 #include <texteditor/ioutlinewidget.h>
 
 #include <QtGui/QTreeView>
+#include <QtGui/QSortFilterProxyModel>
 
 namespace Core {
 class IEditor;
@@ -25,6 +26,21 @@ public:
     QmlJSOutlineTreeView(QWidget *parent = 0);
 };
 
+class QmlJSOutlineFilterModel : public QSortFilterProxyModel
+{
+    Q_OBJECT
+public:
+    QmlJSOutlineFilterModel(QObject *parent);
+    // QSortFilterProxyModel
+    bool filterAcceptsRow(int sourceRow,
+                          const QModelIndex &sourceParent) const;
+
+    bool filterBindings() const;
+    void setFilterBindings(bool filterBindings);
+private:
+    bool m_filterBindings;
+};
+
 class QmlJSOutlineWidget : public TextEditor::IOutlineWidget
 {
     Q_OBJECT
@@ -34,20 +50,25 @@ public:
     void setEditor(QmlJSTextEditor *editor);
 
     // IOutlineWidget
+    virtual QList<QAction*> filterMenuActions() const;
     virtual void setCursorSynchronization(bool syncWithCursor);
 
 private slots:
     void modelUpdated();
     void updateSelectionInTree(const QModelIndex &index);
     void updateSelectionInText(const QItemSelection &selection);
+    void setShowBindings(bool showBindings);
 
 private:
     bool syncCursor();
 
 private:
     QmlJSOutlineTreeView *m_treeView;
+    QmlJSOutlineFilterModel *m_filterModel;
     QWeakPointer<QmlJSTextEditor> m_editor;
 
+    QAction *m_showBindingsAction;
+
     bool m_enableCursorSync;
     bool m_blockCursorSync;
 };
diff --git a/src/plugins/qmljseditor/qmloutlinemodel.cpp b/src/plugins/qmljseditor/qmloutlinemodel.cpp
index ef2c8380136..7e38084d459 100644
--- a/src/plugins/qmljseditor/qmloutlinemodel.cpp
+++ b/src/plugins/qmljseditor/qmloutlinemodel.cpp
@@ -201,6 +201,22 @@ private:
     int indent;
 };
 
+class OutlineItem : public QStandardItem
+{
+    int type() const
+    {
+        return QStandardItem::UserType + 1;
+    }
+
+    QVariant data(int role = Qt::UserRole + 1) const
+    {
+        if (role == Qt::ToolTipRole) {
+
+        }
+        return QStandardItem::data(role);
+    }
+};
+
 QmlOutlineModel::QmlOutlineModel(QObject *parent) :
     QStandardItemModel(parent)
 {
@@ -238,6 +254,7 @@ QModelIndex QmlOutlineModel::enterElement(const QString &type, const QString &id
     }
     item->setIcon(icon);
     item->setToolTip(type);
+    item->setData(ElementType, ItemTypeRole);
     return item->index();
 }
 
@@ -255,6 +272,7 @@ QModelIndex QmlOutlineModel::enterProperty(const QString &name, bool isCustomPro
     } else {
         item->setIcon(m_icons->scriptBindingIcon());
     }
+    item->setData(PropertyType, ItemTypeRole);
     return item->index();
 }
 
diff --git a/src/plugins/qmljseditor/qmloutlinemodel.h b/src/plugins/qmljseditor/qmloutlinemodel.h
index 6b22538ed80..1363ef9b27e 100644
--- a/src/plugins/qmljseditor/qmloutlinemodel.h
+++ b/src/plugins/qmljseditor/qmloutlinemodel.h
@@ -14,7 +14,13 @@ class QmlOutlineModel : public QStandardItemModel
     Q_OBJECT
 public:
     enum CustomRoles {
-        SourceLocationRole = Qt::UserRole + 1
+        SourceLocationRole = Qt::UserRole + 1,
+        ItemTypeRole = SourceLocationRole + 1
+    };
+
+    enum ItemTypes {
+        ElementType,
+        PropertyType
     };
 
     QmlOutlineModel(QObject *parent = 0);
diff --git a/src/plugins/texteditor/ioutlinewidget.h b/src/plugins/texteditor/ioutlinewidget.h
index 1242b853561..1ac85f80740 100644
--- a/src/plugins/texteditor/ioutlinewidget.h
+++ b/src/plugins/texteditor/ioutlinewidget.h
@@ -16,6 +16,7 @@ class TEXTEDITOR_EXPORT IOutlineWidget : public QWidget
 public:
     IOutlineWidget(QWidget *parent = 0) : QWidget(parent) {}
 
+    virtual QList<QAction*> filterMenuActions() const = 0;
     virtual void setCursorSynchronization(bool syncWithCursor) = 0;
 };
 
diff --git a/src/plugins/texteditor/outlinefactory.cpp b/src/plugins/texteditor/outlinefactory.cpp
index f280458ce6f..dac2e6b8c67 100644
--- a/src/plugins/texteditor/outlinefactory.cpp
+++ b/src/plugins/texteditor/outlinefactory.cpp
@@ -1,4 +1,5 @@
 #include "outlinefactory.h"
+#include <coreplugin/icore.h>
 #include <coreplugin/editormanager/editormanager.h>
 #include <coreplugin/editormanager/ieditor.h>
 #include <QVBoxLayout>
@@ -31,6 +32,14 @@ OutlineWidgetStack::OutlineWidgetStack(OutlineFactory *factory) :
     m_toggleSync->setToolTip(tr("Synchronize with Editor"));
     connect(m_toggleSync, SIGNAL(clicked(bool)), this, SLOT(toggleCursorSynchronization()));
 
+    m_filterButton = new QToolButton;
+    m_filterButton->setIcon(QIcon(":/core/images/filtericon.png"));
+    m_filterButton->setToolTip(tr("Filter tree"));
+    m_filterButton->setPopupMode(QToolButton::InstantPopup);
+    m_filterMenu = new QMenu(m_filterButton);
+    m_filterButton->setMenu(m_filterMenu);
+    connect(m_filterMenu, SIGNAL(aboutToShow()), this, SLOT(updateFilterMenu()));
+
     Core::EditorManager *editorManager = Core::EditorManager::instance();
     connect(editorManager, SIGNAL(currentEditorChanged(Core::IEditor*)),
             this, SLOT(updateCurrentEditor(Core::IEditor*)));
@@ -46,6 +55,11 @@ QToolButton *OutlineWidgetStack::toggleSyncButton()
     return m_toggleSync;
 }
 
+QToolButton *OutlineWidgetStack::filterButton()
+{
+    return m_filterButton;
+}
+
 bool OutlineWidgetStack::isCursorSynchronized() const
 {
     return m_syncWithEditor;
@@ -58,6 +72,16 @@ void OutlineWidgetStack::toggleCursorSynchronization()
         outlineWidget->setCursorSynchronization(m_syncWithEditor);
 }
 
+void OutlineWidgetStack::updateFilterMenu()
+{
+    m_filterMenu->clear();
+    if (IOutlineWidget *outlineWidget = qobject_cast<IOutlineWidget*>(currentWidget())) {
+        foreach (QAction *filterAction, outlineWidget->filterMenuActions()) {
+            m_filterMenu->addAction(filterAction);
+        }
+    }
+}
+
 void OutlineWidgetStack::updateCurrentEditor(Core::IEditor *editor)
 {
     IOutlineWidget *newWidget = 0;
@@ -121,6 +145,7 @@ Core::NavigationView OutlineFactory::createWidget()
     OutlineWidgetStack *placeHolder = new OutlineWidgetStack(this);
     n.widget = placeHolder;
     n.dockToolBarWidgets.append(placeHolder->toggleSyncButton());
+    n.dockToolBarWidgets.append(placeHolder->filterButton());
     return n;
 }
 
diff --git a/src/plugins/texteditor/outlinefactory.h b/src/plugins/texteditor/outlinefactory.h
index c3b7b440c19..360ccbdd280 100644
--- a/src/plugins/texteditor/outlinefactory.h
+++ b/src/plugins/texteditor/outlinefactory.h
@@ -4,6 +4,7 @@
 #include <texteditor/ioutlinewidget.h>
 #include <coreplugin/inavigationwidgetfactory.h>
 #include <QtGui/QStackedWidget>
+#include <QtGui/QMenu>
 
 namespace Core {
 class IEditor;
@@ -22,6 +23,7 @@ public:
     ~OutlineWidgetStack();
 
     QToolButton *toggleSyncButton();
+    QToolButton *filterButton();
 
 private:
     bool isCursorSynchronized() const;
@@ -29,12 +31,15 @@ private:
 
 private slots:
     void toggleCursorSynchronization();
+    void updateFilterMenu();
     void updateCurrentEditor(Core::IEditor *editor);
 
 private:
     QStackedWidget *m_widgetStack;
     OutlineFactory *m_factory;
     QToolButton *m_toggleSync;
+    QToolButton *m_filterButton;
+    QMenu *m_filterMenu;
     bool m_syncWithEditor;
 };
 
-- 
GitLab