OSDN Git Service

43af00718890537f27ad1c11966bf29585af66c8
[qt-creator-jp/qt-creator-jp.git] / src / plugins / cppeditor / cppoutline.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 (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "cppoutline.h"
35
36 #include <TranslationUnit.h>
37 #include <Symbol.h>
38
39 #include <coreplugin/ifile.h>
40 #include <coreplugin/editormanager/editormanager.h>
41 #include <cplusplus/OverviewModel.h>
42
43 #include <QtCore/QDebug>
44 #include <QtCore/QTimer>
45 #include <QtGui/QVBoxLayout>
46 #include <QtGui/QMenu>
47
48 using namespace CppEditor::Internal;
49
50 enum {
51     debug = false
52 };
53
54 CppOutlineTreeView::CppOutlineTreeView(QWidget *parent) :
55     Utils::NavigationTreeView(parent)
56 {
57     // see also QmlJSOutlineTreeView
58     setFocusPolicy(Qt::NoFocus);
59     setExpandsOnDoubleClick(false);
60 }
61
62 void CppOutlineTreeView::contextMenuEvent(QContextMenuEvent *event)
63 {
64     if (!event)
65         return;
66
67     QMenu contextMenu;
68
69     contextMenu.addAction(tr("Expand All"), this, SLOT(expandAll()));
70     contextMenu.addAction(tr("Collapse All"), this, SLOT(collapseAll()));
71
72     contextMenu.exec(event->globalPos());
73
74     event->accept();
75 }
76
77 CppOutlineFilterModel::CppOutlineFilterModel(CPlusPlus::OverviewModel *sourceModel, QObject *parent) :
78     QSortFilterProxyModel(parent),
79     m_sourceModel(sourceModel)
80 {
81     setSourceModel(m_sourceModel);
82 }
83
84 bool CppOutlineFilterModel::filterAcceptsRow(int sourceRow,
85                                              const QModelIndex &sourceParent) const
86 {
87     // ignore artifical "<Select Symbol>" entry
88     if (!sourceParent.isValid() && sourceRow == 0) {
89         return false;
90     }
91     // ignore generated symbols, e.g. by macro expansion (Q_OBJECT)
92     const QModelIndex sourceIndex = m_sourceModel->index(sourceRow, 0, sourceParent);
93     CPlusPlus::Symbol *symbol = m_sourceModel->symbolFromIndex(sourceIndex);
94     if (symbol && symbol->isGenerated())
95         return false;
96
97     return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
98 }
99
100
101 CppOutlineWidget::CppOutlineWidget(CPPEditorWidget *editor) :
102     TextEditor::IOutlineWidget(),
103     m_editor(editor),
104     m_treeView(new CppOutlineTreeView(this)),
105     m_model(m_editor->outlineModel()),
106     m_proxyModel(new CppOutlineFilterModel(m_model, this)),
107     m_enableCursorSync(true),
108     m_blockCursorSync(false)
109 {
110     QVBoxLayout *layout = new QVBoxLayout;
111     layout->setMargin(0);
112     layout->setSpacing(0);
113     layout->addWidget(m_treeView);
114     setLayout(layout);
115
116     m_treeView->setModel(m_proxyModel);
117
118     connect(m_model, SIGNAL(modelReset()), this, SLOT(modelUpdated()));
119     modelUpdated();
120
121     connect(m_editor, SIGNAL(outlineModelIndexChanged(QModelIndex)),
122             this, SLOT(updateSelectionInTree(QModelIndex)));
123     connect(m_treeView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
124             this, SLOT(updateSelectionInText(QItemSelection)));
125     connect(m_treeView, SIGNAL(doubleClicked(QModelIndex)),
126             this, SLOT(updateTextCursor(QModelIndex)));
127 }
128
129 QList<QAction*> CppOutlineWidget::filterMenuActions() const
130 {
131     return QList<QAction*>();
132 }
133
134 void CppOutlineWidget::setCursorSynchronization(bool syncWithCursor)
135 {
136     m_enableCursorSync = syncWithCursor;
137     if (m_enableCursorSync)
138         updateSelectionInTree(m_editor->outlineModelIndex());
139 }
140
141 void CppOutlineWidget::modelUpdated()
142 {
143     m_treeView->expandAll();
144 }
145
146 void CppOutlineWidget::updateSelectionInTree(const QModelIndex &index)
147 {
148     if (!syncCursor())
149         return;
150
151     QModelIndex proxyIndex = m_proxyModel->mapFromSource(index);
152
153     m_blockCursorSync = true;
154     if (debug)
155         qDebug() << "CppOutline - updating selection due to cursor move";
156
157     m_treeView->selectionModel()->select(proxyIndex, QItemSelectionModel::ClearAndSelect);
158     m_treeView->scrollTo(proxyIndex);
159     m_blockCursorSync = false;
160 }
161
162 void CppOutlineWidget::updateSelectionInText(const QItemSelection &selection)
163 {
164     if (!syncCursor())
165         return;
166
167     if (!selection.indexes().isEmpty()) {
168         QModelIndex proxyIndex = selection.indexes().first();
169         updateTextCursor(proxyIndex);
170     }
171 }
172
173 void CppOutlineWidget::updateTextCursor(const QModelIndex &proxyIndex)
174 {
175     QModelIndex index = m_proxyModel->mapToSource(proxyIndex);
176     CPlusPlus::Symbol *symbol = m_model->symbolFromIndex(index);
177     if (symbol) {
178         m_blockCursorSync = true;
179
180         if (debug)
181             qDebug() << "CppOutline - moving cursor to" << symbol->line() << symbol->column() - 1;
182
183         Core::EditorManager *editorManager = Core::EditorManager::instance();
184         editorManager->cutForwardNavigationHistory();
185         editorManager->addCurrentPositionToNavigationHistory();
186
187         // line has to be 1 based, column 0 based!
188         m_editor->gotoLine(symbol->line(), symbol->column() - 1);
189         m_blockCursorSync = false;
190     }
191 }
192
193 bool CppOutlineWidget::syncCursor()
194 {
195     return m_enableCursorSync && !m_blockCursorSync;
196 }
197
198 bool CppOutlineWidgetFactory::supportsEditor(Core::IEditor *editor) const
199 {
200     if (qobject_cast<CPPEditor*>(editor))
201         return true;
202     return false;
203 }
204
205 TextEditor::IOutlineWidget *CppOutlineWidgetFactory::createWidget(Core::IEditor *editor)
206 {
207     CPPEditor *cppEditor = qobject_cast<CPPEditor*>(editor);
208     CPPEditorWidget *cppEditorWidget = qobject_cast<CPPEditorWidget*>(cppEditor->widget());
209     Q_ASSERT(cppEditorWidget);
210
211     CppOutlineWidget *widget = new CppOutlineWidget(cppEditorWidget);
212
213     return widget;
214 }