1 /*******************************************************************************
\r
2 * Copyright (c) 2006 Sybase, Inc. and others.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * Sybase, Inc. - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.eclipse.jst.pagedesigner.commands.range;
\r
14 import java.util.Stack;
\r
15 import java.util.Vector;
\r
17 import org.eclipse.core.runtime.Assert;
\r
18 import org.eclipse.gef.GraphicalViewer;
\r
19 import org.eclipse.gef.dnd.TemplateTransfer;
\r
20 import org.eclipse.jst.pagedesigner.IHTMLConstants;
\r
21 import org.eclipse.jst.pagedesigner.css2.CSSUtil;
\r
22 import org.eclipse.jst.pagedesigner.css2.ICSSStyle;
\r
23 import org.eclipse.jst.pagedesigner.dom.DOMRange;
\r
24 import org.eclipse.jst.pagedesigner.dom.EditHelper;
\r
25 import org.eclipse.jst.pagedesigner.dom.EditModelQuery;
\r
26 import org.eclipse.jst.pagedesigner.dom.EditValidateUtil;
\r
27 import org.eclipse.jst.pagedesigner.dom.IDOMPosition;
\r
28 import org.eclipse.jst.pagedesigner.utils.DOMUtil;
\r
29 import org.eclipse.swt.dnd.Clipboard;
\r
30 import org.eclipse.swt.dnd.TextTransfer;
\r
31 import org.eclipse.swt.dnd.Transfer;
\r
32 import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
\r
33 import org.w3c.dom.Document;
\r
34 import org.w3c.dom.Element;
\r
35 import org.w3c.dom.Node;
\r
36 import org.w3c.dom.Text;
\r
41 public abstract class DesignEdit {
\r
43 private Stack _selections;
\r
45 private DOMRange _range;
\r
47 private GraphicalViewer _viewer;
\r
49 private IDOMPosition _operationPosition;
\r
51 private final Document _document;
\r
53 private Stack _processedResult;
\r
59 public DesignEdit(DOMRange range, GraphicalViewer viewer) {
\r
62 _operationPosition = getRange().getStartPosition();
\r
63 _document = ((IDOMNode) _operationPosition.getContainerNode())
\r
64 .getModel().getDocument();
\r
69 * @return the target document
\r
71 protected final Document getDocument() {
\r
76 * @return the result
\r
78 protected abstract boolean operate();
\r
84 protected abstract Text processText(WorkNode node);
\r
90 protected abstract Node processNode(WorkNode node);
\r
96 protected abstract Node processContainer(WorkNode node);
\r
99 * @return the dom range
\r
101 public DOMRange getRange() {
\r
105 void setRange(DOMRange range) {
\r
106 range = EditHelper.normal(range);
\r
107 IDOMPosition start = EditHelper.ensureDOMPosition(range
\r
108 .getStartPosition());
\r
109 IDOMPosition end = EditHelper.ensureDOMPosition(range.getEndPosition());
\r
110 _range = new DOMRange(start, end);
\r
111 EditValidateUtil.validRange(range);
\r
115 * @return the clipboard
\r
117 protected Clipboard getClipboard() {
\r
118 return new Clipboard(_viewer.getControl().getDisplay());
\r
122 * @return the position
\r
124 public IDOMPosition getOperationPosition() {
\r
127 // Assert.isTrue(_operationPosition != null &&
\r
128 // _operationPosition.getContainerNode() != null &&
\r
129 // _operationPosition.getOffset() > -1);
\r
130 // if (_operationPosition.isText())
\r
132 // int length = ((Text)
\r
133 // _operationPosition.getContainerNode()).getLength();
\r
134 // Assert.isTrue(_operationPosition.getOffset() >= 0 &&
\r
135 // _operationPosition.getOffset() <= length);
\r
138 // catch (Exception e)
\r
140 // // "Error", "Error in operation location move"
\r
141 // PDPlugin.getAlerts().confirm("Alert.DesignEdit.opLocationValidTitle",
\r
142 // "Alert.DesignEdit.opLocationValidMessage"); //$NON-NLS-1$
\r
146 return _operationPosition;
\r
152 protected void setOperationPosition(IDOMPosition position) {
\r
153 if (!EditValidateUtil.validPosition(position)) {
\r
156 position = EditHelper.ensureDOMPosition(position);
\r
157 _operationPosition = position;
\r
161 * @return the result of performing the edit
\r
163 public boolean perform() {
\r
164 boolean result = false;
\r
166 result = operate();
\r
171 * @return Returns the _viewer.
\r
173 public GraphicalViewer getViewer() {
\r
177 private Stack collectNodes() {
\r
179 Stack result = new Stack();
\r
180 IDOMPosition start = getRange().getStartPosition(), end = getRange()
\r
182 int pos[] = new int[] { EditModelQuery.getIndexedRegionLocation(start),
\r
183 EditModelQuery.getIndexedRegionLocation(end), };
\r
184 if (!EditModelQuery.isSame(start, end)) {
\r
185 Node ancestor = EditModelQuery.getInstance().getCommonAncestor(
\r
187 WorkNode rootWorkNode = new WorkNode(ancestor, pos[0], pos[1]);
\r
188 rootWorkNode.setRoot(true);
\r
189 result.push(rootWorkNode);
\r
191 // Loop all the children of the ancestor, and and the result
\r
192 // will be collected
\r
193 if (EditModelQuery.isText(ancestor)) {
\r
194 Stack temp = new Stack();
\r
195 EditHelper.getInstance().collectNodes(ancestor, pos[0],
\r
196 pos[1], ancestor, temp);
\r
197 WorkNode wNode = (WorkNode) temp.remove(0);
\r
198 wNode.setParent(rootWorkNode);
\r
199 result.push(wNode);
\r
201 node = ancestor.getFirstChild();
\r
202 Stack temp = new Stack();
\r
203 while (node != null) {
\r
204 EditHelper.getInstance().collectNodes(node, pos[0],
\r
205 pos[1], ancestor, temp);
\r
206 while (temp.size() > 0) {
\r
207 WorkNode wNode = (WorkNode) temp.remove(0);
\r
208 if (wNode.getNode().getParentNode() == ancestor) {
\r
209 wNode.setParent(rootWorkNode);
\r
211 result.push(wNode);
\r
213 node = node.getNextSibling();
\r
216 } catch (Exception e) {
\r
224 * @return Returns the result.
\r
226 public Stack getSelections() {
\r
227 if (_selections == null) {
\r
228 _selections = collectNodes();
\r
230 return _selections;
\r
234 * @return the result stack
\r
236 public Stack getProcessedResult() {
\r
237 if (_processedResult == null) {
\r
238 _processedResult = new Stack();
\r
239 WorkNode rootNode = getRootWorkNode();
\r
240 if (rootNode != null) {
\r
241 processNodes(rootNode, _processedResult);
\r
244 return _processedResult;
\r
248 * @return the root work node
\r
250 protected final WorkNode getRootWorkNode() {
\r
251 WorkNode result = null;
\r
252 if (getSelections().size() > 0) {
\r
253 WorkNode node = (WorkNode) getSelections().get(0);
\r
254 while (node.getParent() != null) {
\r
255 node = node.getParent();
\r
258 Assert.isTrue(node.isRoot());
\r
266 * @return true if node
\r
268 private final boolean processText(WorkNode node, Stack result) {
\r
269 boolean done = false;
\r
270 if (EditModelQuery.isText(node.getNode())) {
\r
271 Node text = processText(node);
\r
272 if (text != null) {
\r
275 getSelections().remove(node);
\r
285 private final void processContainer(WorkNode node, Stack result) {
\r
286 processContainer(node);
\r
287 getSelections().remove(node);
\r
293 * @return true if done
\r
295 private final boolean processChildren(WorkNode node, Stack result) {
\r
296 boolean done = false;
\r
297 if (getFirstSelectedChild(node) != null) {
\r
298 Stack myResult = new Stack();
\r
300 WorkNode child = null;
\r
301 while ((child = getFirstSelectedChild(node)) != null) {
\r
303 processNodes(child, myResult);
\r
306 Node newParent = processContainer(node);
\r
307 newParent = toBeParent(newParent, myResult);
\r
308 result.push(newParent);
\r
310 getSelections().remove(node);
\r
319 * @return true if done
\r
321 private final boolean processChildren1(WorkNode node, Stack result) {
\r
322 boolean done = false;
\r
323 if (node.getNode().hasChildNodes()) {
\r
324 Stack myResult = new Stack();
\r
326 Node childNode = node.getNode().getFirstChild();
\r
328 while (childNode != null) {
\r
329 next = childNode.getNextSibling();
\r
330 int x1 = EditModelQuery.getNodeStartIndex(childNode) - 1;
\r
331 int x2 = EditModelQuery.getNodeEndIndex(childNode) + 1;
\r
332 processNodes(new WorkNode(childNode, x1, x2), myResult);
\r
335 Node newParent = processContainer(node);
\r
336 newParent = toBeParent(newParent, myResult);
\r
337 result.push(newParent);
\r
339 getSelections().remove(node);
\r
346 * Process the nodes that are selected, the result is a collection of nodes
\r
347 * that either are clones or the nodes cuted.
\r
352 protected final void processNodes(WorkNode node, Stack result) {
\r
353 WorkNode child = null;
\r
354 if (node.isRoot()) {
\r
355 while ((child = getFirstSelectedChild(node)) != null) {
\r
356 processNodes(child, result);
\r
359 if (node.isWholeSelected()
\r
361 (!EditModelQuery.isText(node.getNode()) && EditModelQuery
\r
362 .getInstance().isSingleRegionNode(node.getNode()))
\r
364 EditModelQuery.isWidget(node.getNode())) {
\r
365 Node temp = processNode(node);
\r
366 if (temp != null) {
\r
368 getSelections().remove(node);
\r
370 if (!processText(node, result)) {
\r
371 if (!processChildren1(node, result)) {
\r
372 processContainer(node, result);
\r
377 if (!processText(node, result)) {
\r
378 if (!processChildren(node, result)) {
\r
379 processContainer(node, result);
\r
389 protected void setClipboard(Stack result) {
\r
390 Node[] nodes = (Node[]) result.toArray(new Node[result.size()]);
\r
391 StringBuffer sb = new StringBuffer();
\r
392 for (int i = 0, size = nodes.length; i < size; i++) {
\r
393 DOMUtil.nodeToString(nodes[i], sb);
\r
395 getClipboard().setContents(
\r
396 new Object[] { result, sb.toString() },
\r
397 new Transfer[] { TemplateTransfer.getInstance(),
\r
398 TextTransfer.getInstance() });
\r
401 private Node toBeParent(Node parent, Stack children) {
\r
402 while (children.size() > 0) {
\r
403 parent.appendChild((Node) children.remove(0));
\r
408 private WorkNode getFirstSelectedChild(WorkNode node) {
\r
409 for (int i = 0, n = getSelections().size(); i < n; i++) {
\r
410 WorkNode wNode = (WorkNode) getSelections().get(i);
\r
411 if (wNode.getParent() == node) {
\r
423 Node collectStyleNodes(Node rootNode, Vector result) {
\r
424 Element element = null;
\r
425 if (rootNode instanceof Element) {
\r
426 element = (Element) rootNode;
\r
427 } else if (rootNode.getParentNode() != null) {
\r
428 element = (Element) rootNode.getParentNode();
\r
430 ICSSStyle style = CSSUtil.getCSSStyle(element);
\r
432 Node node = EditModelQuery.getDocumentNode(rootNode).createElement(
\r
433 "span"); //$NON-NLS-1$
\r
434 for (int i = 0, n = result.size(); i < n; i++) {
\r
435 node.appendChild((Node) result.elementAt(i));
\r
437 ((Element) node).setAttribute(IHTMLConstants.ATTR_STYLE, CSSUtil
\r
438 .resolveCSSStyle(style));
\r
439 result.removeAllElements();
\r
449 protected final Node collectOtherStyles(Node rootNode, Vector result) {
\r
450 Node cur = rootNode, prev = null, appendPoint = null;
\r
451 if (EditValidateUtil.validNode(rootNode)) {
\r
452 while (!EditModelQuery.isDocument(cur)) {
\r
453 if (!EditValidateUtil.validNode(cur)) {
\r
456 String name = cur.getNodeName() != null ? cur.getNodeName()
\r
457 .toLowerCase() : ""; //$NON-NLS-1$
\r
458 if (EditModelQuery.HTML_STYLE_NODES.contains(name)) {
\r
459 if (prev != null) {
\r
460 Node newone = cur.cloneNode(false);
\r
461 newone.appendChild(prev);
\r
464 prev = cur.cloneNode(false);
\r
465 appendPoint = prev;
\r
468 cur = cur.getParentNode();
\r
470 if (appendPoint != null) {
\r
471 for (int i = 0, n = result.size(); i < n; i++) {
\r
472 appendPoint.appendChild((Node) result.elementAt(i));
\r
474 result.removeAllElements();
\r