Initialize
[sdk/ide/product.git] / org.eclipse.jst.pagedesigner / src / org / eclipse / jst / pagedesigner / commands / range / DesignEdit.java
1 /*******************************************************************************\r
2  * Copyright (c) 2006 Sybase, Inc. and others.\r
3  *\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
8  *\r
9  * Contributors:\r
10  *     Sybase, Inc. - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.eclipse.jst.pagedesigner.commands.range;\r
13 \r
14 import java.util.Stack;\r
15 import java.util.Vector;\r
16 \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
37 \r
38 /**\r
39  * @author mengbo\r
40  */\r
41 public abstract class DesignEdit {\r
42 \r
43     private Stack _selections;\r
44 \r
45         private DOMRange _range;\r
46 \r
47         private GraphicalViewer _viewer;\r
48 \r
49         private IDOMPosition _operationPosition;\r
50 \r
51         private final Document _document;\r
52 \r
53         private Stack _processedResult;\r
54 \r
55         /**\r
56          * @param range\r
57          * @param viewer\r
58          */\r
59         public DesignEdit(DOMRange range, GraphicalViewer viewer) {\r
60                 setRange(range);\r
61                 _viewer = viewer;\r
62                 _operationPosition = getRange().getStartPosition();\r
63                 _document = ((IDOMNode) _operationPosition.getContainerNode())\r
64                                 .getModel().getDocument();\r
65         }\r
66 \r
67         \r
68         /**\r
69          * @return the target document\r
70          */\r
71         protected final Document getDocument() {\r
72         return _document;\r
73     }\r
74 \r
75     /**\r
76      * @return the result\r
77      */\r
78     protected abstract boolean operate();\r
79 \r
80         /**\r
81          * @param node\r
82          * @return the text\r
83          */\r
84         protected abstract Text processText(WorkNode node);\r
85 \r
86         /**\r
87          * @param node\r
88          * @return the node \r
89          */\r
90         protected abstract Node processNode(WorkNode node);\r
91 \r
92         /**\r
93          * @param node\r
94          * @return the node\r
95          */\r
96         protected abstract Node processContainer(WorkNode node);\r
97 \r
98         /**\r
99          * @return the dom range\r
100          */ \r
101         public DOMRange getRange() {\r
102                 return _range;\r
103         }\r
104 \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
112         }\r
113 \r
114         /**\r
115          * @return the clipboard\r
116          */\r
117         protected Clipboard getClipboard() {\r
118                 return new Clipboard(_viewer.getControl().getDisplay());\r
119         }\r
120 \r
121         /**\r
122          * @return the position\r
123          */\r
124         public IDOMPosition getOperationPosition() {\r
125                 // try\r
126                 // {\r
127                 // Assert.isTrue(_operationPosition != null &&\r
128                 // _operationPosition.getContainerNode() != null &&\r
129                 // _operationPosition.getOffset() > -1);\r
130                 // if (_operationPosition.isText())\r
131                 // {\r
132                 // int length = ((Text)\r
133                 // _operationPosition.getContainerNode()).getLength();\r
134                 // Assert.isTrue(_operationPosition.getOffset() >= 0 &&\r
135                 // _operationPosition.getOffset() <= length);\r
136                 // }\r
137                 // }\r
138                 // catch (Exception e)\r
139                 // {\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
143                 // //$NON-NLS-2$\r
144                 // }\r
145 \r
146                 return _operationPosition;\r
147         }\r
148 \r
149         /**\r
150          * @param position\r
151          */\r
152         protected void setOperationPosition(IDOMPosition position) {\r
153                 if (!EditValidateUtil.validPosition(position)) {\r
154                         return;\r
155                 }\r
156                 position = EditHelper.ensureDOMPosition(position);\r
157                 _operationPosition = position;\r
158         }\r
159 \r
160         /**\r
161          * @return the result of performing the edit\r
162          */\r
163         public boolean perform() {\r
164                 boolean result = false;\r
165 \r
166                 result = operate();\r
167                 return result;\r
168         }\r
169 \r
170         /**\r
171          * @return Returns the _viewer.\r
172          */\r
173         public GraphicalViewer getViewer() {\r
174                 return _viewer;\r
175         }\r
176 \r
177         private Stack collectNodes() {\r
178                 Node node;\r
179                 Stack result = new Stack();\r
180                 IDOMPosition start = getRange().getStartPosition(), end = getRange()\r
181                                 .getEndPosition();\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
186                                         start, end);\r
187                         WorkNode rootWorkNode = new WorkNode(ancestor, pos[0], pos[1]);\r
188                         rootWorkNode.setRoot(true);\r
189                         result.push(rootWorkNode);\r
190                         try {\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
200                                 } else {\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
210                                                         }\r
211                                                         result.push(wNode);\r
212                                                 }\r
213                                                 node = node.getNextSibling();\r
214                                         }\r
215                                 }\r
216                         } catch (Exception e) {\r
217                                 result.clear();\r
218                         }\r
219                 }\r
220                 return result;\r
221         }\r
222 \r
223         /**\r
224          * @return Returns the result.\r
225          */\r
226         public Stack getSelections() {\r
227                 if (_selections == null) {\r
228                         _selections = collectNodes();\r
229                 }\r
230                 return _selections;\r
231         }\r
232 \r
233         /**\r
234          * @return the result stack\r
235          */\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
242                         }\r
243                 }\r
244                 return _processedResult;\r
245         }\r
246 \r
247         /**\r
248          * @return the root work node\r
249          */\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
256                         }\r
257                         result = node;\r
258                         Assert.isTrue(node.isRoot());\r
259                 }\r
260                 return result;\r
261         }\r
262 \r
263         /**\r
264          * @param node\r
265          * @param result\r
266          * @return true if node\r
267          */\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
273                                 result.add(text);\r
274                         }\r
275                         getSelections().remove(node);\r
276                         done = true;\r
277                 }\r
278                 return done;\r
279         }\r
280 \r
281         /**\r
282          * @param node\r
283          * @param result\r
284          */\r
285         private final void processContainer(WorkNode node, Stack result) {\r
286                 processContainer(node);\r
287                 getSelections().remove(node);\r
288         }\r
289 \r
290         /**\r
291          * @param node\r
292          * @param result\r
293          * @return true if done\r
294          */\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
299                         {\r
300                                 WorkNode child = null;\r
301                                 while ((child = getFirstSelectedChild(node)) != null) {\r
302                                         {\r
303                                                 processNodes(child, myResult);\r
304                                         }\r
305                                 }\r
306                                 Node newParent = processContainer(node);\r
307                                 newParent = toBeParent(newParent, myResult);\r
308                                 result.push(newParent);\r
309                         }\r
310                         getSelections().remove(node);\r
311                         done = true;\r
312                 }\r
313                 return done;\r
314         }\r
315 \r
316         /**\r
317          * @param node\r
318          * @param result\r
319          * @return true if done\r
320          */\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
325                         {\r
326                                 Node childNode = node.getNode().getFirstChild();\r
327                                 Node next = null;\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
333                                         childNode = next;\r
334                                 }\r
335                                 Node newParent = processContainer(node);\r
336                                 newParent = toBeParent(newParent, myResult);\r
337                                 result.push(newParent);\r
338                         }\r
339                         getSelections().remove(node);\r
340                         done = true;\r
341                 }\r
342                 return done;\r
343         }\r
344 \r
345         /**\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
348          * \r
349          * @param node\r
350          * @param result\r
351          */\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
357                         }\r
358                 } else {\r
359                         if (node.isWholeSelected()\r
360                                         || //\r
361                                         (!EditModelQuery.isText(node.getNode()) && EditModelQuery\r
362                                                         .getInstance().isSingleRegionNode(node.getNode()))\r
363                                         || //\r
364                                         EditModelQuery.isWidget(node.getNode())) {\r
365                                 Node temp = processNode(node);\r
366                                 if (temp != null) {\r
367                                         result.push(temp);\r
368                                         getSelections().remove(node);\r
369                                 } else {\r
370                                         if (!processText(node, result)) {\r
371                                                 if (!processChildren1(node, result)) {\r
372                                                         processContainer(node, result);\r
373                                                 }\r
374                                         }\r
375                                 }\r
376                         } else {\r
377                                 if (!processText(node, result)) {\r
378                                         if (!processChildren(node, result)) {\r
379                                                 processContainer(node, result);\r
380                                         }\r
381                                 }\r
382                         }\r
383                 }\r
384         }\r
385 \r
386         /**\r
387          * @param result\r
388          */\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
394                 }\r
395                 getClipboard().setContents(\r
396                                 new Object[] { result, sb.toString() },\r
397                                 new Transfer[] { TemplateTransfer.getInstance(),\r
398                                                 TextTransfer.getInstance() });\r
399         }\r
400 \r
401         private Node toBeParent(Node parent, Stack children) {\r
402                 while (children.size() > 0) {\r
403                         parent.appendChild((Node) children.remove(0));\r
404                 }\r
405                 return parent;\r
406         }\r
407 \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
412                                 return wNode;\r
413                         }\r
414                 }\r
415                 return null;\r
416         }\r
417 \r
418         /**\r
419          * @param rootNode\r
420          * @param result\r
421          * @return the node\r
422          */\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
429                 }\r
430                 ICSSStyle style = CSSUtil.getCSSStyle(element);\r
431 \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
436                 }\r
437                 ((Element) node).setAttribute(IHTMLConstants.ATTR_STYLE, CSSUtil\r
438                                 .resolveCSSStyle(style));\r
439                 result.removeAllElements();\r
440                 result.add(node);\r
441                 return node;\r
442         }\r
443 \r
444         /**\r
445          * @param rootNode\r
446          * @param result \r
447          * @return the node\r
448          */\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
454                                         return null;\r
455                                 }\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
462                                                 prev = newone;\r
463                                         } else {\r
464                                                 prev = cur.cloneNode(false);\r
465                                                 appendPoint = prev;\r
466                                         }\r
467                                 }\r
468                                 cur = cur.getParentNode();\r
469                         }\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
473                                 }\r
474                                 result.removeAllElements();\r
475                                 result.add(prev);\r
476                         }\r
477                 }\r
478                 return prev;\r
479         }\r
480 }\r