OSDN Git Service

It's 2011 now.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qmldesigner / designercore / filemanager / addpropertyvisitor.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 "addpropertyvisitor.h"
35
36 #include <qmljs/parser/qmljsast_p.h>
37 #include <qmljs/parser/qmljsengine_p.h>
38
39 using namespace QmlDesigner;
40 using namespace QmlDesigner::Internal;
41 using namespace QmlJS;
42 using namespace QmlJS::AST;
43
44 AddPropertyVisitor::AddPropertyVisitor(QmlDesigner::TextModifier &modifier,
45                                        quint32 parentLocation,
46                                        const QString &name,
47                                        const QString &value,
48                                        QmlRefactoring::PropertyType propertyType,
49                                        const QStringList &propertyOrder):
50     QMLRewriter(modifier),
51     m_parentLocation(parentLocation),
52     m_name(name),
53     m_value(value),
54     m_propertyType(propertyType),
55     m_propertyOrder(propertyOrder)
56 {
57 }
58
59 bool AddPropertyVisitor::visit(QmlJS::AST::UiObjectDefinition *ast)
60 {
61     if (didRewriting())
62         return false;
63
64     if (ast->firstSourceLocation().offset == m_parentLocation) {
65         // FIXME: change this to use the QmlJS::Rewriter class
66         addInMembers(ast->initializer);
67         return false;
68     }
69
70     return !didRewriting();
71 }
72
73 bool AddPropertyVisitor::visit(QmlJS::AST::UiObjectBinding *ast)
74 {
75     if (didRewriting())
76         return false;
77
78     if (ast->qualifiedTypeNameId->identifierToken.offset == m_parentLocation) {
79         // FIXME: change this to use the QmlJS::Rewriter class
80         addInMembers(ast->initializer);
81         return false;
82     }
83
84     return !didRewriting();
85 }
86
87 // FIXME: duplicate code in the QmlJS::Rewriter class, remove this
88 void AddPropertyVisitor::addInMembers(QmlJS::AST::UiObjectInitializer *initializer)
89 {
90     UiObjectMemberList *insertAfter = searchMemberToInsertAfter(initializer->members, m_name, m_propertyOrder);
91     SourceLocation endOfPreviousMember;
92     SourceLocation startOfNextMember;
93     unsigned depth;
94
95     if (insertAfter == 0 || insertAfter->member == 0) {
96         // insert as first member
97         endOfPreviousMember = initializer->lbraceToken;
98
99         if (initializer->members && initializer->members->member)
100             startOfNextMember = initializer->members->member->firstSourceLocation();
101         else
102             startOfNextMember = initializer->rbraceToken;
103
104         depth = calculateIndentDepth(endOfPreviousMember) + indentDepth();
105     } else {
106         endOfPreviousMember = insertAfter->member->lastSourceLocation();
107
108         if (insertAfter->next && insertAfter->next->member)
109             startOfNextMember = insertAfter->next->member->firstSourceLocation();
110         else
111             startOfNextMember = initializer->rbraceToken;
112
113         depth = calculateIndentDepth(endOfPreviousMember);
114     }
115     const bool isOneLiner = endOfPreviousMember.startLine == startOfNextMember.startLine;
116     bool needsPreceedingSemicolon = false;
117     bool needsTrailingSemicolon = false;
118
119     if (isOneLiner) {
120         if (insertAfter == 0) { // we're inserting after an lbrace
121             if (initializer->members) { // we're inserting before a member (and not the rbrace)
122                 needsTrailingSemicolon = m_propertyType == QmlRefactoring::ScriptBinding;
123             }
124         } else { // we're inserting after a member, not after the lbrace
125             if (endOfPreviousMember.isValid()) { // there already is a semicolon after the previous member
126                 if (insertAfter->next && insertAfter->next->member) { // and the after us there is a member, not an rbrace, so:
127                     needsTrailingSemicolon = m_propertyType == QmlRefactoring::ScriptBinding;
128                 }
129             } else { // there is no semicolon after the previous member (probably because there is an rbrace after us/it, so:
130                 needsPreceedingSemicolon = true;
131             }
132         }
133     }
134
135     QString newPropertyTemplate;
136     switch (m_propertyType) {
137     case QmlRefactoring::ArrayBinding:
138         newPropertyTemplate = QLatin1String("%1: [\n%2\n]");
139         m_value = addIndentation(m_value, 4);
140         break;
141
142     case QmlRefactoring::ObjectBinding:
143         newPropertyTemplate = QLatin1String("%1: %2");
144         break;
145
146     case QmlRefactoring::ScriptBinding:
147         newPropertyTemplate = QLatin1String("%1: %2");
148         break;
149
150     default:
151         Q_ASSERT(!"unknown property type");
152     }
153
154     if (isOneLiner) {
155         if (needsPreceedingSemicolon)
156             newPropertyTemplate.prepend(QLatin1Char(';'));
157         newPropertyTemplate.prepend(QLatin1Char(' '));
158         if (needsTrailingSemicolon)
159             newPropertyTemplate.append(QLatin1Char(';'));
160         depth = 0;
161     } else {
162         newPropertyTemplate.prepend(QLatin1Char('\n'));
163     }
164
165     const QString newPropertyText = addIndentation(newPropertyTemplate.arg(m_name, m_value), depth);
166     replace(endOfPreviousMember.end(), 0, newPropertyText);
167
168     setDidRewriting(true);
169 }