designeractionmanager.cpp 15.8 KB
Newer Older
1
2
/****************************************************************************
**
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** 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.
**
** GNU Lesser General Public License Usage
** 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
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "designeractionmanager.h"
#include "modelnodecontextmenu_helper.h"
#include "modelnodeoperations.h"
#include "componentcore_constants.h"
#include <nodeproperty.h>

#include <QMenu>

namespace QmlDesigner {

static inline QString captionForModelNode(const ModelNode &modelNode)
{
    if (modelNode.id().isEmpty())
        return modelNode.simplifiedTypeName();

    return modelNode.id();
}

static inline bool contains(const QmlItemNode &node, const QPoint &position)
{
50
    return node.isValid() && node.instanceSceneTransform().mapRect(node.instanceBoundingRect()).contains(position);
51
52
53
54
55
56
57
58
59
60
}

namespace Internal {

class DesignerActionManagerView : public QmlModelView
{
public:
    DesignerActionManagerView() : QmlModelView(0), m_isInRewriterTransaction(false), m_setupContextDirty(false)
    {}

61
    void modelAttached(Model *model) QTC_OVERRIDE
62
63
64
65
66
    {
        QmlModelView::modelAttached(model);
        setupContext();
    }

67
    void modelAboutToBeDetached(Model *model) QTC_OVERRIDE
68
69
70
71
72
    {
        QmlModelView::modelAboutToBeDetached(model);
        setupContext();
    }

73
    virtual void nodeCreated(const ModelNode &) QTC_OVERRIDE
74
75
76
77
    {
        setupContext();
    }

78
    virtual void nodeAboutToBeRemoved(const ModelNode &) QTC_OVERRIDE
79
80
    {}

81
    virtual void nodeRemoved(const ModelNode &, const NodeAbstractProperty &, PropertyChangeFlags) QTC_OVERRIDE
82
83
84
85
86
87
88
    {
        setupContext();
    }

    virtual void nodeAboutToBeReparented(const ModelNode &,
                                         const NodeAbstractProperty &,
                                         const NodeAbstractProperty &,
89
                                         AbstractView::PropertyChangeFlags ) QTC_OVERRIDE
90
91
92
93
94
95
    {
        setupContext();
    }

    virtual void nodeReparented(const ModelNode &, const NodeAbstractProperty &,
                                const NodeAbstractProperty &,
96
                                AbstractView::PropertyChangeFlags) QTC_OVERRIDE
97
98
99
100
    {
        setupContext();
    }

101
    virtual void nodeIdChanged(const ModelNode&, const QString&, const QString&) QTC_OVERRIDE
102
103
    {}

104
    virtual void propertiesAboutToBeRemoved(const QList<AbstractProperty>&) QTC_OVERRIDE
105
106
    {}

107
    virtual void propertiesRemoved(const QList<AbstractProperty>&) QTC_OVERRIDE
108
109
110
111
    {
        setupContext();
    }

112
    virtual void variantPropertiesChanged(const QList<VariantProperty>&, PropertyChangeFlags) QTC_OVERRIDE
113
114
    {}

115
    virtual void bindingPropertiesChanged(const QList<BindingProperty>&, PropertyChangeFlags) QTC_OVERRIDE
116
117
    {}

118
    virtual void rootNodeTypeChanged(const QString &, int , int ) QTC_OVERRIDE
119
120
121
122
    {
        setupContext();
    }

123
    virtual void instancePropertyChange(const QList<QPair<ModelNode, PropertyName> > &) QTC_OVERRIDE
124
125
    {}

126
    virtual void instancesCompleted(const QVector<ModelNode> &) QTC_OVERRIDE
127
128
    {}

129
    virtual void instanceInformationsChange(const QMultiHash<ModelNode, InformationName> &) QTC_OVERRIDE
130
131
    {}

132
    virtual void instancesRenderImageChanged(const QVector<ModelNode> &) QTC_OVERRIDE
133
134
    {}

135
    virtual void instancesPreviewImageChanged(const QVector<ModelNode> &) QTC_OVERRIDE
136
137
    {}

138
    virtual void instancesChildrenChanged(const QVector<ModelNode> &) QTC_OVERRIDE
139
140
    {}

141
    virtual void instancesToken(const QString &, int , const QVector<ModelNode> &) QTC_OVERRIDE
142
143
    {}

144
    virtual void nodeSourceChanged(const ModelNode &, const QString &) QTC_OVERRIDE
145
146
    {}

147
    virtual void rewriterBeginTransaction() QTC_OVERRIDE
148
149
150
151
    {
        m_isInRewriterTransaction = true;
    }

152
    virtual void rewriterEndTransaction() QTC_OVERRIDE
153
154
155
156
157
158
159
    {
        m_isInRewriterTransaction = false;

        if (m_setupContextDirty)
            setupContext();
    }

160
    virtual void actualStateChanged(const ModelNode &) QTC_OVERRIDE
161
162
163
164
165
    {
        setupContext();
    }

    virtual void selectedNodesChanged(const QList<ModelNode> &,
166
                                      const QList<ModelNode> &) QTC_OVERRIDE
167
168
169
170
    {
        setupContext();
    }

171
    virtual void nodeOrderChanged(const NodeListProperty &, const ModelNode &, int ) QTC_OVERRIDE
172
173
174
175
    {
        setupContext();
    }

176
    virtual void importsChanged(const QList<Import> &, const QList<Import> &) QTC_OVERRIDE
177
178
179
180
    {
        setupContext();
    }

181
    virtual void scriptFunctionsChanged(const ModelNode &, const QStringList &) QTC_OVERRIDE
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
    {}

    void setDesignerActionList(const QList<AbstractDesignerAction* > &designerActionList)
    {
        m_designerActionList = designerActionList;
    }

protected:
    void setupContext()
    {
        if (m_isInRewriterTransaction) {
            m_setupContextDirty = true;
            return;
        }
        SelectionContext selectionContext(this);
        foreach (AbstractDesignerAction* action, m_designerActionList) {
            action->setCurrentContext(selectionContext);
        }
        m_setupContextDirty = false;
    }

    QList<AbstractDesignerAction* > m_designerActionList;
    bool m_isInRewriterTransaction;
    bool m_setupContextDirty;
};

} //Internal

DesignerActionManager *DesignerActionManager::m_instance = 0;

void DesignerActionManager::addDesignerAction(AbstractDesignerAction *newAction)
{
    instance()->addDesignerActionInternal(newAction);
}

QList<AbstractDesignerAction* > DesignerActionManager::designerActions()
{
    return instance()->factoriesInternal();
}

QmlModelView *DesignerActionManager::view()
{
224
    return instance()->m_view;
225
226
}

Thomas Hartmann's avatar
Thomas Hartmann committed
227
class VisiblityModelNodeAction : public ModelNodeAction
228
229
{
public:
Thomas Hartmann's avatar
Thomas Hartmann committed
230
231
232
233
234
    VisiblityModelNodeAction(const QString &description, const QString &category, int priority,
            ModelNodeOperations::SelectionAction action,
            SelectionContextFunction enabled = &SelectionContextFunctors::always,
            SelectionContextFunction visibility = &SelectionContextFunctors::always) :
        ModelNodeAction(description, category, priority, action, enabled, visibility)
235
236
237
    {}
    virtual void updateContext()
    {
238
239
240
241
        defaultAction()->setSelectionContext(selectionContext());
        if (selectionContext().isValid()) {
            defaultAction()->setEnabled(isEnabled(selectionContext()));
            defaultAction()->setVisible(isVisible(selectionContext()));
242

243
244
            defaultAction()->setCheckable(true);
            QmlItemNode itemNode = QmlItemNode(selectionContext().currentSingleSelectedNode());
245
            if (itemNode.isValid())
246
                defaultAction()->setChecked(itemNode.instanceValue("visible").toBool());
247
            else
248
                defaultAction()->setEnabled(false);
249
250
251
252
        }
    }
};

Thomas Hartmann's avatar
Thomas Hartmann committed
253
class SelectionModelNodeAction : public MenuDesignerAction
254
255
256
{
public:
    SelectionModelNodeAction(const QString &displayName, const QString &menuId, int priority) :
Thomas Hartmann's avatar
Thomas Hartmann committed
257
258
259
        MenuDesignerAction(displayName, menuId, priority,
                           &SelectionContextFunctors::always, &SelectionContextFunctors::selectionEnabled)

260
261
262
263
264
265
266
267
268
269
270
271
272
273
    {}

    virtual void updateContext()
    {
        m_menu->clear();
        if (m_selectionContext.isValid()) {
            m_action->setEnabled(isEnabled(m_selectionContext));
            m_action->setVisible(isVisible(m_selectionContext));
        } else {
            return;
        }
        if (m_action->isEnabled()) {
            ModelNode parentNode;
            if (m_selectionContext.singleSelected() && !m_selectionContext.currentSingleSelectedNode().isRootNode()) {
Thomas Hartmann's avatar
Thomas Hartmann committed
274
                ActionTemplate *selectionAction = new ActionTemplate(QString(), &ModelNodeOperations::select);
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
                selectionAction->setParent(m_menu.data());

                parentNode = m_selectionContext.currentSingleSelectedNode().parentProperty().parentModelNode();
                m_selectionContext.setTargetNode(parentNode);
                selectionAction->setText(QString(QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Select parent: %1")).arg(
                                             captionForModelNode(parentNode)));
                selectionAction->setSelectionContext(m_selectionContext);

                m_menu->addAction(selectionAction);
            }
            foreach (const ModelNode &node, m_selectionContext.view()->allModelNodes()) {
                if (node != m_selectionContext.currentSingleSelectedNode()
                        && node != parentNode
                        && contains(node, m_selectionContext.scenePos())
                        && !node.isRootNode()) {
                    m_selectionContext.setTargetNode(node);
Thomas Hartmann's avatar
Thomas Hartmann committed
291
292
                    QString what = QString(QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Select: %1")).arg(captionForModelNode(node));
                    ActionTemplate *selectionAction = new ActionTemplate(what, &ModelNodeOperations::select);
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
                    selectionAction->setSelectionContext(m_selectionContext);

                    m_menu->addAction(selectionAction);
                }
            }
        }
    }
};

char xProperty[] = "x";
char yProperty[] = "y";
char zProperty[] = "z";
char widthProperty[] = "width";
char heightProperty[] = "height";

Thomas Hartmann's avatar
Thomas Hartmann committed
308
309
310
using namespace SelectionContextFunctors;

bool multiSelection(const SelectionContext &context)
311
{
Thomas Hartmann's avatar
Thomas Hartmann committed
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
    return !singleSelection(context);
}

bool singleSelectionAndInBaseState(const SelectionContext &context)
{
    return singleSelection(context) && inBaseState(context);
}

bool multiSelectionAndInBaseState(const SelectionContext &context)
{
    return multiSelection(context) && inBaseState(context);
}

bool selectionHasProperty1or2(const SelectionContext &context, const char *x, const char *y)
{
    return selectionHasProperty(context, x) || selectionHasProperty(context, y);
}
329

Thomas Hartmann's avatar
Thomas Hartmann committed
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
bool selectionHasSameParentAndInBaseState(const SelectionContext &context)
{
    return selectionHasSameParent(context) && inBaseState(context);
}

bool selectionCanBeLayouted(const SelectionContext &context)
{
    return selectionHasSameParentAndInBaseState(context) && inBaseState(context);
}

bool selectionNotEmptyAndHasZProperty(const SelectionContext &context)
{
    return selectionNotEmpty(context) && selectionHasProperty(context, zProperty);
}

bool selectionNotEmptyAndHasWidthOrHeightProperty(const SelectionContext &context)
{
    return selectionNotEmpty(context)
        && selectionHasProperty1or2(context, widthProperty, heightProperty);
}

bool selectionNotEmptyAndHasXorYProperty(const SelectionContext &context)
{
    return selectionNotEmpty(context)
        && selectionHasProperty1or2(context, xProperty, yProperty);
}

void DesignerActionManager::createDefaultDesignerActions()
{
359
360
    using namespace SelectionContextFunctors;
    using namespace ComponentCoreConstants;
Thomas Hartmann's avatar
Thomas Hartmann committed
361
    using namespace ModelNodeOperations;
362
363
364

    addDesignerAction(new SelectionModelNodeAction(selectionCategoryDisplayName, selectionCategory, prioritySelectionCategory));

Thomas Hartmann's avatar
Thomas Hartmann committed
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
    addDesignerAction(new MenuDesignerAction(stackCategoryDisplayName, stackCategory, priorityStackCategory, &always));
        addDesignerAction(new ModelNodeAction
                   (toFrontDisplayName, stackCategory, 200, &toFront, &singleSelection));
        addDesignerAction(new ModelNodeAction
                   (toBackDisplayName, stackCategory, 180, &toBack, &singleSelection));
        addDesignerAction(new ModelNodeAction
                   (raiseDisplayName, stackCategory, 160, &raise, &selectionNotEmpty));
        addDesignerAction(new ModelNodeAction
                   (lowerDisplayName, stackCategory, 140, &lower, &selectionNotEmpty));
        addDesignerAction(new SeperatorDesignerAction(stackCategory, 120));
        addDesignerAction(new ModelNodeAction
                   (resetZDisplayName, stackCategory, 100, &resetZ, &selectionNotEmptyAndHasZProperty));

    addDesignerAction(new MenuDesignerAction(editCategoryDisplayName, editCategory, priorityEditCategory, &selectionNotEmpty));
        addDesignerAction(new ModelNodeAction
                   (resetPositionDisplayName, editCategory, 200, &resetPosition, &selectionNotEmptyAndHasXorYProperty));
        addDesignerAction(new ModelNodeAction
                   (resetSizeDisplayName, editCategory, 180, &resetSize, &selectionNotEmptyAndHasWidthOrHeightProperty));
        addDesignerAction(new VisiblityModelNodeAction
                   (visibilityDisplayName, editCategory, 160, &setVisible, &singleSelectedItem));

    addDesignerAction(new MenuDesignerAction(anchorsCategoryDisplayName, anchorsCategory,
                    priorityAnchorsCategory, &singleSelectionAndInBaseState));
        addDesignerAction(new ModelNodeAction
                   (anchorsFillDisplayName, anchorsCategory, 200, &anchorsFill, &singleSelectionItemIsNotAnchored));
        addDesignerAction(new ModelNodeAction
                   (anchorsResetDisplayName, anchorsCategory, 180, &anchorsReset, &singleSelectionItemIsAnchored));

    addDesignerAction(new MenuDesignerAction(layoutCategoryDisplayName, layoutCategory,
                    priorityLayoutCategory, &multiSelectionAndInBaseState));
        addDesignerAction(new ModelNodeAction
                   (layoutRowDisplayName, layoutCategory, 200, &layoutRow, &selectionCanBeLayouted));
        addDesignerAction(new ModelNodeAction
                   (layoutColumnDisplayName, layoutCategory, 180, &layoutColumn, &selectionCanBeLayouted));
        addDesignerAction(new ModelNodeAction
                   (layoutGridDisplayName, layoutCategory, 160, &layoutGrid, &selectionCanBeLayouted));
        addDesignerAction(new ModelNodeAction
                   (layoutFlowDisplayName, layoutCategory, 140, &layoutFlow, &selectionCanBeLayouted));

    addDesignerAction(new SeperatorDesignerAction(rootCategory, priorityTopLevelSeperator));
    addDesignerAction(new ModelNodeAction
               (goIntoComponentDisplayName, rootCategory, priorityGoIntoComponent, &goIntoComponent, &selectionIsComponent));
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
}

DesignerActionManager *DesignerActionManager::instance()
{
    if (!m_instance) {
        m_instance = new DesignerActionManager;
        createDefaultDesignerActions();
    }

    return m_instance;
}

void DesignerActionManager::addDesignerActionInternal(AbstractDesignerAction *newAction)
{
    m_designerActions.append(QSharedPointer<AbstractDesignerAction>(newAction));
    m_view->setDesignerActionList(designerActions());
}

QList<AbstractDesignerAction* > DesignerActionManager::factoriesInternal() const
{
    QList<AbstractDesignerAction* > list;
    foreach (const QSharedPointer<AbstractDesignerAction> &pointer, m_designerActions) {
        list.append(pointer.data());
    }

    return list;
}

DesignerActionManager::DesignerActionManager() : m_view(new Internal::DesignerActionManagerView)
{
}

439
440
441
442
443
DesignerActionManager::~DesignerActionManager()
{
    delete m_view;
}

444
} //QmlDesigner