blob: d60faf4859411bdfa1bf4707d021bec8a0bdfd90 [file] [log] [blame]
itrimble38bf0b92006-10-30 18:59:16 +00001/*******************************************************************************
2 * Copyright (c) 2006 Sybase, Inc. and others.
3 *
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Sybase, Inc. - initial API and implementation
11 *******************************************************************************/
12package org.eclipse.jst.pagedesigner.commands.range;
13
14import java.util.Stack;
15import java.util.Vector;
16
cbateman8c348742007-01-09 00:25:49 +000017import org.eclipse.core.runtime.Assert;
itrimble38bf0b92006-10-30 18:59:16 +000018import org.eclipse.gef.GraphicalViewer;
19import org.eclipse.gef.dnd.TemplateTransfer;
itrimble38bf0b92006-10-30 18:59:16 +000020import org.eclipse.jst.pagedesigner.IHTMLConstants;
21import org.eclipse.jst.pagedesigner.css2.CSSUtil;
22import org.eclipse.jst.pagedesigner.css2.ICSSStyle;
23import org.eclipse.jst.pagedesigner.dom.DOMRange;
24import org.eclipse.jst.pagedesigner.dom.EditHelper;
25import org.eclipse.jst.pagedesigner.dom.EditModelQuery;
26import org.eclipse.jst.pagedesigner.dom.EditValidateUtil;
27import org.eclipse.jst.pagedesigner.dom.IDOMPosition;
28import org.eclipse.jst.pagedesigner.utils.DOMUtil;
29import org.eclipse.swt.dnd.Clipboard;
30import org.eclipse.swt.dnd.TextTransfer;
31import org.eclipse.swt.dnd.Transfer;
itrimble38bf0b92006-10-30 18:59:16 +000032import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
33import org.w3c.dom.Document;
34import org.w3c.dom.Element;
35import org.w3c.dom.Node;
36import org.w3c.dom.Text;
37
38/**
39 * @author mengbo
40 */
41public abstract class DesignEdit {
itrimble38bf0b92006-10-30 18:59:16 +000042
cbateman7f14e202007-10-15 04:22:37 +000043 private Stack _selections;
itrimble38bf0b92006-10-30 18:59:16 +000044
45 private DOMRange _range;
46
47 private GraphicalViewer _viewer;
48
49 private IDOMPosition _operationPosition;
50
cbateman7f14e202007-10-15 04:22:37 +000051 private final Document _document;
itrimble38bf0b92006-10-30 18:59:16 +000052
cbateman7f14e202007-10-15 04:22:37 +000053 private Stack _processedResult;
itrimble38bf0b92006-10-30 18:59:16 +000054
cbateman7f14e202007-10-15 04:22:37 +000055 /**
56 * @param range
57 * @param viewer
58 */
itrimble38bf0b92006-10-30 18:59:16 +000059 public DesignEdit(DOMRange range, GraphicalViewer viewer) {
60 setRange(range);
61 _viewer = viewer;
62 _operationPosition = getRange().getStartPosition();
63 _document = ((IDOMNode) _operationPosition.getContainerNode())
64 .getModel().getDocument();
itrimble38bf0b92006-10-30 18:59:16 +000065 }
66
cbateman7f14e202007-10-15 04:22:37 +000067
68 /**
69 * @return the target document
70 */
71 protected final Document getDocument() {
72 return _document;
73 }
itrimble38bf0b92006-10-30 18:59:16 +000074
cbateman7f14e202007-10-15 04:22:37 +000075 /**
76 * @return the result
77 */
78 protected abstract boolean operate();
79
80 /**
81 * @param node
82 * @return the text
83 */
itrimble38bf0b92006-10-30 18:59:16 +000084 protected abstract Text processText(WorkNode node);
85
cbateman7f14e202007-10-15 04:22:37 +000086 /**
87 * @param node
88 * @return the node
89 */
itrimble38bf0b92006-10-30 18:59:16 +000090 protected abstract Node processNode(WorkNode node);
91
cbateman7f14e202007-10-15 04:22:37 +000092 /**
93 * @param node
94 * @return the node
95 */
itrimble38bf0b92006-10-30 18:59:16 +000096 protected abstract Node processContainer(WorkNode node);
97
cbateman7f14e202007-10-15 04:22:37 +000098 /**
99 * @return the dom range
100 */
itrimble38bf0b92006-10-30 18:59:16 +0000101 public DOMRange getRange() {
102 return _range;
103 }
104
105 void setRange(DOMRange range) {
106 range = EditHelper.normal(range);
107 IDOMPosition start = EditHelper.ensureDOMPosition(range
108 .getStartPosition());
109 IDOMPosition end = EditHelper.ensureDOMPosition(range.getEndPosition());
110 _range = new DOMRange(start, end);
111 EditValidateUtil.validRange(range);
112 }
113
cbateman7f14e202007-10-15 04:22:37 +0000114 /**
115 * @return the clipboard
116 */
itrimble38bf0b92006-10-30 18:59:16 +0000117 protected Clipboard getClipboard() {
118 return new Clipboard(_viewer.getControl().getDisplay());
119 }
120
cbateman7f14e202007-10-15 04:22:37 +0000121 /**
122 * @return the position
123 */
itrimble38bf0b92006-10-30 18:59:16 +0000124 public IDOMPosition getOperationPosition() {
125 // try
126 // {
127 // Assert.isTrue(_operationPosition != null &&
128 // _operationPosition.getContainerNode() != null &&
129 // _operationPosition.getOffset() > -1);
130 // if (_operationPosition.isText())
131 // {
132 // int length = ((Text)
133 // _operationPosition.getContainerNode()).getLength();
134 // Assert.isTrue(_operationPosition.getOffset() >= 0 &&
135 // _operationPosition.getOffset() <= length);
136 // }
137 // }
138 // catch (Exception e)
139 // {
140 // // "Error", "Error in operation location move"
141 // PDPlugin.getAlerts().confirm("Alert.DesignEdit.opLocationValidTitle",
142 // "Alert.DesignEdit.opLocationValidMessage"); //$NON-NLS-1$
143 // //$NON-NLS-2$
144 // }
145
146 return _operationPosition;
147 }
148
cbateman7f14e202007-10-15 04:22:37 +0000149 /**
150 * @param position
151 */
itrimble38bf0b92006-10-30 18:59:16 +0000152 protected void setOperationPosition(IDOMPosition position) {
153 if (!EditValidateUtil.validPosition(position)) {
154 return;
155 }
156 position = EditHelper.ensureDOMPosition(position);
157 _operationPosition = position;
158 }
159
cbateman7f14e202007-10-15 04:22:37 +0000160 /**
161 * @return the result of performing the edit
162 */
itrimble38bf0b92006-10-30 18:59:16 +0000163 public boolean perform() {
164 boolean result = false;
165
166 result = operate();
167 return result;
168 }
169
170 /**
171 * @return Returns the _viewer.
172 */
173 public GraphicalViewer getViewer() {
174 return _viewer;
175 }
176
177 private Stack collectNodes() {
178 Node node;
179 Stack result = new Stack();
180 IDOMPosition start = getRange().getStartPosition(), end = getRange()
181 .getEndPosition();
182 int pos[] = new int[] { EditModelQuery.getIndexedRegionLocation(start),
183 EditModelQuery.getIndexedRegionLocation(end), };
184 if (!EditModelQuery.isSame(start, end)) {
185 Node ancestor = EditModelQuery.getInstance().getCommonAncestor(
186 start, end);
187 WorkNode rootWorkNode = new WorkNode(ancestor, pos[0], pos[1]);
188 rootWorkNode.setRoot(true);
189 result.push(rootWorkNode);
190 try {
191 // Loop all the children of the ancestor, and and the result
192 // will be collected
193 if (EditModelQuery.isText(ancestor)) {
194 Stack temp = new Stack();
195 EditHelper.getInstance().collectNodes(ancestor, pos[0],
196 pos[1], ancestor, temp);
197 WorkNode wNode = (WorkNode) temp.remove(0);
198 wNode.setParent(rootWorkNode);
199 result.push(wNode);
200 } else {
201 node = ancestor.getFirstChild();
202 Stack temp = new Stack();
203 while (node != null) {
204 EditHelper.getInstance().collectNodes(node, pos[0],
205 pos[1], ancestor, temp);
206 while (temp.size() > 0) {
207 WorkNode wNode = (WorkNode) temp.remove(0);
208 if (wNode.getNode().getParentNode() == ancestor) {
209 wNode.setParent(rootWorkNode);
210 }
211 result.push(wNode);
212 }
213 node = node.getNextSibling();
214 }
215 }
216 } catch (Exception e) {
217 result.clear();
218 }
219 }
220 return result;
221 }
222
223 /**
224 * @return Returns the result.
225 */
226 public Stack getSelections() {
227 if (_selections == null) {
228 _selections = collectNodes();
229 }
230 return _selections;
231 }
232
cbateman7f14e202007-10-15 04:22:37 +0000233 /**
234 * @return the result stack
235 */
itrimble38bf0b92006-10-30 18:59:16 +0000236 public Stack getProcessedResult() {
237 if (_processedResult == null) {
238 _processedResult = new Stack();
239 WorkNode rootNode = getRootWorkNode();
240 if (rootNode != null) {
241 processNodes(rootNode, _processedResult);
242 }
243 }
244 return _processedResult;
245 }
246
cbateman7f14e202007-10-15 04:22:37 +0000247 /**
248 * @return the root work node
249 */
itrimble38bf0b92006-10-30 18:59:16 +0000250 protected final WorkNode getRootWorkNode() {
251 WorkNode result = null;
252 if (getSelections().size() > 0) {
253 WorkNode node = (WorkNode) getSelections().get(0);
254 while (node.getParent() != null) {
255 node = node.getParent();
256 }
257 result = node;
258 Assert.isTrue(node.isRoot());
259 }
260 return result;
261 }
262
cbateman7f14e202007-10-15 04:22:37 +0000263 /**
264 * @param node
265 * @param result
266 * @return true if node
267 */
268 private final boolean processText(WorkNode node, Stack result) {
itrimble38bf0b92006-10-30 18:59:16 +0000269 boolean done = false;
270 if (EditModelQuery.isText(node.getNode())) {
271 Node text = processText(node);
272 if (text != null) {
273 result.add(text);
274 }
275 getSelections().remove(node);
276 done = true;
277 }
278 return done;
279 }
280
cbateman7f14e202007-10-15 04:22:37 +0000281 /**
282 * @param node
283 * @param result
284 */
285 private final void processContainer(WorkNode node, Stack result) {
itrimble38bf0b92006-10-30 18:59:16 +0000286 processContainer(node);
287 getSelections().remove(node);
itrimble38bf0b92006-10-30 18:59:16 +0000288 }
289
cbateman7f14e202007-10-15 04:22:37 +0000290 /**
291 * @param node
292 * @param result
293 * @return true if done
294 */
295 private final boolean processChildren(WorkNode node, Stack result) {
itrimble38bf0b92006-10-30 18:59:16 +0000296 boolean done = false;
297 if (getFirstSelectedChild(node) != null) {
298 Stack myResult = new Stack();
299 {
300 WorkNode child = null;
301 while ((child = getFirstSelectedChild(node)) != null) {
302 {
303 processNodes(child, myResult);
304 }
305 }
306 Node newParent = processContainer(node);
307 newParent = toBeParent(newParent, myResult);
308 result.push(newParent);
309 }
310 getSelections().remove(node);
311 done = true;
312 }
313 return done;
314 }
315
cbateman7f14e202007-10-15 04:22:37 +0000316 /**
317 * @param node
318 * @param result
319 * @return true if done
320 */
321 private final boolean processChildren1(WorkNode node, Stack result) {
itrimble38bf0b92006-10-30 18:59:16 +0000322 boolean done = false;
323 if (node.getNode().hasChildNodes()) {
324 Stack myResult = new Stack();
325 {
326 Node childNode = node.getNode().getFirstChild();
327 Node next = null;
328 while (childNode != null) {
329 next = childNode.getNextSibling();
330 int x1 = EditModelQuery.getNodeStartIndex(childNode) - 1;
331 int x2 = EditModelQuery.getNodeEndIndex(childNode) + 1;
332 processNodes(new WorkNode(childNode, x1, x2), myResult);
333 childNode = next;
334 }
335 Node newParent = processContainer(node);
336 newParent = toBeParent(newParent, myResult);
337 result.push(newParent);
338 }
339 getSelections().remove(node);
340 done = true;
341 }
342 return done;
343 }
344
345 /**
346 * Process the nodes that are selected, the result is a collection of nodes
347 * that either are clones or the nodes cuted.
348 *
349 * @param node
itrimble38bf0b92006-10-30 18:59:16 +0000350 * @param result
351 */
352 protected final void processNodes(WorkNode node, Stack result) {
353 WorkNode child = null;
354 if (node.isRoot()) {
355 while ((child = getFirstSelectedChild(node)) != null) {
356 processNodes(child, result);
357 }
358 } else {
359 if (node.isWholeSelected()
360 || //
361 (!EditModelQuery.isText(node.getNode()) && EditModelQuery
362 .getInstance().isSingleRegionNode(node.getNode()))
363 || //
364 EditModelQuery.isWidget(node.getNode())) {
365 Node temp = processNode(node);
366 if (temp != null) {
367 result.push(temp);
368 getSelections().remove(node);
369 } else {
370 if (!processText(node, result)) {
371 if (!processChildren1(node, result)) {
372 processContainer(node, result);
373 }
374 }
375 }
376 } else {
377 if (!processText(node, result)) {
378 if (!processChildren(node, result)) {
379 processContainer(node, result);
380 }
381 }
382 }
383 }
384 }
385
cbateman7f14e202007-10-15 04:22:37 +0000386 /**
387 * @param result
388 */
itrimble38bf0b92006-10-30 18:59:16 +0000389 protected void setClipboard(Stack result) {
390 Node[] nodes = (Node[]) result.toArray(new Node[result.size()]);
391 StringBuffer sb = new StringBuffer();
392 for (int i = 0, size = nodes.length; i < size; i++) {
393 DOMUtil.nodeToString(nodes[i], sb);
394 }
395 getClipboard().setContents(
396 new Object[] { result, sb.toString() },
397 new Transfer[] { TemplateTransfer.getInstance(),
398 TextTransfer.getInstance() });
399 }
400
401 private Node toBeParent(Node parent, Stack children) {
402 while (children.size() > 0) {
403 parent.appendChild((Node) children.remove(0));
404 }
405 return parent;
406 }
407
408 private WorkNode getFirstSelectedChild(WorkNode node) {
409 for (int i = 0, n = getSelections().size(); i < n; i++) {
410 WorkNode wNode = (WorkNode) getSelections().get(i);
411 if (wNode.getParent() == node) {
412 return wNode;
413 }
414 }
415 return null;
416 }
417
cbateman7f14e202007-10-15 04:22:37 +0000418 /**
419 * @param rootNode
420 * @param result
421 * @return the node
422 */
423 Node collectStyleNodes(Node rootNode, Vector result) {
itrimble38bf0b92006-10-30 18:59:16 +0000424 Element element = null;
425 if (rootNode instanceof Element) {
426 element = (Element) rootNode;
427 } else if (rootNode.getParentNode() != null) {
428 element = (Element) rootNode.getParentNode();
429 }
430 ICSSStyle style = CSSUtil.getCSSStyle(element);
431
432 Node node = EditModelQuery.getDocumentNode(rootNode).createElement(
gkesslercfc53082008-11-18 22:25:04 +0000433 "span"); //$NON-NLS-1$
itrimble38bf0b92006-10-30 18:59:16 +0000434 for (int i = 0, n = result.size(); i < n; i++) {
435 node.appendChild((Node) result.elementAt(i));
436 }
437 ((Element) node).setAttribute(IHTMLConstants.ATTR_STYLE, CSSUtil
438 .resolveCSSStyle(style));
439 result.removeAllElements();
440 result.add(node);
441 return node;
442 }
443
cbateman7f14e202007-10-15 04:22:37 +0000444 /**
445 * @param rootNode
446 * @param result
447 * @return the node
448 */
449 protected final Node collectOtherStyles(Node rootNode, Vector result) {
itrimble38bf0b92006-10-30 18:59:16 +0000450 Node cur = rootNode, prev = null, appendPoint = null;
451 if (EditValidateUtil.validNode(rootNode)) {
452 while (!EditModelQuery.isDocument(cur)) {
453 if (!EditValidateUtil.validNode(cur)) {
454 return null;
455 }
456 String name = cur.getNodeName() != null ? cur.getNodeName()
gkesslercfc53082008-11-18 22:25:04 +0000457 .toLowerCase() : ""; //$NON-NLS-1$
itrimble38bf0b92006-10-30 18:59:16 +0000458 if (EditModelQuery.HTML_STYLE_NODES.contains(name)) {
459 if (prev != null) {
460 Node newone = cur.cloneNode(false);
461 newone.appendChild(prev);
462 prev = newone;
463 } else {
464 prev = cur.cloneNode(false);
465 appendPoint = prev;
466 }
467 }
468 cur = cur.getParentNode();
469 }
470 if (appendPoint != null) {
471 for (int i = 0, n = result.size(); i < n; i++) {
472 appendPoint.appendChild((Node) result.elementAt(i));
473 }
474 result.removeAllElements();
475 result.add(prev);
476 }
477 }
478 return prev;
479 }
480}