1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "private/textwriter_p.h"
43
44 QT_QML_BEGIN_NAMESPACE
45
46 using namespace QDeclarativeJS;
47
TextWriter()48 TextWriter::TextWriter()
49 :string(0), cursor(0)
50 {
51 }
52
overlaps(int posA,int lengthA,int posB,int lengthB)53 static bool overlaps(int posA, int lengthA, int posB, int lengthB) {
54 return (posA < posB + lengthB && posA + lengthA > posB + lengthB)
55 || (posA < posB && posA + lengthA > posB);
56 }
57
hasOverlap(int pos,int length)58 bool TextWriter::hasOverlap(int pos, int length)
59 {
60 {
61 QListIterator<Replace> i(replaceList);
62 while (i.hasNext()) {
63 const Replace &cmd = i.next();
64 if (overlaps(pos, length, cmd.pos, cmd.length))
65 return true;
66 }
67 }
68 {
69 QListIterator<Move> i(moveList);
70 while (i.hasNext()) {
71 const Move &cmd = i.next();
72 if (overlaps(pos, length, cmd.pos, cmd.length))
73 return true;
74 }
75 return false;
76 }
77 }
78
hasMoveInto(int pos,int length)79 bool TextWriter::hasMoveInto(int pos, int length)
80 {
81 QListIterator<Move> i(moveList);
82 while (i.hasNext()) {
83 const Move &cmd = i.next();
84 if (cmd.to >= pos && cmd.to < pos + length)
85 return true;
86 }
87 return false;
88 }
89
replace(int pos,int length,const QString & replacement)90 void TextWriter::replace(int pos, int length, const QString &replacement)
91 {
92 Q_ASSERT(!hasOverlap(pos, length));
93 Q_ASSERT(!hasMoveInto(pos, length));
94
95 Replace cmd;
96 cmd.pos = pos;
97 cmd.length = length;
98 cmd.replacement = replacement;
99 replaceList += cmd;
100 }
101
move(int pos,int length,int to)102 void TextWriter::move(int pos, int length, int to)
103 {
104 Q_ASSERT(!hasOverlap(pos, length));
105
106 Move cmd;
107 cmd.pos = pos;
108 cmd.length = length;
109 cmd.to = to;
110 moveList += cmd;
111 }
112
doReplace(const Replace & replace)113 void TextWriter::doReplace(const Replace &replace)
114 {
115 int diff = replace.replacement.size() - replace.length;
116 {
117 QMutableListIterator<Replace> i(replaceList);
118 while (i.hasNext()) {
119 Replace &c = i.next();
120 if (replace.pos < c.pos)
121 c.pos += diff;
122 else if (replace.pos + replace.length < c.pos + c.length)
123 c.length += diff;
124 }
125 }
126 {
127 QMutableListIterator<Move> i(moveList);
128 while (i.hasNext()) {
129 Move &c = i.next();
130 if (replace.pos < c.pos)
131 c.pos += diff;
132 else if (replace.pos + replace.length < c.pos + c.length)
133 c.length += diff;
134
135 if (replace.pos < c.to)
136 c.to += diff;
137 }
138 }
139
140 if (string) {
141 string->replace(replace.pos, replace.length, replace.replacement);
142 } else if (cursor) {
143 cursor->setPosition(replace.pos);
144 cursor->setPosition(replace.pos + replace.length, QTextCursor::KeepAnchor);
145 cursor->insertText(replace.replacement);
146 }
147 }
148
doMove(const Move & move)149 void TextWriter::doMove(const Move &move)
150 {
151 QString text;
152 if (string) {
153 text = string->mid(move.pos, move.length);
154 } else if (cursor) {
155 cursor->setPosition(move.pos);
156 cursor->setPosition(move.pos + move.length, QTextCursor::KeepAnchor);
157 text = cursor->selectedText();
158 }
159
160 Replace cut;
161 cut.pos = move.pos;
162 cut.length = move.length;
163 Replace paste;
164 paste.pos = move.to;
165 paste.length = 0;
166 paste.replacement = text;
167
168 replaceList.append(cut);
169 replaceList.append(paste);
170
171 Replace cmd;
172 while (!replaceList.isEmpty()) {
173 cmd = replaceList.first();
174 replaceList.removeFirst();
175 doReplace(cmd);
176 }
177 }
178
write(QString * s)179 void TextWriter::write(QString *s)
180 {
181 string = s;
182 write_helper();
183 string = 0;
184 }
185
write(QTextCursor * textCursor)186 void TextWriter::write(QTextCursor *textCursor)
187 {
188 cursor = textCursor;
189 write_helper();
190 cursor = 0;
191 }
192
write_helper()193 void TextWriter::write_helper()
194 {
195 if (cursor)
196 cursor->beginEditBlock();
197 {
198 Replace cmd;
199 while (!replaceList.isEmpty()) {
200 cmd = replaceList.first();
201 replaceList.removeFirst();
202 doReplace(cmd);
203 }
204 }
205 {
206 Move cmd;
207 while (!moveList.isEmpty()) {
208 cmd = moveList.first();
209 moveList.removeFirst();
210 doMove(cmd);
211 }
212 }
213 if (cursor)
214 cursor->endEditBlock();
215 }
216
217 QT_QML_END_NAMESPACE
218