OSDN Git Service

Update license.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qmljseditor / qmljsoutline.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
8 **
9 **
10 ** GNU Lesser General Public License Usage
11 **
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 **
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 **
23 ** Other Usage
24 **
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **************************************************************************/
32
33 #include "qmljsoutline.h"
34 #include "qmloutlinemodel.h"
35 #include "qmljseditoreditable.h"
36 #include "qmljsoutlinetreeview.h"
37
38 #include <coreplugin/icore.h>
39 #include <coreplugin/ifile.h>
40 #include <coreplugin/editormanager/editormanager.h>
41
42 #include <QtCore/QDebug>
43 #include <QtCore/QSettings>
44 #include <QtGui/QAction>
45 #include <QtGui/QVBoxLayout>
46 #include <QtGui/QTextBlock>
47
48 using namespace QmlJS;
49
50 enum {
51     debug = false
52 };
53
54 namespace QmlJSEditor {
55 namespace Internal {
56
57
58 QmlJSOutlineFilterModel::QmlJSOutlineFilterModel(QObject *parent) :
59     QSortFilterProxyModel(parent)
60 {
61     setDynamicSortFilter(true);
62 }
63
64 bool QmlJSOutlineFilterModel::filterAcceptsRow(int sourceRow,
65                                                const QModelIndex &sourceParent) const
66 {
67     if (m_filterBindings) {
68         QModelIndex sourceIndex = sourceModel()->index(sourceRow, 0, sourceParent);
69         QVariant itemType = sourceIndex.data(QmlOutlineModel::ItemTypeRole);
70         if (itemType == QmlOutlineModel::NonElementBindingType) {
71             return false;
72         }
73     }
74     return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
75 }
76
77 QVariant QmlJSOutlineFilterModel::data(const QModelIndex &index, int role) const
78 {
79     if (role == QmlOutlineModel::AnnotationRole) {
80         // Don't show element id etc behind element if the property is also visible
81         if (!filterBindings()
82                 && index.data(QmlOutlineModel::ItemTypeRole) == QmlOutlineModel::ElementType) {
83             return QVariant();
84         }
85     }
86     return QSortFilterProxyModel::data(index, role);
87 }
88
89 bool QmlJSOutlineFilterModel::filterBindings() const
90 {
91     return m_filterBindings;
92 }
93
94 void QmlJSOutlineFilterModel::setFilterBindings(bool filterBindings)
95 {
96     m_filterBindings = filterBindings;
97     invalidateFilter();
98 }
99
100 QmlJSOutlineWidget::QmlJSOutlineWidget(QWidget *parent) :
101     TextEditor::IOutlineWidget(parent),
102     m_treeView(new QmlJSOutlineTreeView(this)),
103     m_filterModel(new QmlJSOutlineFilterModel(this)),
104     m_editor(0),
105     m_enableCursorSync(true),
106     m_blockCursorSync(false)
107 {
108     m_filterModel->setFilterBindings(false);
109
110     m_treeView->setModel(m_filterModel);
111
112     QVBoxLayout *layout = new QVBoxLayout;
113
114     layout->setMargin(0);
115     layout->setSpacing(0);
116     layout->addWidget(m_treeView);
117
118     m_showBindingsAction = new QAction(this);
119     m_showBindingsAction->setText(tr("Show All Bindings"));
120     m_showBindingsAction->setCheckable(true);
121     m_showBindingsAction->setChecked(true);
122     connect(m_showBindingsAction, SIGNAL(toggled(bool)), this, SLOT(setShowBindings(bool)));
123
124     setLayout(layout);
125 }
126
127 void QmlJSOutlineWidget::setEditor(QmlJSTextEditorWidget *editor)
128 {
129     m_editor = editor;
130
131     m_filterModel->setSourceModel(m_editor->outlineModel());
132     modelUpdated();
133
134     connect(m_treeView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
135             this, SLOT(updateSelectionInText(QItemSelection)));
136
137     connect(m_treeView, SIGNAL(doubleClicked(QModelIndex)),
138             this, SLOT(updateTextCursor(QModelIndex)));
139
140     connect(m_editor, SIGNAL(outlineModelIndexChanged(QModelIndex)),
141             this, SLOT(updateSelectionInTree(QModelIndex)));
142     connect(m_editor->outlineModel(), SIGNAL(updated()),
143             this, SLOT(modelUpdated()));
144 }
145
146 QList<QAction*> QmlJSOutlineWidget::filterMenuActions() const
147 {
148     QList<QAction*> list;
149     list.append(m_showBindingsAction);
150     return list;
151 }
152
153 void QmlJSOutlineWidget::setCursorSynchronization(bool syncWithCursor)
154 {
155     m_enableCursorSync = syncWithCursor;
156     if (m_enableCursorSync)
157         updateSelectionInTree(m_editor->outlineModelIndex());
158 }
159
160 void QmlJSOutlineWidget::restoreSettings(int position)
161 {
162     QSettings *settings = Core::ICore::instance()->settings();
163     bool showBindings = settings->value("QmlJSOutline."+QString::number(position)+".ShowBindings", true).toBool();
164     m_showBindingsAction->setChecked(showBindings);
165 }
166
167 void QmlJSOutlineWidget::saveSettings(int position)
168 {
169     QSettings *settings = Core::ICore::instance()->settings();
170     settings->setValue("QmlJSOutline."+QString::number(position)+".ShowBindings",
171                        m_showBindingsAction->isChecked());
172 }
173
174 void QmlJSOutlineWidget::modelUpdated()
175 {
176     m_treeView->expandAll();
177 }
178
179 void QmlJSOutlineWidget::updateSelectionInTree(const QModelIndex &index)
180 {
181     if (!syncCursor())
182         return;
183
184     m_blockCursorSync = true;
185
186     QModelIndex baseIndex = index;
187     QModelIndex filterIndex = m_filterModel->mapFromSource(baseIndex);
188     while (baseIndex.isValid() && !filterIndex.isValid()) { // Search for ancestor index actually shown
189         baseIndex = baseIndex.parent();
190         filterIndex = m_filterModel->mapFromSource(baseIndex);
191     }
192
193     m_treeView->selectionModel()->select(filterIndex, QItemSelectionModel::ClearAndSelect);
194     m_treeView->scrollTo(filterIndex);
195     m_blockCursorSync = false;
196 }
197
198 void QmlJSOutlineWidget::updateSelectionInText(const QItemSelection &selection)
199 {
200     if (!syncCursor())
201         return;
202
203     if (!selection.indexes().isEmpty()) {
204         QModelIndex index = selection.indexes().first();
205
206         updateTextCursor(index);
207     }
208 }
209
210 void QmlJSOutlineWidget::updateTextCursor(const QModelIndex &index)
211 {
212     QModelIndex sourceIndex = m_filterModel->mapToSource(index);
213     AST::SourceLocation location = m_editor->outlineModel()->sourceLocation(sourceIndex);
214
215     if (!location.isValid())
216         return;
217
218     const QTextBlock lastBlock = m_editor->document()->lastBlock();
219     const uint textLength = lastBlock.position() + lastBlock.length();
220     if (location.offset >= textLength)
221         return;
222
223     Core::EditorManager *editorManager = Core::EditorManager::instance();
224     editorManager->cutForwardNavigationHistory();
225     editorManager->addCurrentPositionToNavigationHistory();
226
227     QTextCursor textCursor = m_editor->textCursor();
228     m_blockCursorSync = true;
229     textCursor.setPosition(location.offset);
230     m_editor->setTextCursor(textCursor);
231     m_editor->centerCursor();
232     m_blockCursorSync = false;
233 }
234
235 void QmlJSOutlineWidget::setShowBindings(bool showBindings)
236 {
237     m_filterModel->setFilterBindings(!showBindings);
238     modelUpdated();
239     updateSelectionInTree(m_editor->outlineModelIndex());
240 }
241
242 bool QmlJSOutlineWidget::syncCursor()
243 {
244     return m_enableCursorSync && !m_blockCursorSync;
245 }
246
247 bool QmlJSOutlineWidgetFactory::supportsEditor(Core::IEditor *editor) const
248 {
249     if (qobject_cast<QmlJSEditorEditable*>(editor))
250         return true;
251     return false;
252 }
253
254 TextEditor::IOutlineWidget *QmlJSOutlineWidgetFactory::createWidget(Core::IEditor *editor)
255 {
256     QmlJSOutlineWidget *widget = new QmlJSOutlineWidget;
257
258     QmlJSEditorEditable *qmlJSEditable = qobject_cast<QmlJSEditorEditable*>(editor);
259     QmlJSTextEditorWidget *qmlJSEditor = qobject_cast<QmlJSTextEditorWidget*>(qmlJSEditable->widget());
260     Q_ASSERT(qmlJSEditor);
261
262     widget->setEditor(qmlJSEditor);
263
264     return widget;
265 }
266
267 } // namespace Internal
268 } // namespace QmlJSEditor