navigatorview.cpp 17 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8
9
10
11
12
13
14
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15
16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
18
19
20
21
22
23
24
25
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
26
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
29
30
31
32

#include "navigatorview.h"
#include "navigatortreemodel.h"
#include "navigatorwidget.h"
33
#include "nameitemdelegate.h"
34
#include "iconcheckboxitemdelegate.h"
35

36
#include <coreplugin/editormanager/editormanager.h>
37
#include <coreplugin/icore.h>
38

39
#include <designmodecontext.h>
40
#include <nodeproperty.h>
41
#include <nodelistproperty.h>
42
#include <variantproperty.h>
43
#include <QHeaderView>
Marco Bubke's avatar
Marco Bubke committed
44
#include <qmlitemnode.h>
45

46
47
static inline void setScenePos(const QmlDesigner::ModelNode &modelNode,const QPointF &pos)
{
48
49
    if (modelNode.hasParentProperty() && QmlDesigner::QmlItemNode::isValidQmlItemNode(modelNode.parentProperty().parentModelNode())) {
        QmlDesigner::QmlItemNode parentNode = modelNode.parentProperty().parentQmlObjectNode().toQmlItemNode();
50
51
52
53
54
55
56
57
58

        if (!parentNode.modelNode().metaInfo().isLayoutable()) {
            QPointF localPos = parentNode.instanceSceneTransform().inverted().map(pos);
            modelNode.variantProperty("x").setValue(localPos.toPoint().x());
            modelNode.variantProperty("y").setValue(localPos.toPoint().y());
        } else { //Items in Layouts do not have a position
            modelNode.removeProperty("x");
            modelNode.removeProperty("y");
        }
59
60
    }
}
61
62
63
64

namespace QmlDesigner {

NavigatorView::NavigatorView(QObject* parent) :
Marco Bubke's avatar
Marco Bubke committed
65
        AbstractView(parent),
66
        m_blockSelectionChangedSignal(false),
67
        m_widget(new NavigatorWidget(this)),
68
69
        m_treeModel(new NavigatorTreeModel(this))
{
70
71
72
    Internal::NavigatorContext *navigatorContext = new Internal::NavigatorContext(m_widget.data());
    Core::ICore::addContextObject(navigatorContext);

73
74
75
    m_widget->setTreeModel(m_treeModel.data());

    connect(treeWidget()->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(changeSelection(QItemSelection,QItemSelection)));
76
77
78
79
80
81

    connect(m_widget.data(), SIGNAL(leftButtonClicked()), this, SLOT(leftButtonClicked()));
    connect(m_widget.data(), SIGNAL(rightButtonClicked()), this, SLOT(rightButtonClicked()));
    connect(m_widget.data(), SIGNAL(downButtonClicked()), this, SLOT(downButtonClicked()));
    connect(m_widget.data(), SIGNAL(upButtonClicked()), this, SLOT(upButtonClicked()));

82
    treeWidget()->setIndentation(treeWidget()->indentation() * 0.5);
83

84
85
86
87
88
89
    NameItemDelegate *idDelegate = new NameItemDelegate(this,
                                                        m_treeModel.data());
    IconCheckboxItemDelegate *showDelegate = new IconCheckboxItemDelegate(this,
                                                                          ":/qmldesigner/images/eye_open.png",
                                                                          ":/qmldesigner/images/placeholder.png",
                                                                          m_treeModel.data());
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104

#ifdef _LOCK_ITEMS_
    IconCheckboxItemDelegate *lockDelegate = new IconCheckboxItemDelegate(this,":/qmldesigner/images/lock.png",
                                                          ":/qmldesigner/images/hole.png",m_treeModel.data());
#endif


    treeWidget()->setItemDelegateForColumn(0,idDelegate);
#ifdef _LOCK_ITEMS_
    treeWidget()->setItemDelegateForColumn(1,lockDelegate);
    treeWidget()->setItemDelegateForColumn(2,showDelegate);
#else
    treeWidget()->setItemDelegateForColumn(1,showDelegate);
#endif

105
106
107
108
109
110
111
112
}

NavigatorView::~NavigatorView()
{
    if (m_widget && !m_widget->parent())
        delete m_widget.data();
}

113
114
115
116
117
118
119
bool NavigatorView::hasWidget() const
{
    return true;
}

WidgetInfo NavigatorView::widgetInfo()
{
120
121
    return createWidgetInfo(m_widget.data(),
                            new WidgetInfo::ToolBarWidgetDefaultFactory<NavigatorWidget>(m_widget.data()),
122
                            QStringLiteral("Navigator"),
123
124
                            WidgetInfo::LeftPane,
                            0);
125
126
}

127
128
void NavigatorView::modelAttached(Model *model)
{
Marco Bubke's avatar
Marco Bubke committed
129
    AbstractView::modelAttached(model);
130
131
132

    m_treeModel->setView(this);

133
134
    QTreeView *treeView = treeWidget();
    treeView->expandAll();
135

136
    treeView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
137
138
139
    treeView->header()->resizeSection(1,26);
    treeView->setRootIsDecorated(false);
    treeView->setIndentation(20);
140
#ifdef _LOCK_ITEMS_
141
    treeView->header()->resizeSection(2,20);
142
#endif
143
144
145
146
}

void NavigatorView::modelAboutToBeDetached(Model *model)
{
147
    m_treeModel->removeSubTree(rootModelNode());
148
    m_treeModel->clearView();
Marco Bubke's avatar
Marco Bubke committed
149
    AbstractView::modelAboutToBeDetached(model);
150
151
}

152
void NavigatorView::importsChanged(const QList<Import> &/*addedImports*/, const QList<Import> &/*removedImports*/)
153
154
155
156
{
    treeWidget()->update();
}

157
void NavigatorView::nodeCreated(const ModelNode & /*createdNode*/)
158
159
160
{
}

161
void NavigatorView::nodeRemoved(const ModelNode & /*removedNode*/, const NodeAbstractProperty & /*parentProperty*/, PropertyChangeFlags /*propertyChange*/)
162
163
164
{
}

165
void NavigatorView::propertiesRemoved(const QList<AbstractProperty> & /*propertyList*/)
166
167
168
{
}

169
void NavigatorView::variantPropertiesChanged(const QList<VariantProperty> & /*propertyList*/, PropertyChangeFlags /*propertyChange*/)
170
171
172
{
}

173
void NavigatorView::bindingPropertiesChanged(const QList<BindingProperty> & /*propertyList*/, PropertyChangeFlags /*propertyChange*/)
174
{
175
176
}

177
178
179
180
181
void NavigatorView::signalHandlerPropertiesChanged(const QVector<SignalHandlerProperty> & /*propertyList*/,
                                                   AbstractView::PropertyChangeFlags /*propertyChange*/)
{
}

182
183
void NavigatorView::nodeAboutToBeRemoved(const ModelNode &removedNode)
{
Marco Bubke's avatar
Marco Bubke committed
184
    m_treeModel->removeSubTree(removedNode);
185
186
}

187
188
189
190
void NavigatorView::nodeAboutToBeReparented(const ModelNode &/*node*/, const NodeAbstractProperty &/*newPropertyParent*/, const NodeAbstractProperty &/*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/)
{
}

191
192
193
194
void NavigatorView::nodeReparented(const ModelNode &node, const NodeAbstractProperty & /*newPropertyParent*/, const NodeAbstractProperty & /*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/)
{
    bool blocked = blockSelectionChangedSignal(true);

Marco Bubke's avatar
Marco Bubke committed
195
196
    m_treeModel->removeSubTree(node);

197
198
199
200
201
202
203
204
205
    if (node.isInHierarchy())
        m_treeModel->addSubTree(node);

    // make sure selection is in sync again
    updateItemSelection();

    blockSelectionChangedSignal(blocked);
}

206
void NavigatorView::nodeIdChanged(const ModelNode& node, const QString & /*newId*/, const QString & /*oldId*/)
207
208
209
210
211
212
213
214
{
    if (m_treeModel->isInTree(node))
        m_treeModel->updateItemRow(node);
}

void NavigatorView::propertiesAboutToBeRemoved(const QList<AbstractProperty>& propertyList)
{
    foreach (const AbstractProperty &property, propertyList) {
215
216
217
218
        if (property.isNodeAbstractProperty()) {
            NodeAbstractProperty nodeAbstractProperty(property.toNodeListProperty());
            foreach (const ModelNode &childNode, nodeAbstractProperty.directSubNodes()) {
                m_treeModel->removeSubTree(childNode);
219
220
221
222
223
            }
        }
    }
}

224
void NavigatorView::rootNodeTypeChanged(const QString & /*type*/, int /*majorVersion*/, int /*minorVersion*/)
225
{
226
227
    if (m_treeModel->isInTree(rootModelNode()))
        m_treeModel->updateItemRow(rootModelNode());
228
229
}

230
void NavigatorView::auxiliaryDataChanged(const ModelNode &modelNode, const PropertyName & name, const QVariant & /*data*/)
231
{
232
    if (name == "invisible" && m_treeModel->isInTree(modelNode))
233
234
    {
        // update model
235
        m_treeModel->updateItemRow(modelNode);
236
237

        // repaint row (id and icon)
238
239
240
241
242
        foreach (const ModelNode &currentModelNode, modelNode.allSubModelNodesAndThisNode()) {
            QModelIndex index = m_treeModel->indexForNode(currentModelNode);
            treeWidget()->update(index);
            treeWidget()->update(index.sibling(index.row(),index.column()+1));
        }
243
    }
244
245
}

Marco Bubke's avatar
Marco Bubke committed
246
247
248
249
void NavigatorView::scriptFunctionsChanged(const ModelNode &/*node*/, const QStringList &/*scriptFunctionList*/)
{
}

250
void NavigatorView::instancePropertyChange(const QList<QPair<ModelNode, PropertyName> > &/*propertyList*/)
251
252
{
}
Marco Bubke's avatar
Marco Bubke committed
253

254
255
256
257
void NavigatorView::instancesCompleted(const QVector<ModelNode> &/*completedNodeList*/)
{
}

258
void NavigatorView::instanceInformationsChange(const QMultiHash<ModelNode, InformationName> &/*informationChangeHash*/)
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
{
}

void NavigatorView::instancesRenderImageChanged(const QVector<ModelNode> &/*nodeList*/)
{
}

void NavigatorView::instancesPreviewImageChanged(const QVector<ModelNode> &/*nodeList*/)
{
}

void NavigatorView::instancesChildrenChanged(const QVector<ModelNode> &/*nodeList*/)
{

}

275
void NavigatorView::nodeSourceChanged(const ModelNode &, const QString & /*newNodeSource*/)
276
277
278
279
{

}

280
281
282
283
284
285
286
287
void NavigatorView::rewriterBeginTransaction()
{
}

void NavigatorView::rewriterEndTransaction()
{
}

288
void NavigatorView::currentStateChanged(const ModelNode &/*node*/)
289
290
291
{
}

292
293
294
295
296
void NavigatorView::instancesToken(const QString &/*tokenName*/, int /*tokenNumber*/, const QVector<ModelNode> &/*nodeVector*/)
{

}

297
void NavigatorView::nodeOrderChanged(const NodeListProperty &listProperty, const ModelNode &node, int /*oldIndex*/)
298
{
299
300
301
302
303
304
305
    if (m_treeModel->isInTree(node)) {
        m_treeModel->removeSubTree(listProperty.parentModelNode());

        if (node.isInHierarchy())
            m_treeModel->addSubTree(listProperty.parentModelNode());

    }
306
307
}

308
309
310
311
void NavigatorView::changeToComponent(const QModelIndex &index)
{
    if (index.isValid() && m_treeModel->data(index, Qt::UserRole).isValid()) {
        ModelNode doubleClickNode = m_treeModel->nodeForIndex(index);
Marco Bubke's avatar
Marco Bubke committed
312
        if (doubleClickNode.metaInfo().isFileComponent())
Eike Ziller's avatar
Eike Ziller committed
313
314
            Core::EditorManager::openEditor(doubleClickNode.metaInfo().componentFileName(),
                                            Core::Id(), Core::EditorManager::DoNotMakeVisible);
315
316
317
    }
}

318
319
320
321
322
323
324
325
void NavigatorView::leftButtonClicked()
{
    if (selectedModelNodes().count() > 1)
        return; //Semantics are unclear for multi selection.

    bool blocked = blockSelectionChangedSignal(true);

    foreach (const ModelNode &node, selectedModelNodes()) {
326
        if (!node.isRootNode() && !node.parentProperty().parentModelNode().isRootNode()) {
327
            if (QmlItemNode::isValidQmlItemNode(node)) {
328
                QPointF scenePos = QmlItemNode(node).instanceScenePosition();
329
                node.parentProperty().parentProperty().reparentHere(node);
330
331
332
                if (!scenePos.isNull())
                    setScenePos(node, scenePos);
            } else {
333
                node.parentProperty().parentProperty().reparentHere(node);
334
335
            }
        }
336
337
338
339
340
341
342
343
344
345
346
347
    }
    updateItemSelection();
    blockSelectionChangedSignal(blocked);
}

void NavigatorView::rightButtonClicked()
{
    if (selectedModelNodes().count() > 1)
        return; //Semantics are unclear for multi selection.

    bool blocked = blockSelectionChangedSignal(true);
    foreach (const ModelNode &node, selectedModelNodes()) {
348
349
        if (!node.isRootNode() && node.parentProperty().isNodeListProperty() && node.parentProperty().count() > 1) {
            int index = node.parentProperty().indexOf(node);
350
351
352
            index--;
            if (index >= 0) { //for the first node the semantics are not clear enough. Wrapping would be irritating.
                ModelNode newParent = node.parentProperty().toNodeListProperty().at(index);
353

354
355
356
                if (QmlItemNode::isValidQmlItemNode(node)
                        && QmlItemNode::isValidQmlItemNode(newParent)
                        && !newParent.metaInfo().defaultPropertyIsComponent()) {
357
358
359
360
361
                    QPointF scenePos = QmlItemNode(node).instanceScenePosition();
                    newParent.nodeAbstractProperty(newParent.metaInfo().defaultPropertyName()).reparentHere(node);
                    if (!scenePos.isNull())
                        setScenePos(node, scenePos);
                } else {
362
363
                    if (newParent.metaInfo().isValid() && !newParent.metaInfo().defaultPropertyIsComponent())
                        newParent.nodeAbstractProperty(newParent.metaInfo().defaultPropertyName()).reparentHere(node);
364
                }
365
366
367
368
369
370
371
372
373
374
375
376
            }
        }
    }
    updateItemSelection();
    blockSelectionChangedSignal(blocked);
}

void NavigatorView::upButtonClicked()
{
    bool blocked = blockSelectionChangedSignal(true);
    foreach (const ModelNode &node, selectedModelNodes()) {
        if (!node.isRootNode() && node.parentProperty().isNodeListProperty()) {
377
            int oldIndex = node.parentProperty().indexOf(node);
378
379
380
            int index = oldIndex;
            index--;
            if (index < 0)
381
                index = node.parentProperty().count() - 1; //wrap around
382
383
384
385
386
387
388
389
390
391
392
393
            node.parentProperty().toNodeListProperty().slide(oldIndex, index);
        }
    }
    updateItemSelection();
    blockSelectionChangedSignal(blocked);
}

void NavigatorView::downButtonClicked()
{
    bool blocked = blockSelectionChangedSignal(true);
    foreach (const ModelNode &node, selectedModelNodes()) {
        if (!node.isRootNode() && node.parentProperty().isNodeListProperty()) {
394
            int oldIndex = node.parentProperty().indexOf(node);
395
396
            int index = oldIndex;
            index++;
397
            if (index >= node.parentProperty().count())
398
399
400
401
402
403
404
405
                index = 0; //wrap around
            node.parentProperty().toNodeListProperty().slide(oldIndex, index);
        }
    }
    updateItemSelection();
    blockSelectionChangedSignal(blocked);
}

406
407
408
409
410
411
void NavigatorView::changeSelection(const QItemSelection & /*newSelection*/, const QItemSelection &/*deselected*/)
{
    if (m_blockSelectionChangedSignal)
        return;
    QSet<ModelNode> nodeSet;
    foreach (const QModelIndex &index, treeWidget()->selectionModel()->selectedIndexes()) {
412
413
        if (m_treeModel->data(index, Qt::UserRole).isValid())
            nodeSet.insert(m_treeModel->nodeForIndex(index));
414
415
416
417
418
419
420
    }

    bool blocked = blockSelectionChangedSignal(true);
    setSelectedModelNodes(nodeSet.toList());
    blockSelectionChangedSignal(blocked);
}

421
void NavigatorView::selectedNodesChanged(const QList<ModelNode> &/*selectedNodeList*/, const QList<ModelNode> &/*lastSelectedNodeList*/)
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
{
    updateItemSelection();
}

void NavigatorView::updateItemSelection()
{
    QItemSelection itemSelection;
    foreach (const ModelNode &node, selectedModelNodes()) {
        const QModelIndex index = m_treeModel->indexForNode(node);
        if (index.isValid()) {
            const QModelIndex beginIndex(m_treeModel->index(index.row(), 0, index.parent()));
            const QModelIndex endIndex(m_treeModel->index(index.row(), m_treeModel->columnCount(index.parent()) - 1, index.parent()));
            if (beginIndex.isValid() && endIndex.isValid())
                itemSelection.select(beginIndex, endIndex);
        }
    }

    bool blocked = blockSelectionChangedSignal(true);
    treeWidget()->selectionModel()->select(itemSelection, QItemSelectionModel::ClearAndSelect);
    blockSelectionChangedSignal(blocked);

443
444
445
    if (!selectedModelNodes().isEmpty())
        treeWidget()->scrollTo(m_treeModel->indexForNode(selectedModelNodes().first()));

446
    // make sure selected nodes a visible
447
    foreach (const QModelIndex &selectedIndex, itemSelection.indexes()) {
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
        if (selectedIndex.column() == 0)
            expandRecursively(selectedIndex);
    }
}

QTreeView *NavigatorView::treeWidget()
{
    if (m_widget)
        return m_widget->treeView();
    return 0;
}

NavigatorTreeModel *NavigatorView::treeModel()
{
    return m_treeModel.data();
}

// along the lines of QObject::blockSignals
bool NavigatorView::blockSelectionChangedSignal(bool block)
{
    bool oldValue = m_blockSelectionChangedSignal;
    m_blockSelectionChangedSignal = block;
    return oldValue;
}

void NavigatorView::expandRecursively(const QModelIndex &index)
{
    QModelIndex currentIndex = index;
    while (currentIndex.isValid()) {
        if (!treeWidget()->isExpanded(currentIndex))
            treeWidget()->expand(currentIndex);
        currentIndex = currentIndex.parent();
    }
}

} // namespace QmlDesigner