0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.netbeans.modules.visualweb.designer.jsf.text;
0043:
0044: import com.sun.rave.designtime.DesignBean;
0045: import com.sun.rave.designtime.markup.MarkupDesignBean;
0046: import java.awt.Point;
0047: import java.util.ArrayList;
0048: import java.util.List;
0049: import javax.swing.event.EventListenerList;
0050: import org.netbeans.modules.visualweb.api.designer.Designer;
0051: import org.netbeans.modules.visualweb.api.designer.Designer.Box;
0052:
0053: import org.netbeans.modules.visualweb.api.designer.DomProvider;
0054: import org.netbeans.modules.visualweb.api.designer.DomProvider.DomDocumentEvent;
0055: import org.netbeans.modules.visualweb.api.designer.DomProvider.DomDocumentListener;
0056: import org.netbeans.modules.visualweb.api.designer.DomProvider.DomDocument;
0057: import org.netbeans.modules.visualweb.api.designer.DomProvider.DomPosition;
0058: import org.netbeans.modules.visualweb.api.designer.DomProvider.DomPosition.Bias;
0059: import org.netbeans.modules.visualweb.api.designer.DomProvider.DomRange;
0060: import org.netbeans.modules.visualweb.api.designer.cssengine.CssProvider;
0061: import org.netbeans.modules.visualweb.api.designer.cssengine.CssValue;
0062: import org.netbeans.modules.visualweb.api.designer.cssengine.StyleData;
0063: import org.netbeans.modules.visualweb.api.designer.markup.MarkupService;
0064: import org.netbeans.modules.visualweb.api.designer.cssengine.XhtmlCss;
0065: import org.netbeans.modules.visualweb.designer.html.HtmlAttribute;
0066: import org.netbeans.modules.visualweb.designer.html.HtmlTag;
0067: import org.netbeans.modules.visualweb.designer.jsf.JsfForm;
0068: import org.netbeans.modules.visualweb.designer.jsf.JsfSupportUtilities;
0069: import org.netbeans.modules.visualweb.insync.UndoEvent;
0070: import org.netbeans.modules.visualweb.insync.markup.MarkupUnit;
0071:
0072: import org.openide.ErrorManager;
0073: import org.openide.util.NbBundle;
0074: import org.w3c.dom.DOMException;
0075:
0076: import org.w3c.dom.DocumentFragment;
0077: import org.w3c.dom.Element;
0078: import org.w3c.dom.Node;
0079: import org.w3c.dom.NodeList;
0080: import org.w3c.dom.Text;
0081: import org.w3c.dom.ranges.DocumentRange;
0082: import org.w3c.dom.traversal.DocumentTraversal;
0083: import org.w3c.dom.traversal.NodeFilter;
0084: import org.w3c.dom.traversal.NodeIterator;
0085:
0086: /**
0087: * XXX Moved from designer/../Document.
0088: *
0089: * Wrapper object for dom documents; holds some additional
0090: * state and document methods.
0091: *
0092: * @todo Refactor the EventListener into an adapter class
0093: * @todo IMPORTANT: I need to cache the font lookup stuff so
0094: * I don't keep recomputing it!
0095: * @author Tor Norbye
0096: */
0097: public class DomDocumentImpl implements DomProvider.DomDocument {
0098: // // DEBUG:
0099: // // Log info pertaining to document events
0100: // static final boolean debugevents = false;
0101: // private WebForm webform;
0102: private JsfForm jsfForm;
0103:
0104: // private ImageCache imageCache;
0105: // private DocumentCache frameCache;
0106:
0107: // /** For testsuite use only!!! */
0108: // public URL testBase;
0109:
0110: // /**
0111: // * The event listener list for the document.
0112: // */
0113: // protected EventListenerList listenerList = new EventListenerList();
0114:
0115: // --- Document locking ----------------------------------
0116: // private UndoEvent undoEvent;
0117:
0118: public DomDocumentImpl(/*WebForm webform*/JsfForm jsfForm) {
0119: // this.webform = webform;
0120: this .jsfForm = jsfForm;
0121:
0122: // Ensure we've got a model
0123: // TODO - this should be cleaned up
0124: // webform.getDomSynchronizer();
0125: }
0126:
0127: public String toString() {
0128: // if ((webform != null) && (webform.getModel() != null) && (webform.getMarkup() != null) &&
0129: // (webform.getMarkup().getFileObject() != null)) {
0130: // return "Document[" + webform.getMarkup().getFileObject().toString() + "]";
0131: // }
0132:
0133: // return super.toString() + "[webForm=" + webform + "]"; // NOI18N
0134: return super .toString() + "[jsfForm=" + jsfForm + "]"; // NOI18N
0135: }
0136:
0137: // public WebForm getWebForm() {
0138: // return webform;
0139: // }
0140:
0141: // /**
0142: // * Returns the location to resolve relative URLs against. By
0143: // * default this will be the document's URL if the document
0144: // * was loaded from a URL. If a base tag is found and
0145: // * can be parsed, it will be used as the base location.
0146: // *
0147: // * @return the base location
0148: // */
0149: // public URL getBase() {
0150: //// URL url = webform.getMarkup().getBase();
0151: // URL url = webform.getBaseUrl();
0152: //
0153: // if (url != null) {
0154: // return url;
0155: // }
0156: //
0157: // return testBase;
0158: // }
0159:
0160: // XXX Moved to Webform.
0161: // /**
0162: // * Return a cache of images for this document
0163: // */
0164: // public ImageCache getImageCache() {
0165: // if (imageCache == null) {
0166: // imageCache = new ImageCache();
0167: // }
0168: //
0169: // return imageCache;
0170: // }
0171: //
0172: // /**
0173: // * Return a cache of webform boxes associated with this document
0174: // * @todo Rename; it's no longer a box cache but rather a document
0175: // * cache!
0176: // */
0177: // public DocumentCache getFrameBoxCache() {
0178: // if (frameCache == null) {
0179: // frameCache = new DocumentCache();
0180: // }
0181: //
0182: // return frameCache;
0183: // }
0184: //
0185: // /**
0186: // * Return true iff the document has cached frame boxes
0187: // */
0188: // public boolean hasCachedFrameBoxes() {
0189: // return (frameCache != null) && (frameCache.size() > 0);
0190: // }
0191: //
0192: // /**
0193: // * Clear out caches for a "refresh" operation
0194: // */
0195: // public void flushCaches() {
0196: // if (frameCache != null) {
0197: // frameCache.flush();
0198: // }
0199: //
0200: // if (imageCache != null) {
0201: // imageCache.flush();
0202: // }
0203: // }
0204:
0205: // public void insertString(/*DesignerCaret caret,*/ Position pos, String str) {
0206: public boolean insertString(
0207: /*DesignerCaret caret,*/Designer designer,
0208: DomRange domRange, String str) {
0209: if (domRange == null) {
0210: return false;
0211: }
0212: // UndoEvent undoEvent = webform.getModel().writeLock(NbBundle.getMessage(DefaultKeyTypedAction.class, "InsertChar")); // NOI18N
0213: // DomProvider.WriteLock writeLock = jsfForm.writeLock(NbBundle.getMessage(DomDocumentImpl.class, "LBL_InsertText")); // NOI18N
0214: UndoEvent writeLock = jsfForm.writeLock(NbBundle.getMessage(
0215: DomDocumentImpl.class, "LBL_InsertText")); // NOI18N
0216: try {
0217:
0218: // if (hasSelection()) {
0219: // removeSelection();
0220: if (!domRange.isEmpty()) {
0221: deleteRangeContents(domRange);
0222: }
0223:
0224: // Position pos = getDot();
0225: // DomPosition pos = getDot();
0226: DomPosition pos = domRange.getDot();
0227:
0228: // if (editor == null) {
0229: // if (!component.getWebForm().isInlineEditing()) {
0230: if (!designer.isInlineEditing()) {
0231: // assert (pos == Position.NONE) || !pos.isRendered();
0232: // if (pos != Position.NONE && MarkupService.isRenderedNode(pos.getNode())) {
0233: // if (pos != DomPosition.NONE && MarkupService.isRenderedNode(pos.getNode())) {
0234: if (pos != DomPosition.NONE
0235: && isRenderedNode(pos.getNode())) {
0236: ErrorManager.getDefault().notify(
0237: ErrorManager.INFORMATIONAL,
0238: new IllegalStateException(
0239: "Node is expected to be not rendered, node="
0240: + pos.getNode())); // NOI18N
0241: return false;
0242: }
0243: } // else: Stay in the DocumentFragment; don't jump to the source DOM (there is none)
0244:
0245: // if (pos == Position.NONE) {
0246: if (pos == DomPosition.NONE) {
0247: // UIManager.getLookAndFeel().provideErrorFeedback(this);
0248: return false;
0249: }
0250:
0251: // TODO: If you're pressing shift while hitting Enter, we should force a <br/>,
0252: // and otherwise we should split the current block tag (if there is one, and
0253: // that block tag is not a <div> or a <body> (for these we always use <br>).
0254: // assert (pos != null) && (pos != Position.NONE);
0255: if (pos == null || pos == DomPosition.NONE) {
0256: ErrorManager.getDefault().notify(
0257: ErrorManager.INFORMATIONAL,
0258: new IllegalArgumentException(
0259: "Invalid position, pos=" + pos)); // NOI18N
0260: return false;
0261: }
0262:
0263: // Element body = webform.getHtmlBody();
0264: Element body = jsfForm.getHtmlBody();
0265:
0266: if ((pos.getNode() == body)
0267: || ((pos.getNode().getParentNode() == body)
0268: && (pos.getNode().getNodeType() == Node.TEXT_NODE) && JsfSupportUtilities
0269: .onlyWhitespace(pos.getNode()
0270: .getNodeValue()))) {
0271: // Trying to insert text right at the top <body> level.
0272: // Insert text in a paragraph instead!
0273: Node next = null;
0274:
0275: if (pos.getNode() == body) {
0276: next = body.getChildNodes().item(pos.getOffset());
0277: } else {
0278: next = pos.getNode().getNextSibling();
0279: }
0280:
0281: // XXX TODO get rid of using xhtml directly,
0282: // it should be shielded by api.
0283: Element p = createElement(
0284: org.netbeans.modules.visualweb.xhtml.P.class
0285: .getName(), body, next);
0286: createElement(
0287: org.netbeans.modules.visualweb.xhtml.Br.class
0288: .getName(), p, null);
0289:
0290: // pos.setLocation(p, 0, Bias.FORWARD);
0291: // caret.setDot(new Position(p, 0, Bias.FORWARD));
0292: fireInsertUpdate(new DefaultDomDocumentEvent(this ,
0293: createDomPosition(p, 0, Bias.FORWARD)));
0294: }
0295:
0296: if (str.equals("\n") || str.equals("\r\n")) {
0297: insertNewline(/*caret,*/pos.getNode(), pos.getOffset());
0298:
0299: return true;
0300: }
0301:
0302: // Can't put "&" directly in source!
0303: // if (str.equals("&") && !FacesSupport.isHtmlNode(webform, pos.getNode())) {
0304: if (str.equals("&")
0305: && !isHtmlNode(/*webform*/jsfForm, pos.getNode())) { // NOI18N
0306: str = "&"; // NOI18N
0307: }
0308:
0309: Node node = pos.getNode();
0310: int offset = pos.getOffset();
0311: Node targetNode = node; // Node to move caret to when we're done
0312: int targetOffset = offset;
0313:
0314: // TODO - replace <, >, ", etc. with entities
0315: if ((node.getNodeType() == Node.TEXT_NODE)
0316: || (node.getNodeType() == Node.CDATA_SECTION_NODE)) {
0317: org.w3c.dom.Text text = (org.w3c.dom.Text) node;
0318:
0319: if ((str.length() == 1) && (str.charAt(0) == ' ')) {
0320: insertSpace(/*caret,*/pos.getNode(), pos
0321: .getOffset());
0322:
0323: // XXX check that this works on Windows too - or do they
0324: // use \r\n ?
0325: return true;
0326: } else {
0327: text.insertData(offset, str);
0328: targetNode = text;
0329: targetOffset += str.length();
0330: }
0331:
0332: // caret.setDot(new Position(targetNode, targetOffset, pos.getBias()));
0333: fireInsertUpdate(new DefaultDomDocumentEvent(this ,
0334: createDomPosition(targetNode, targetOffset, pos
0335: .getBias())));
0336: } else if ((node.getNodeType() == Node.ELEMENT_NODE)
0337: || (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE)) {
0338: NodeList list = node.getChildNodes();
0339: int len = list.getLength();
0340:
0341: if ((len == 0) || (offset >= len)) {
0342: // We have a 0 index but no children, e.g. we're
0343: // inside an empty element.
0344: // XXX what if it's a newline??
0345: // Add a text node into the list, as the first
0346: // child
0347: // XXX for the <body> tag I should auto insert a <p>
0348: // too around the text...
0349: // org.w3c.dom.Document dom = webform.getJspDom();
0350: org.w3c.dom.Document dom = jsfForm.getJspDom();
0351:
0352: Node text = dom.createTextNode(str);
0353:
0354: // if (((RaveRenderNode)node).isJspx()) {
0355: if (MarkupService.isJspxNode(node)) {
0356: MarkupService.markJspxSource(text);
0357: }
0358:
0359: node.appendChild(text);
0360:
0361: // caret.setDot(new Position(text, str.length(), Bias.FORWARD));
0362: fireInsertUpdate(new DefaultDomDocumentEvent(this ,
0363: createDomPosition(text, str.length(),
0364: Bias.FORWARD)));
0365:
0366: return true;
0367: } else if (offset < len) {
0368: // Insert text before the given sibling;
0369: // if prev is a text node append to
0370: // that, otherwise insert a text node there
0371: if ((offset > 0)
0372: && (list.item(offset - 1) instanceof Text)) {
0373: org.w3c.dom.CharacterData text = (org.w3c.dom.CharacterData) list
0374: .item(offset - 1);
0375: text.appendData(str);
0376:
0377: // caret.setDot(new Position(text, text.getLength(), pos.getBias()));
0378: fireInsertUpdate(new DefaultDomDocumentEvent(
0379: this , createDomPosition(text, text
0380: .getLength(), pos.getBias())));
0381:
0382: return true;
0383: } else {
0384: // org.w3c.dom.Document dom = webform.getJspDom();
0385: org.w3c.dom.Document dom = jsfForm.getJspDom();
0386:
0387: Node text = dom.createTextNode(str);
0388:
0389: // if (((RaveRenderNode)node).isJspx()) {
0390: if (MarkupService.isJspxNode(node)) {
0391: MarkupService.markJspxSource(text);
0392: }
0393:
0394: Node before = list.item(offset);
0395: node.insertBefore(text, before);
0396:
0397: // caret.setDot(new Position(text, str.length(), Bias.FORWARD));
0398: fireInsertUpdate(new DefaultDomDocumentEvent(
0399: this , createDomPosition(text, str
0400: .length(), Bias.FORWARD)));
0401:
0402: return true;
0403: }
0404: }
0405: } else {
0406: ErrorManager.getDefault().log(
0407: "Unexpected node: " + offset + ", str=" + str);
0408: return false;
0409: }
0410: return true;
0411:
0412: } finally {
0413: // doc.writeUnlock();
0414: // webform.getModel().writeUnlock(undoEvent);
0415: jsfForm.writeUnlock(writeLock);
0416: }
0417:
0418: }
0419:
0420: public boolean deleteRangeContents(DomRange domRange) {
0421: if (domRange instanceof DomRangeImpl) {
0422: DomRangeImpl domRangeImpl = (DomRangeImpl) domRange;
0423:
0424: DomPosition firstPosition = domRangeImpl.getFirstPosition();
0425: DomPosition lastPosition = domRangeImpl.getLastPosition();
0426: // XXX For now it works only over the source nodes. That has to be changes.
0427: if (!jsfForm.isInlineEditing()
0428: // && (MarkupService.isRenderedNode(firstPosition.getNode()) || MarkupService.isRenderedNode(lastPosition.getNode()))) {
0429: && (isRenderedNode(firstPosition.getNode()) || isRenderedNode(lastPosition
0430: .getNode()))) {
0431: ErrorManager.getDefault().notify(
0432: ErrorManager.INFORMATIONAL,
0433: new IllegalStateException(
0434: "It is not inline editing, nor both positions are source ones," // NOI18N
0435: + "\nstartPosition="
0436: + firstPosition // NOI18N
0437: + "\nendPosition="
0438: + lastPosition)); // NOI18N
0439: return false;
0440: }
0441:
0442: deleteComponents(firstPosition, lastPosition);
0443: return domRangeImpl.deleteRangeContents();
0444: }
0445: return false;
0446: }
0447:
0448: public String getRangeText(DomRange domRange) {
0449: if (domRange instanceof DomRangeImpl) {
0450: DomRangeImpl domRangeImpl = (DomRangeImpl) domRange;
0451:
0452: DomPosition firstPosition = domRangeImpl.getFirstPosition();
0453: DomPosition lastPosition = domRangeImpl.getLastPosition();
0454: return getText(firstPosition, lastPosition);
0455: }
0456:
0457: return ""; // NOI18N
0458: }
0459:
0460: // XXX Moved from FacesSupport
0461: private static boolean isHtmlNode(
0462: /*WebForm webform*/JsfForm jsfForm, Node node) {
0463: if (node.getNodeType() == Node.TEXT_NODE) {
0464: node = node.getParentNode();
0465: }
0466:
0467: if ((node == null) || !(node instanceof Element)) {
0468: return false;
0469: }
0470:
0471: // RaveElement element = (RaveElement)node;
0472: // if (element.isRendered()) {
0473: // return true;
0474: // }
0475: // if (MarkupService.isRenderedNode(node)) {
0476: if (jsfForm.isRenderedNode(node)) {
0477: return true;
0478: }
0479:
0480: // if (webform.getManager().isInlineEditing()) {
0481: if (jsfForm.isInlineEditing()) {
0482: // In inline editing mode we'return modifying an already rendered
0483: // fragment. It is not marked rendered since in terms of source mapping
0484: // it's serving as a source dom, returned from FacesPageUnit's render
0485: // operations etc.
0486: return true;
0487: }
0488:
0489: return false;
0490: }
0491:
0492: /** Any more inline content on this line? */
0493: private static boolean haveMoreInlineContent(Node node) {
0494: while (node != null) {
0495: if (node instanceof Text) {
0496: return true;
0497: } else if (node instanceof Element) {
0498: Element element = (Element) node;
0499: HtmlTag tag = HtmlTag.getTag(element.getTagName());
0500:
0501: if (tag == HtmlTag.BR) {
0502: return true;
0503: }
0504:
0505: // Value display = CssLookup.getValue(element, XhtmlCss.DISPLAY_INDEX);
0506: CssValue cssDisplay = CssProvider.getEngineService()
0507: .getComputedValueForElement(element,
0508: XhtmlCss.DISPLAY_INDEX);
0509:
0510: // if (ContainerBox.isInlineTag(cssDisplay, element, tag)) {
0511: if (CssProvider.getValueService().isInlineTag(
0512: cssDisplay, element, tag)) {
0513: return true;
0514: }
0515: }
0516:
0517: node = node.getNextSibling();
0518: }
0519:
0520: return false;
0521: }
0522:
0523: /** Insert a newline at the given position: if we're inside a list this
0524: * means to add a new list item, otherwise we add a <br> (or two, in
0525: * a few scenarios.)
0526: */
0527: private void insertNewline(/*DesignerCaret caret,*/Node node,
0528: int offset) {
0529: org.w3c.dom.Text text = null;
0530: Node parent = null;
0531: Node next = null;
0532:
0533: if ((node.getNodeType() == Node.TEXT_NODE)
0534: || (node.getNodeType() == Node.CDATA_SECTION_NODE)) {
0535: text = (org.w3c.dom.Text) node;
0536: next = text.getNextSibling();
0537: parent = node.getParentNode();
0538: } else {
0539: parent = node;
0540:
0541: NodeList list = node.getChildNodes();
0542: int len = list.getLength();
0543:
0544: if ((len == 0) || (offset >= len)) {
0545: // We have a 0 index but no children, e.g. we're
0546: // inside an empty element.
0547: // XXX Can we do anything here?
0548: next = null;
0549: } else if (offset < len) {
0550: next = list.item(offset);
0551: }
0552: }
0553:
0554: // Inserted newline: should split string and insert a
0555: // <br/> (unless we're inside a list, in that case create
0556: // a new bullet)
0557: // Element list = DesignerUtils.getListItemParent(node);
0558: Element list = getListItemParent(node);
0559:
0560: if (list != null) {
0561: // XXX TODO get rid of using xhtml directly,
0562: // it should be shielded by api.
0563: Element li = createElement(
0564: org.netbeans.modules.visualweb.xhtml.Li.class
0565: .getName(), list.getParentNode(), list
0566: .getNextSibling());
0567: // DocumentRange dom = (DocumentRange)webform.getJspDom();
0568: DocumentRange dom = (DocumentRange) jsfForm.getJspDom();
0569:
0570: org.w3c.dom.ranges.Range domRange = dom.createRange();
0571: domRange.setStart(node, offset);
0572:
0573: // Locate end of the current list item
0574: // Position listItemEnd = Position.create(list, true);
0575: DomPosition listItemEnd = createNextDomPosition(list, true);
0576: domRange.setEnd(listItemEnd.getNode(), listItemEnd
0577: .getOffset());
0578:
0579: DocumentFragment df = domRange.extractContents();
0580: domRange.detach();
0581:
0582: NodeList nl = df.getChildNodes();
0583:
0584: if ((nl.getLength() > 0)
0585: && nl.item(0) instanceof Element
0586: && ((Element) nl.item(0)).getTagName().equals(
0587: HtmlTag.LI.name)) {
0588: nl = nl.item(0).getChildNodes();
0589: }
0590:
0591: for (int ch = 0, len = nl.getLength(); ch < len; ch++) {
0592: Node n = nl.item(ch);
0593:
0594: if (n == null) {
0595: continue;
0596: }
0597:
0598: if (((n.getNodeType() == Node.TEXT_NODE) || (n
0599: .getNodeType() == Node.CDATA_SECTION_NODE))
0600: && JsfSupportUtilities.onlyWhitespace(n
0601: .getNodeValue())) {
0602: continue;
0603: }
0604:
0605: li.appendChild(n);
0606: }
0607:
0608: if (li.getChildNodes().getLength() == 0) {
0609: // XXX TODO get rid of using xhtml directly,
0610: // it should be shielded by api.
0611: createElement(
0612: org.netbeans.modules.visualweb.xhtml.Br.class
0613: .getName(), li, null);
0614: }
0615:
0616: // It's possible that we've moved EVERYTHING from the current item
0617: // in which case we need to put a <br> in there.
0618: if (node.getChildNodes().getLength() == 0) {
0619: // XXX TODO get rid of using xhtml directly,
0620: // it should be shielded by api.
0621: createElement(
0622: org.netbeans.modules.visualweb.xhtml.Br.class
0623: .getName(), node, null);
0624: }
0625:
0626: // caret.setDot(new Position(li, 0, Bias.FORWARD));
0627: fireInsertUpdate(new DefaultDomDocumentEvent(this ,
0628: createDomPosition(li, 0, Bias.FORWARD)));
0629: } else {
0630: // TODO - if the offset is 0, or end, we don't have
0631: // to split!
0632: Element br;
0633:
0634: if ((text == null) || (offset == text.getLength())) {
0635: // Insert after our (possibly text-)node
0636: // null for next is okay - will be
0637: // appended to the end of the list
0638: boolean isLastInline = !haveMoreInlineContent(next);
0639: boolean after = true;
0640: // XXX TODO get rid of using xhtml directly,
0641: // it should be shielded by api.
0642: br = createElement(
0643: org.netbeans.modules.visualweb.xhtml.Br.class
0644: .getName(), parent, next);
0645:
0646: // We may have to insert an additional <br> here.
0647: // Let's say you have this: "<p>Hello^</p>" and you
0648: // press Return. If we just insert a <br/> you get
0649: // "<p>Hello<br/>^</p>" which is still only a single line;
0650: // but the user is expecting to see a new blank line
0651: // to edit: "<p>Hello<br/>^<br/></p>". Of course we
0652: // can't blindly insert one; we have to know that
0653: // there aren't any other inline tags following the
0654: // br in line context; e.g. if we press return here:
0655: // "<p>Hello^<span>foo</span></p>" we should end up with
0656: // "<p>Hello<br/>^<span>foo</span></p>".
0657: if (isLastInline) {
0658: // XXX TODO get rid of using xhtml directly,
0659: // it should be shielded by api.
0660: br = createElement(
0661: org.netbeans.modules.visualweb.xhtml.Br.class
0662: .getName(), parent, next);
0663: after = false;
0664: }
0665:
0666: if (next instanceof Element) {
0667: // caret.setDot(Position.create((Element)next, false));
0668: fireInsertUpdate(new DefaultDomDocumentEvent(
0669: this ,
0670: createNextDomPosition((Element) next, false)));
0671: } else {
0672: // caret.setDot(Position.create(br, after));
0673: fireInsertUpdate(new DefaultDomDocumentEvent(this ,
0674: createNextDomPosition(br, after)));
0675: }
0676: } else if (offset == 0) {
0677: // Insert before our text node
0678: // XXX TODO get rid of using xhtml directly,
0679: // it should be shielded by api.
0680: br = createElement(
0681: org.netbeans.modules.visualweb.xhtml.Br.class
0682: .getName(), parent, text);
0683:
0684: // caret.setDot(new Position(text, 0, Bias.FORWARD));
0685: fireInsertUpdate(new DefaultDomDocumentEvent(this ,
0686: createDomPosition(text, 0, Bias.FORWARD)));
0687: } else {
0688: // Insert in the middle of the text node; split it
0689: org.w3c.dom.Text secondHalf = text.splitText(offset);
0690: // XXX TODO get rid of using xhtml directly,
0691: // it should be shielded by api.
0692: br = createElement(
0693: org.netbeans.modules.visualweb.xhtml.Br.class
0694: .getName(), text.getParentNode(),
0695: secondHalf);
0696:
0697: if (JsfSupportUtilities.onlyWhitespace(secondHalf
0698: .getNodeValue())) {
0699: boolean isLastInline = true;
0700:
0701: if (secondHalf.getNextSibling() != null) {
0702: isLastInline = !haveMoreInlineContent(secondHalf
0703: .getNextSibling());
0704: }
0705:
0706: if (isLastInline) {
0707: // XXX TODO get rid of using xhtml directly,
0708: // it should be shielded by api.
0709: br = createElement(
0710: org.netbeans.modules.visualweb.xhtml.Br.class
0711: .getName(), text
0712: .getParentNode(), secondHalf
0713: .getNextSibling());
0714:
0715: // caret.setDot(Position.create(br, false));
0716: fireInsertUpdate(new DefaultDomDocumentEvent(
0717: this , createNextDomPosition(br, false)));
0718:
0719: return;
0720: }
0721: }
0722:
0723: //caret.setDot(Position.create(br, true));
0724: // caret.setDot(new Position(secondHalf, 0, Bias.FORWARD));
0725: fireInsertUpdate(new DefaultDomDocumentEvent(this ,
0726: createDomPosition(secondHalf, 0, Bias.FORWARD)));
0727: }
0728: }
0729: }
0730:
0731: // XXX Moved from DesignerUtils.
0732: /** For the given node, locate a parent list item element, or return
0733: * null if no such parent is found.
0734: */
0735: private static Element getListItemParent(Node node) {
0736: while (node != null) {
0737: if (node.getNodeType() == Node.ELEMENT_NODE) {
0738: Element element = (Element) node;
0739:
0740: if (element.getTagName().equals(HtmlTag.LI.name)) {
0741: return element;
0742: }
0743: }
0744:
0745: node = node.getParentNode();
0746: }
0747:
0748: return null;
0749: }
0750:
0751: private void insertSpace(/*DesignerCaret caret,*/Node node,
0752: int offset) {
0753: org.w3c.dom.Text text = null;
0754: Node parent = null;
0755: Node next = null;
0756: String str = " ";
0757:
0758: if ((node.getNodeType() == Node.TEXT_NODE)
0759: || (node.getNodeType() == Node.CDATA_SECTION_NODE)) {
0760: text = (org.w3c.dom.Text) node;
0761: } else {
0762: parent = node;
0763:
0764: NodeList list = node.getChildNodes();
0765: int len = list.getLength();
0766:
0767: if ((len == 0) || (offset >= len)) {
0768: // We have a 0 index but no children, e.g. we're
0769: // inside an empty element.
0770: // XXX Can we do anything here?
0771: next = null;
0772: } else if (offset < len) {
0773: next = list.item(offset);
0774: }
0775:
0776: // org.w3c.dom.Document dom = webform.getJspDom();
0777: org.w3c.dom.Document dom = jsfForm.getJspDom();
0778:
0779: text = dom.createTextNode(str);
0780:
0781: // if (((RaveRenderNode)node).isJspx()) {
0782: if (MarkupService.isJspxNode(node)) {
0783: MarkupService.markJspxSource(text);
0784: }
0785:
0786: parent.insertBefore(text, next);
0787:
0788: // caret.setDot(new Position(text, str.length(), Bias.FORWARD));
0789: fireInsertUpdate(new DefaultDomDocumentEvent(this ,
0790: createDomPosition(text, str.length(), Bias.FORWARD)));
0791:
0792: return;
0793: }
0794:
0795: // Special handling for spaces! If the user hits the space
0796: // bar multiple times, html will simply compress the spaces
0797: // to a single character. So we have to convert this to
0798: // a . However, we don't want ALL spaces to become
0799: // since "nbsp" stands for "non breaking space" -
0800: // this would totally break word wrapping - so we only
0801: // convert the second and subsequent character in the
0802: // sequence.
0803: // But even that's not enough. We want the nonbreaking spaces
0804: // to be located with the PREVIOUS word, not the next word,
0805: // so we have to do a little magic.
0806: // In particular (^ denotes caret/insert location for space):
0807: // "foo^bar" -> "foo bar"
0808: // "foo ^bar" -> "foo bar"
0809: // "foo ^bar" -> "foo bar"
0810: // "foo ^bar" -> "foo bar"
0811: // "foo ^ bar" -> "foo ^ bar"
0812: // Algorithm:
0813: // if the character before the caret is a space
0814: // then insert an NBSP -before- it
0815: // else if the character after the caret is a space
0816: // then insert an NBSP
0817: // else insert a space
0818: String data = text.getData();
0819: int len = text.getLength();
0820: assert offset <= len;
0821:
0822: boolean before = (offset > 0)
0823: && (data.charAt(offset - 1) == ' ');
0824: boolean after = (offset < len) && (data.charAt(offset) == ' ');
0825: Node targetNode = node; // Node to move caret to when we're done
0826: int targetOffset = offset;
0827:
0828: if (before || after) {
0829: if (before) {
0830: offset--;
0831: }
0832:
0833: //final String NBSP_STRING = "\u00A0";
0834: final String NBSP_STRING;
0835:
0836: // XXX #115195 This is not OK for inline editing.
0837: if (!jsfForm.isInlineEditing()) {
0838: // if (((RaveRenderNode)node).isJspx()) {
0839: if (MarkupService.isJspxNode(node)) {
0840: NBSP_STRING = " "; // JSPX source is "escaped"
0841: } else { // html - put it right into source. Should I try to insert
0842:
0843: // an entity reference here instead? Might not serialize well.
0844: // Make sure AttributeInlineEditor checks for this!
0845: NBSP_STRING = "\u00A0";
0846: }
0847:
0848: str = NBSP_STRING;
0849: }
0850:
0851: text.insertData(offset, str);
0852: targetNode = text;
0853: targetOffset += str.length();
0854:
0855: // Insert an entity instead
0856:
0857: /*
0858: // XXX No, that doesn't work right. The parser seems to
0859: // convert entities into character data, and not do the
0860: // reverse translation, so this doesn't buy us anything.
0861: EntityReference er = webform.getDom().createEntityReference("nbsp");
0862: if (offset == 0) {
0863: // Insert before our text node
0864: text.getParentNode().insertBefore(er, text);
0865: targetNode = text;
0866: targetOffset = 1;
0867: } else if (offset == text.getLength()) {
0868: // Insert after our text node
0869: // null for text.getNextSibling() is okay - will be
0870: // appended to the end of the list
0871: text.getParentNode().insertBefore(er, text.getNextSibling());
0872: targetNode = text;
0873: targetOffset += str.length();
0874: } else {
0875: // Insert in the middle of the text node; split it
0876: org.w3c.dom.Text secondHalf = text.splitText(offset);
0877: text.getParentNode().insertBefore(er, secondHalf);
0878: targetNode = secondHalf;
0879: targetOffset = 0;
0880: }
0881: */
0882: } else {
0883: text.insertData(offset, str);
0884: targetNode = text;
0885: targetOffset += str.length();
0886: }
0887:
0888: // XXX check that this works on Windows too - or do they
0889: // use \r\n ?
0890: // caret.setDot(new Position(targetNode, targetOffset, Bias.FORWARD));
0891: fireInsertUpdate(new DefaultDomDocumentEvent(this ,
0892: createDomPosition(targetNode, targetOffset,
0893: Bias.FORWARD)));
0894: }
0895:
0896: // /** XXX Copy also in insync/FacesDnDSupport
0897: // * Create a new bean of the given type, positioned below parent
0898: // * before the given node. Returns the created element. */
0899: // private DesignBean createBean(String className, Node parent, Node before) {
0900: //// MarkupPosition pos = new MarkupPosition(parent, before);
0901: //// DesignBean parentBean = /*FacesSupport.*/Util.findParentBean(parent);
0902: //// LiveUnit unit = webform.getModel().getLiveUnit();
0903: //// DesignBean bean = unit.createBean(className, parentBean, pos);
0904: ////
0905: //// return bean;
0906: // return webform.createBean(className, parent, before);
0907: // }
0908:
0909: // /** XXX Copy also in insync/FacesDnDSupport.
0910: // * Given a node, return the nearest DesignBean that "contains" it */
0911: // private static DesignBean findParentBean(Node node) {
0912: // while (node != null) {
0913: //// if (node instanceof RaveElement) {
0914: //// RaveElement element = (RaveElement)node;
0915: // if (node instanceof Element) {
0916: // Element element = (Element)node;
0917: //
0918: //// if (element.getDesignBean() != null) {
0919: //// return element.getDesignBean();
0920: //// }
0921: //// MarkupDesignBean markupDesignBean = InSyncService.getProvider().getMarkupDesignBeanForElement(element);
0922: // MarkupDesignBean markupDesignBean = WebForm.getDomProviderService().getMarkupDesignBeanForElement(element);
0923: // if (markupDesignBean != null) {
0924: // return markupDesignBean;
0925: // }
0926: // }
0927: //
0928: // node = node.getParentNode();
0929: // }
0930: //
0931: // return null;
0932: // }
0933:
0934: /** Create a new element of the given type, positioned below parent
0935: * before the given node. Returns the created element. */
0936: private/*public*/Element createElement(String className,
0937: Node parent, Node before) {
0938: // XXX TODO Pass in the tag name too. If we're editing in a DocumentFragment
0939: // (e.g. inline editing) create elements directly rather than going
0940: // through the designtime API.
0941: // DesignBean bean = createBean(className, parent, before);
0942: // DesignBean bean = webform.createBean(className, parent, before);
0943: // return webform.createComponent(className, parent, before);
0944: return jsfForm.createComponent(className, parent, before);
0945:
0946: // if (bean == null) {
0947: // return null;
0948: // }
0949:
0950: // return FacesSupport.getMarkupBean(bean).getElement();
0951: // return Util.getMarkupBean(bean).getElement();
0952: // return WebForm.getDomProviderService().getMarkupBeanElement(bean);
0953: }
0954:
0955: // XXX Moved form DomRangeImpl.
0956: /** Delete all the JSF components found in the given range */
0957: // private void deleteComponents() {
0958: private void deleteComponents(DomPosition first, DomPosition second) {
0959: // This will require a traversal, but probably not using the
0960: // DomTraversal class since we'll be deleting elements as
0961: // we're traversing
0962: // Position second = getLastPosition();
0963: // DomPosition second = getLastPosition();
0964:
0965: // if (second == Position.NONE) {
0966: if (second == DomPosition.NONE) {
0967: return;
0968: }
0969:
0970: // Position first = getFirstPosition();
0971: // DomPosition first = getFirstPosition();
0972: // assert first.isEarlierThan(first);
0973:
0974: Node firstNode = first.getNode();
0975:
0976: if (firstNode instanceof Element) {
0977: if (first.getOffset() < firstNode.getChildNodes()
0978: .getLength()) {
0979: firstNode = firstNode.getChildNodes().item(
0980: first.getOffset());
0981: }
0982: }
0983:
0984: Node secondNode = second.getNode();
0985:
0986: if (first.equals(second)) {
0987: secondNode = firstNode;
0988: } else if (secondNode instanceof Element) {
0989: if ((second.getOffset() > 0)
0990: && (second.getOffset() <= secondNode
0991: .getChildNodes().getLength())) {
0992: secondNode = secondNode.getChildNodes().item(
0993: second.getOffset() - 1);
0994: } else if (second.getOffset() == 0) {
0995: // Gotta locate immediate inorder traversal neighbor to the left
0996: while ((secondNode != null)
0997: && (secondNode.getPreviousSibling() == null)) {
0998: secondNode = secondNode.getParentNode();
0999: }
1000:
1001: if (secondNode == null) {
1002: ErrorManager.getDefault().log(
1003: "Unexpected second position " + second); // NOI18N
1004:
1005: return;
1006: }
1007:
1008: secondNode = secondNode.getPreviousSibling();
1009:
1010: while (true) {
1011: NodeList nl = secondNode.getChildNodes();
1012:
1013: if (nl.getLength() > 0) {
1014: secondNode = nl.item(nl.getLength() - 1);
1015: } else {
1016: break;
1017: }
1018: }
1019: }
1020: }
1021:
1022: // Insert content for the first node
1023: if ((firstNode == secondNode) && firstNode instanceof Text) {
1024: // Common case - and we're done; no components to be deleted here
1025: return;
1026: }
1027:
1028: // Iterate over the range building up all the DesignBeans to be
1029: // destroyed
1030: // ArrayList beans = new ArrayList();
1031: List<Element> components = new ArrayList<Element>();
1032:
1033: // org.w3c.dom.Document dom = webform.getJspDom();
1034: org.w3c.dom.Document dom = jsfForm.getJspDom();
1035:
1036: if (!(dom instanceof DocumentTraversal)) {
1037: return;
1038: }
1039:
1040: DocumentTraversal trav = (DocumentTraversal) dom;
1041:
1042: // Iterating over all since we can't just limit ourselves to text nodes
1043: // in case the target node is not necessarily a text node!
1044: NodeIterator iterator = trav.createNodeIterator(dom,
1045: NodeFilter.SHOW_ALL, null, false);
1046:
1047: // The node iterator doesn't seem to have a way to jump to a
1048: // particular node, so we search for it ourselves
1049: Node curr = firstNode;
1050:
1051: while (curr != null) {
1052: try {
1053: curr = iterator.nextNode();
1054:
1055: if (curr == firstNode) {
1056: break;
1057: }
1058: } catch (DOMException ex) {
1059: ErrorManager.getDefault().notify(
1060: ErrorManager.INFORMATIONAL, ex);
1061:
1062: break;
1063: }
1064: }
1065:
1066: Node last = secondNode;
1067:
1068: while (curr != null) {
1069: // if (curr instanceof RaveElement) {
1070: // RaveElement element = (RaveElement)curr;
1071: if (curr instanceof Element) {
1072: Element element = (Element) curr;
1073: // DesignBean bean = element.getDesignBean();
1074: // DesignBean bean = InSyncService.getProvider().getMarkupDesignBeanForElement(element);
1075: // DesignBean bean = WebForm.getDomProviderService().getMarkupDesignBeanForElement(element);
1076: Element componentRootElement = MarkupService
1077: .getRenderedElementForElement(element);
1078:
1079: // if ((bean != null) &&
1080: if ((componentRootElement != null)
1081: && ((element.getParentNode() == null) ||
1082: // (element.getParentNode() instanceof RaveElement &&
1083: // (((RaveElement)element.getParentNode()).getDesignBean() != bean)))) {
1084: (element.getParentNode() instanceof Element
1085: // && InSyncService.getProvider().getMarkupDesignBeanForElement((Element)element.getParentNode()) != bean))) {
1086: // && WebForm.getDomProviderService().getMarkupDesignBeanForElement((Element)element.getParentNode()) != bean))) {
1087: && MarkupService
1088: .getRenderedElementForElement((Element) element
1089: .getParentNode()) != componentRootElement))) {
1090: // if (!beans.contains(bean)) {
1091: // beans.add(bean);
1092: // }
1093: if (!components.contains(componentRootElement)) {
1094: components.add(componentRootElement);
1095: }
1096: }
1097: }
1098:
1099: if ((curr == null) || (curr == last)) {
1100: break;
1101: }
1102:
1103: try {
1104: curr = iterator.nextNode();
1105: } catch (DOMException ex) {
1106: ErrorManager.getDefault().notify(ex);
1107:
1108: break;
1109: }
1110: }
1111:
1112: iterator.detach();
1113:
1114: // FacesModel model = webform.getModel();
1115: // Document doc = webform.getDocument();
1116:
1117: //// UndoEvent undoEvent = webform.getModel().writeLock(NbBundle.getMessage(DeleteNextCharAction.class, "DeleteText")); // NOI18N
1118: //// DomProvider.WriteLock writeLock = webform.writeLock(NbBundle.getMessage(DeleteNextCharAction.class, "DeleteText")); // NOI18N
1119: // DomProvider.WriteLock writeLock = jsfForm.writeLock(NbBundle.getMessage(DomDocumentImpl.class, "LBL_DeleteText")); // NOI18N
1120: // try {
1121: //// doc.writeLock(NbBundle.getMessage(DeleteNextCharAction.class, "DeleteText")); // NOI18N
1122: //
1123: //// for (int i = 0; i < beans.size(); i++) {
1124: //// DesignBean bean = (DesignBean)beans.get(i);
1125: // for (Element componentRootElement : components) {
1126: //
1127: //// if (!FacesSupport.isSpecialBean(/*webform, */bean)) {
1128: //// if (!Util.isSpecialBean(bean)) {
1129: //// if (bean instanceof MarkupDesignBean && !WebForm.getDomProviderService().isSpecialComponent(
1130: //// WebForm.getDomProviderService().getComponentRootElementForMarkupDesignBean((MarkupDesignBean)bean))) {
1131: //// if (!WebForm.getDomProviderService().isSpecialComponent(componentRootElement)) {
1132: // if (!JsfSupportUtilities.isSpecialComponent(componentRootElement)) {
1133: //// model.getLiveUnit().deleteBean(bean);
1134: //// webform.deleteBean(bean);
1135: //// webform.deleteComponent(componentRootElement);
1136: // jsfForm.deleteComponent(componentRootElement);
1137: // }
1138: // }
1139: // } finally {
1140: //// doc.writeUnlock();
1141: //// webform.getModel().writeUnlock(undoEvent);
1142: //// webform.writeUnlock(writeLock);
1143: // jsfForm.writeUnlock(writeLock);
1144: // }
1145: deleteComponents(components.toArray(new Element[components
1146: .size()]));
1147: }
1148:
1149: /** Return the text in the range (linearized to a String); this is only the
1150: * text nodes, not comment nodes, not markup, etc.
1151: */
1152: private String getText(DomPosition first, DomPosition second) {
1153: // Since we'll be iterating forwards, gotta make sure we know
1154: // which point is first
1155: // Position second = getLastPosition();
1156: // DomPosition second = getLastPosition();
1157:
1158: // if (second == Position.NONE) {
1159: if (second == DomPosition.NONE) {
1160: return "";
1161: }
1162:
1163: // Position first = getFirstPosition();
1164: // DomPosition first = getFirstPosition();
1165: // assert first.isEarlierThan(first);
1166:
1167: StringBuffer sb = new StringBuffer();
1168:
1169: Node firstNode = first.getNode();
1170:
1171: if (firstNode instanceof Element) {
1172: if (first.getOffset() < firstNode.getChildNodes()
1173: .getLength()) {
1174: firstNode = firstNode.getChildNodes().item(
1175: first.getOffset());
1176: }
1177: }
1178:
1179: Node secondNode = second.getNode();
1180:
1181: if (first.equals(second)) {
1182: secondNode = firstNode;
1183: } else if (secondNode instanceof Element) {
1184: if ((second.getOffset() > 0)
1185: && (second.getOffset() <= secondNode
1186: .getChildNodes().getLength())) {
1187: secondNode = secondNode.getChildNodes().item(
1188: second.getOffset() - 1);
1189: } else if (second.getOffset() == 0) {
1190: // Gotta locate immediate inorder traversal neighbor to the left
1191: while ((secondNode != null)
1192: && (secondNode.getPreviousSibling() == null)) {
1193: secondNode = secondNode.getParentNode();
1194: }
1195:
1196: if (secondNode == null) {
1197: ErrorManager.getDefault().log(
1198: "Unexpected second position " + second); // NOI18N
1199:
1200: return "";
1201: }
1202:
1203: secondNode = secondNode.getPreviousSibling();
1204:
1205: while (true) {
1206: NodeList nl = secondNode.getChildNodes();
1207:
1208: if (nl.getLength() > 0) {
1209: secondNode = nl.item(nl.getLength() - 1);
1210: } else {
1211: break;
1212: }
1213: }
1214: }
1215: }
1216:
1217: // Insert content for the first node
1218: if (firstNode instanceof Text) {
1219: if (secondNode == firstNode) {
1220: String s = firstNode.getNodeValue();
1221:
1222: for (int i = first.getOffset(); i < second.getOffset(); i++) {
1223: sb.append(s.charAt(i));
1224: }
1225:
1226: return sb.toString();
1227: } else {
1228: String s = firstNode.getNodeValue();
1229:
1230: for (int i = first.getOffset(), n = s.length(); i < n; i++) {
1231: sb.append(s.charAt(i));
1232: }
1233: }
1234: }
1235:
1236: // Append content for all the nodes between first and second
1237: // org.w3c.dom.Document dom = webform.getJspDom();
1238: org.w3c.dom.Document dom = jsfForm.getJspDom();
1239:
1240: if (!(dom instanceof DocumentTraversal)) {
1241: return "";
1242: }
1243:
1244: DocumentTraversal trav = (DocumentTraversal) dom;
1245:
1246: // Iterating over all since we can't just limit ourselves to text nodes
1247: // in case the target node is not necessarily a text node!
1248: NodeIterator iterator = trav.createNodeIterator(dom,
1249: NodeFilter.SHOW_ALL, null, false);
1250: Node curr = firstNode;
1251:
1252: // The node iterator doesn't seem to have a way to jump to a particular node,
1253: // so we search for it ourselves
1254: while (curr != null) {
1255: try {
1256: curr = iterator.nextNode();
1257:
1258: if (curr == firstNode) {
1259: break;
1260: }
1261: } catch (DOMException ex) {
1262: ErrorManager.getDefault().notify(ex);
1263:
1264: break;
1265: }
1266: }
1267:
1268: Node last = secondNode;
1269:
1270: while (curr != null) {
1271: try {
1272: curr = iterator.nextNode();
1273: } catch (DOMException ex) {
1274: ErrorManager.getDefault().notify(ex);
1275:
1276: break;
1277: }
1278:
1279: if ((curr == null) || (curr == last)) {
1280: break;
1281: }
1282:
1283: if (curr instanceof Text) {
1284: sb.append(curr.getNodeValue());
1285: }
1286: }
1287:
1288: iterator.detach();
1289:
1290: // Append content for the last node
1291: if (secondNode instanceof Text) {
1292: String s = secondNode.getNodeValue();
1293:
1294: for (int i = 0; i < second.getOffset(); i++) {
1295: sb.append(s.charAt(i));
1296: }
1297: }
1298:
1299: return sb.toString();
1300: }
1301:
1302: // XXX Moved to GridHandler.
1303: // /** Transfer the given element such that it's parented at the given position */
1304: // public boolean reparent(DesignBean bean, Element element, Position pos) {
1305: // if (pos == Position.NONE) {
1306: // return false;
1307: // }
1308: //
1309: // // First see where it's currently located
1310: // Position currPos = Position.create(element, false);
1311: //
1312: // if (pos.equals(currPos)) {
1313: // return true; // Already in the right place - done
1314: // }
1315: //
1316: //// if (pos.isRendered()) {
1317: // if (MarkupService.isRenderedNode(pos.getNode())) {
1318: // pos = pos.getSourcePosition();
1319: // }
1320: //
1321: // if (pos == Position.NONE) {
1322: // return false;
1323: // }
1324: //
1325: // Node node = pos.getNode();
1326: //
1327: // // Ensure the node is not in a DocumentFragment - if it is, moving
1328: // // an element here is going to remove it from the jsp!!
1329: // Node curr = node;
1330: //
1331: // while (curr.getParentNode() != null) {
1332: // curr = curr.getParentNode();
1333: // }
1334: //
1335: // //if (curr instanceof DocumentFragment) {
1336: // if (curr != webform.getJspDom()) {
1337: // return false;
1338: // }
1339: //
1340: // Node parentNode = node;
1341: // Node before = null;
1342: //
1343: // if (node instanceof Text) {
1344: // parentNode = node.getParentNode();
1345: //
1346: // if (pos.getOffset() == 0) {
1347: // before = node;
1348: // } else {
1349: // Text txt = (Text)node;
1350: //
1351: // if (pos.getOffset() < txt.getLength()) {
1352: // before = txt.splitText(pos.getOffset());
1353: // } else {
1354: // // Ugh, what if it's the last node here??
1355: // // XXX won't work right!
1356: // before = txt.getNextSibling();
1357: // }
1358: // }
1359: // } else {
1360: // before = parentNode.getFirstChild();
1361: //
1362: // for (int i = 0, n = pos.getOffset(); i < n; i++) {
1363: // if (before == null) {
1364: // break;
1365: // }
1366: //
1367: // before = before.getNextSibling();
1368: // }
1369: // }
1370: //
1371: // if (before == element) {
1372: // return true;
1373: // }
1374: //
1375: //// LiveUnit lu = webform.getModel().getLiveUnit();
1376: //// MarkupPosition markupPos = new MarkupPosition(parentNode, before);
1377: //// DesignBean parentBean = null;
1378: //// Node e = parentNode;
1379: ////
1380: //// while (e != null) {
1381: ////// if (e instanceof RaveElement) {
1382: ////// parentBean = ((RaveElement)e).getDesignBean();
1383: //// if (e instanceof Element) {
1384: ////// parentBean = InSyncService.getProvider().getMarkupDesignBeanForElement((Element)e);
1385: //// parentBean = WebForm.getDomProviderService().getMarkupDesignBeanForElement((Element)e);
1386: ////
1387: //// if (parentBean != null) {
1388: //// break;
1389: //// }
1390: //// }
1391: ////
1392: //// e = e.getParentNode();
1393: //// }
1394: ////
1395: //// if (bean == parentBean) {
1396: //// return false;
1397: //// }
1398: ////
1399: //// boolean success = lu.moveBean(bean, parentBean, markupPos);
1400: // boolean success = webform.moveBean(bean, parentNode, before);
1401: //
1402: // if (webform.getPane().getCaret() != null) {
1403: // pos = ModelViewMapper.getFirstDocumentPosition(webform, false);
1404: // webform.getPane().getCaret().setDot(pos);
1405: // }
1406: //
1407: // return success;
1408: // }
1409:
1410: // /**
1411: // * Acquires a lock to begin mutating the document this lock
1412: // * protects. There can be no writing, notification of changes, or
1413: // * reading going on in order to gain the lock. Additionally a thread is
1414: // * allowed to gain more than one <code>writeLock</code>,
1415: // * as long as it doesn't attempt to gain additional <code>writeLock</code>s
1416: // * from within document notification.
1417: // * @param description Description of the task being initiated
1418: // */
1419: // public final synchronized void writeLock(String description) {
1420: // undoEvent = webform.getModel().writeLock(description);
1421: // }
1422: //
1423: // /**
1424: // * Releases a write lock previously obtained via <code>writeLock</code>.
1425: // * After decrementing the lock count if there are no oustanding locks
1426: // * this will allow a new writer, or readers.
1427: // *
1428: // * @see #writeLock
1429: // */
1430: // public final synchronized void writeUnlock() {
1431: // webform.getModel().writeUnlock(undoEvent);
1432: // undoEvent = null;
1433: // }
1434:
1435: // /**
1436: // * Acquires a lock to begin reading some state from the
1437: // * document. There can be multiple readers at the same time.
1438: // * Writing blocks the readers until notification of the change
1439: // * to the listeners has been completed. This method should
1440: // * be used very carefully to avoid unintended compromise
1441: // * of the document. It should always be balanced with a
1442: // * <code>readUnlock</code>.
1443: // *
1444: // * @todo Consider making this API protected
1445: // * @see #readUnlock
1446: // */
1447: // public final synchronized void readLock() {
1448: // webform.getMarkup().readLock();
1449: // }
1450: //
1451: // /**
1452: // * Does a read unlock. This signals that one
1453: // * of the readers is done. If there are no more readers
1454: // * then writing can begin again. This should be balanced
1455: // * with a readLock, and should occur in a finally statement
1456: // * so that the balance is guaranteed. The following is an
1457: // * example.
1458: // * <pre><code>
1459: // * readLock();
1460: // * try {
1461: // * // do something
1462: // * } finally {
1463: // * readUnlock();
1464: // * }
1465: // * </code></pre>
1466: // *
1467: // * @todo Consider making this API protected
1468: // * @see #readLock
1469: // */
1470: // public final synchronized void readUnlock() {
1471: // webform.getMarkup().readUnlock();
1472: // }
1473:
1474: // XXX Moved to WebForm.isGridModeDocument.
1475: // // XXX Also in insync/FacesDnDSupport
1476: // /**
1477: // * Return true if this document is in "grid mode" (objects
1478: // * should be positioned by absolute coordinates instead of in
1479: // * "flow" order.
1480: // *
1481: // * @return true iff the document should be in grid mode
1482: // */
1483: // public boolean isGridMode() {
1484: // Element b = webform.getHtmlBody();
1485: //
1486: // if (b == null) {
1487: // return false;
1488: // }
1489: //
1490: //// Value val = CssLookup.getValue(b, XhtmlCss.RAVELAYOUT_INDEX);
1491: // CssValue cssValue = CssProvider.getEngineService().getComputedValueForElement(b, XhtmlCss.RAVELAYOUT_INDEX);
1492: //
1493: //// return val == CssValueConstants.GRID_VALUE;
1494: // return CssProvider.getValueService().isGridValue(cssValue);
1495: // }
1496:
1497: // public Element findComponent(String id) {
1498: // // Hack for now
1499: // return findElement(webform.getHtmlBody(), id);
1500: // }
1501: //
1502: // public Element findElement(String id) {
1503: // // Hack for now
1504: // return findElement(webform.getHtmlBody(), id);
1505: // }
1506: //
1507: // private Element findElement(Element element, String id) {
1508: // String eid = element.getAttribute(HtmlAttribute.ID);
1509: //
1510: // if ((eid != null) && (eid.equals(id))) {
1511: // return element;
1512: // }
1513: //
1514: // NodeList list = element.getChildNodes();
1515: // int len = list.getLength();
1516: //
1517: // for (int i = 0; i < len; i++) {
1518: // Node child = list.item(i);
1519: //
1520: // if (child.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
1521: // element = findElement((Element)child, id);
1522: //
1523: // if (element != null) {
1524: // return element;
1525: // }
1526: // }
1527: // }
1528: //
1529: // return null;
1530: // }
1531:
1532: // XXX Moved to InteractionManager.
1533: // /**
1534: // * Report whether the given node is in a read-only region of
1535: // * the document or not.
1536: // */
1537: // public static boolean isReadOnlyRegion(Position pos) {
1538: // Node node = pos.getNode();
1539: //
1540: // // Determine if this node is in a DocumentFragment which means
1541: // // it's read only
1542: // while (node != null) {
1543: // node = node.getParentNode();
1544: //
1545: // if (node instanceof org.w3c.dom.Document) {
1546: // break;
1547: // }
1548: // }
1549: //
1550: // return node == null;
1551: // }
1552:
1553: // >>> Listening support.
1554: // XXX Temporarily here, then after moved with document interface to the API together don't make it nested class.
1555:
1556: private void fireInsertUpdate(DomDocumentEvent evt) {
1557: for (DomDocumentListener l : getDomDocumentListeners()) {
1558: l.insertUpdate(evt);
1559: }
1560: }
1561:
1562: private void fireComponentMoved(DomDocumentEvent evt) {
1563: for (DomDocumentListener l : getDomDocumentListeners()) {
1564: l.componentMoved(evt);
1565: }
1566: }
1567:
1568: private void fireComponentsMoved(DomDocumentEvent evt) {
1569: for (DomDocumentListener l : getDomDocumentListeners()) {
1570: l.componentsMoved(evt);
1571: }
1572: }
1573:
1574: private void fireComponentMovedTo(DomDocumentEvent evt) {
1575: for (DomDocumentListener l : getDomDocumentListeners()) {
1576: l.componentMovedTo(evt);
1577: }
1578: }
1579:
1580: private final EventListenerList listenerList = new EventListenerList();
1581:
1582: public void addDomDocumentListener(DomDocumentListener l) {
1583: listenerList.add(DomDocumentListener.class, l);
1584: }
1585:
1586: public void removeDomDocumentListener(DomDocumentListener l) {
1587: listenerList.remove(DomDocumentListener.class, l);
1588: }
1589:
1590: private DomDocumentListener[] getDomDocumentListeners() {
1591: return listenerList.getListeners(DomDocumentListener.class);
1592: }
1593:
1594: public DomProvider.DomPosition createDomPosition(Node node,
1595: int offset, DomPosition.Bias bias) {
1596: if (node == null) {
1597: return DomPosition.NONE;
1598: }
1599: return DomPositionImpl.create(this , node, offset, bias);
1600: }
1601:
1602: public DomProvider.DomPosition createNextDomPosition(Node node,
1603: boolean after) {
1604: if (node == null) {
1605: return DomPosition.NONE;
1606: }
1607: return DomPositionImpl.createNext(this , node, after);
1608: }
1609:
1610: public DomProvider.DomRange createRange(Node dotNode,
1611: int dotOffset, Node markNode, int markOffset) {
1612: return DomRangeImpl.create(this , dotNode, dotOffset, markNode,
1613: markOffset);
1614: }
1615:
1616: public int compareBoudaryPoints(Node endPointA, int offsetA,
1617: Node endPointB, int offsetB) {
1618: return DomPositionImpl.compareBoundaryPoints(endPointA,
1619: offsetA, endPointB, offsetB);
1620: }
1621:
1622: public DomProvider.DomPosition first(
1623: DomProvider.DomPosition dot,
1624: org.netbeans.modules.visualweb.api.designer.DomProvider.DomPosition mark) {
1625: return DomPositionImpl.first(dot, mark);
1626: }
1627:
1628: public DomProvider.DomPosition last(
1629: DomProvider.DomPosition dot,
1630: org.netbeans.modules.visualweb.api.designer.DomProvider.DomPosition mark) {
1631: return DomPositionImpl.last(dot, mark);
1632: }
1633:
1634: private static class DefaultDomDocumentEvent implements
1635: DomDocumentEvent {
1636: private final DomDocument document;
1637: private final DomPosition position;
1638:
1639: public DefaultDomDocumentEvent(DomDocument document,
1640: DomPosition position) {
1641: this .document = document;
1642: this .position = position;
1643: }
1644:
1645: public DomDocument getDomDocument() {
1646: return document;
1647: }
1648:
1649: public DomPosition getDomPosition() {
1650: return position;
1651: }
1652: } // End of DefaultDomDocumentEvent.
1653:
1654: /** Transfer the given element such that it's parented at the given position */
1655: // private boolean reparent(DesignBean bean, Element element, Position pos, WebForm webform) {
1656: // private boolean reparentComponent(Element componentRootElement, /*Element element,*/ Position pos, WebForm webform) {
1657: private boolean reparentComponent(Element componentRootElement, /*Element element,*/
1658: DomPosition pos /*, WebForm webform*/) {
1659: // if (pos == Position.NONE) {
1660: if (pos == DomPosition.NONE) {
1661: return false;
1662: }
1663:
1664: // First see where it's currently located
1665: // Position currPos = Position.create(element, false);
1666: // Position currPos = Position.create(componentRootElement, false);
1667: // DomPosition currPos = webform.createDomPosition(componentRootElement, false);
1668: DomPosition currPos = createNextDomPosition(
1669: componentRootElement, false);
1670:
1671: if (pos.equals(currPos)) {
1672: return true; // Already in the right place - done
1673: }
1674:
1675: // if (pos.isRendered()) {
1676: // if (MarkupService.isRenderedNode(pos.getNode())) {
1677: if (isRenderedNode(pos.getNode())) {
1678: pos = pos.getSourcePosition();
1679: }
1680:
1681: // if (pos == Position.NONE) {
1682: if (pos == DomPosition.NONE) {
1683: return false;
1684: }
1685:
1686: Node node = pos.getNode();
1687:
1688: // Ensure the node is not in a DocumentFragment - if it is, moving
1689: // an element here is going to remove it from the jsp!!
1690: Node curr = node;
1691:
1692: while (curr.getParentNode() != null) {
1693: curr = curr.getParentNode();
1694: }
1695:
1696: //if (curr instanceof DocumentFragment) {
1697: // if (curr != webform.getJspDom()) {
1698: if (curr != jsfForm.getJspDom()) {
1699: return false;
1700: }
1701:
1702: Node parentNode = node;
1703: Node before = null;
1704:
1705: if (node instanceof Text) {
1706: parentNode = node.getParentNode();
1707:
1708: if (pos.getOffset() == 0) {
1709: before = node;
1710: } else {
1711: Text txt = (Text) node;
1712:
1713: if (pos.getOffset() < txt.getLength()) {
1714: before = txt.splitText(pos.getOffset());
1715: } else {
1716: // Ugh, what if it's the last node here??
1717: // XXX won't work right!
1718: before = txt.getNextSibling();
1719: }
1720: }
1721: } else {
1722: before = parentNode.getFirstChild();
1723:
1724: for (int i = 0, n = pos.getOffset(); i < n; i++) {
1725: if (before == null) {
1726: break;
1727: }
1728:
1729: before = before.getNextSibling();
1730: }
1731: }
1732:
1733: // if (before == element) {
1734: // XXX Comparing rendered with source element can never fit.
1735: if (before == componentRootElement) {
1736: return true;
1737: }
1738:
1739: // LiveUnit lu = webform.getModel().getLiveUnit();
1740: // MarkupPosition markupPos = new MarkupPosition(parentNode, before);
1741: // DesignBean parentBean = null;
1742: // Node e = parentNode;
1743: //
1744: // while (e != null) {
1745: //// if (e instanceof RaveElement) {
1746: //// parentBean = ((RaveElement)e).getDesignBean();
1747: // if (e instanceof Element) {
1748: //// parentBean = InSyncService.getProvider().getMarkupDesignBeanForElement((Element)e);
1749: // parentBean = WebForm.getDomProviderService().getMarkupDesignBeanForElement((Element)e);
1750: //
1751: // if (parentBean != null) {
1752: // break;
1753: // }
1754: // }
1755: //
1756: // e = e.getParentNode();
1757: // }
1758: //
1759: // if (bean == parentBean) {
1760: // return false;
1761: // }
1762: //
1763: // boolean success = lu.moveBean(bean, parentBean, markupPos);
1764: // boolean success = webform.moveComponent(componentRootElement, parentNode, before);
1765: boolean success = jsfForm.moveComponent(componentRootElement,
1766: parentNode, before);
1767:
1768: //// if (webform.getPane().getCaret() != null) {
1769: // if (webform.getPane().hasCaret()) {
1770: // pos = ModelViewMapper.getFirstDocumentPosition(webform, false);
1771: //// webform.getPane().getCaret().setDot(pos);
1772: // webform.getPane().setCaretDot(pos);
1773: // }
1774: fireComponentMoved(new DefaultDomDocumentEvent(this , null));
1775:
1776: return success;
1777: }
1778:
1779: // XXX Moved from designer/../GridHandler
1780: // TODO 1) Refactor, there should be listener on the designer, informing about user actions.
1781: // TODO 2) This is very messy, simplify, devide to more methods.
1782: public void moveComponents(Designer designer, Box[] boxes,
1783: Point[] offsetPoints, DomPosition pos, int newX, int newY,
1784: boolean snapEnabled) {
1785: // Locate a grid layout parent
1786: // Document doc = editor.getDocument();
1787: // WebForm webform = doc.getWebForm();
1788: // WebForm webform = editor.getWebForm();
1789:
1790: // int numMoved = beans.size();
1791: // int numMoved = boxes.size();
1792: int numMoved = boxes.length;
1793:
1794: // Rectangle boundingBox = null;
1795:
1796: String description;
1797: if (numMoved > 1) {
1798: // description = NbBundle.getMessage(GridHandler.class, "MoveComponents");
1799: description = NbBundle.getMessage(DomDocumentImpl.class,
1800: "LBL_MoveComponents");
1801: } else {
1802: description = NbBundle.getMessage(DomDocumentImpl.class,
1803: "LBL_MoveComponent");
1804: }
1805: // UndoEvent undoEvent = webform.getModel().writeLock(description);
1806: // DomProvider.WriteLock writeLock = webform.writeLock(description);
1807: // DomProvider.WriteLock writeLock = jsfForm.writeLock(description);
1808: UndoEvent writeLock = jsfForm.writeLock(description);
1809: try {
1810: // String description;
1811: //
1812: // if (numMoved > 1) {
1813: // description = NbBundle.getMessage(GridHandler.class, "MoveComponents");
1814: // } else {
1815: // description = NbBundle.getMessage(GridHandler.class, "MoveComponent");
1816: // }
1817: //
1818: // doc.writeLock(description);
1819:
1820: // Move the components
1821: for (int i = 0; i < numMoved; i++) {
1822: // MarkupDesignBean bean = beans.get(i);
1823: // Rectangle offset = offsetRectangles.get(i);
1824: // CssBox box = boxes.get(i);
1825: // CssBox box = boxes[i];
1826: Box box = boxes[i];
1827: // Rectangle offset = offsetRectangles[i];
1828: Point offset = offsetPoints[i];
1829:
1830: // Element componentRootElement = CssBox.getElementForComponentRootCssBox(box);
1831: Element componentRootElement = box
1832: .getComponentRootElement();
1833:
1834: // Element e = box.getElement();
1835: //
1836: // if (e == null) {
1837: // e = bean.getElement();
1838: // }
1839:
1840: // int x = newX + offset.x;
1841: // int y = newY + offset.y;
1842: //
1843: // if (!snapDisabled) {
1844: // x = snapX(x, box.getPositionedBy());
1845: // y = snapY(y, box.getPositionedBy());
1846: // }
1847:
1848: int x = newX + offset.x;
1849: int y = newY + offset.y;
1850:
1851: if (snapEnabled) {
1852: x = designer.snapX(x, box.getPositionedBy());
1853: y = designer.snapY(y, box.getPositionedBy());
1854: }
1855:
1856: // CssBox parentBox = box.getParent();
1857: Box parentBox = box.getParent();
1858:
1859: // if (boundingBox == null) {
1860: // boundingBox = new Rectangle(x, y, box.getWidth(), box.getHeight());
1861: // } else {
1862: // boundingBox.add(x, y);
1863: // boundingBox.add(x + box.getWidth(), y + box.getHeight());
1864: // }
1865:
1866: try {
1867: boolean moveSucceeded = true;
1868:
1869: // if ((pos != null) && (pos != Position.NONE)) {
1870: if ((pos != null) && (pos != DomPosition.NONE)) {
1871: // TODO: better batch handling here
1872: // moveSucceeded = doc.reparent(bean, e, pos);
1873: // moveSucceeded = reparentComponent(componentRootElement, /*e,*/ pos, webform);
1874: // moveSucceeded = webForm.getDomDocument().reparentComponent(componentRootElement, /*e,*/ pos);
1875: moveSucceeded = reparentComponent(
1876: componentRootElement, /*e,*/pos);
1877: } else if (!isAbsolutelyPositioned(componentRootElement)) {
1878: // Looks like we've moved a flow position element
1879: // out to grid
1880: // CssBox pb = null;
1881: Element parent = null;
1882: // Element element = box.getDesignBean().getElement();
1883: // XXX Possible NPE?
1884: // Element element = CssBox.getMarkupDesignBeanForCssBox(box).getElement();
1885: // Element boxComponentRootElement = CssBox.getElementForComponentRootCssBox(box);
1886: Element boxComponentRootElement = componentRootElement;
1887: // XXX Get rid of using source elements in the designer.
1888: Element element = MarkupService
1889: .getSourceElementForElement(boxComponentRootElement);
1890:
1891: if (element == null) {
1892: // XXX #124560 Give one more try.
1893: MarkupDesignBean markupDesignBean = MarkupUnit
1894: .getMarkupDesignBeanForElement(boxComponentRootElement);
1895: if (markupDesignBean != null) {
1896: element = markupDesignBean.getElement();
1897: }
1898:
1899: // XXX #109112 This box is not to move.
1900: if (element == null) {
1901: continue;
1902: }
1903: }
1904:
1905: if (element.getParentNode() != null
1906: && element.getParentNode()
1907: .getNodeType() == org.w3c.dom.Node.ELEMENT_NODE
1908: && element.getParentNode()
1909: .getNodeName().equals(
1910: HtmlTag.FSUBVIEW.name)) {
1911: // pb = parentBox;
1912: parent = (Element) element.getParentNode();
1913: // } else if ((parentBox != null) && (parentBox.getDesignBean() != null)) {
1914: // MarkupDesignBean parentBean = parentBox.getDesignBean();
1915: } else {
1916: // MarkupDesignBean parentMarkupDesignBean = CssBox.getMarkupDesignBeanForCssBox(parentBox);
1917: // Element parentComponentRootElement = CssBox.getElementForComponentRootCssBox(parentBox);
1918: Element parentComponentRootElement = parentBox == null ? null
1919: : parentBox
1920: .getComponentRootElement();
1921: if (parentComponentRootElement != null) {
1922: Element parentElement = MarkupService
1923: .getSourceElementForElement(parentComponentRootElement);
1924:
1925: if ((parentElement != null)
1926: && (parentElement.getTagName()
1927: .equals(HtmlTag.FORM.name))) {
1928: // pb = parentBox;
1929: // parent = parentBox.getSourceElement();
1930: parent = parentElement;
1931: }
1932: }
1933: }
1934:
1935: // Designer[] designers = JsfForm.findDesigners(jsfForm);
1936: // Designer designer = designers.length == 0 ? null : designers[0];
1937:
1938: // if (pb == null) {
1939: if (parent == null) {
1940: // CssBox currentBox = webform.getMapper().findBox(x, y);
1941: // CssBox currentBox = ModelViewMapper.findBox(webform.getPane().getPageBox(), x, y);
1942: Box currentBox = designer.findBox(x, y);
1943: if (currentBox != null) {
1944:
1945: // for (int j = 0, m = currentBox.getBoxCount(); j < m; j++) {
1946: // HtmlTag tag = currentBox.getBox(j).getTag();
1947: for (Box child : currentBox
1948: .getChildren()) {
1949: HtmlTag tag = child.getTag();
1950:
1951: if (tag == HtmlTag.FORM) {
1952: // pb = currentBox.getBox(j);
1953: // parent = currentBox.getSourceElement();
1954: // #102848 Get the form (not body).
1955: parent = child
1956: .getSourceElement();
1957:
1958: break;
1959: }
1960: }
1961:
1962: // if (pb == null) {
1963: // pb = currentBox;
1964: // }
1965: if (parent == null) {
1966: parent = currentBox
1967: .getSourceElement();
1968: }
1969: }
1970: }
1971:
1972: // if (parent == null) {
1973: // parent = pb.getSourceElement();
1974: // }
1975:
1976: if (element.getParentNode() != parent) {
1977: moveSucceeded =
1978: // doc.reparent(bean, e, new Position(parent, 0, Bias.FORWARD));
1979: // reparentComponent(componentRootElement, /*e,*/ new Position(parent, 0, Bias.FORWARD), webform);
1980: // reparentComponent(componentRootElement, /*e,*/ Position.create(parent, 0, Bias.FORWARD), webform);
1981: // reparentComponent(componentRootElement, /*e,*/ webForm.createDomPosition(parent, 0, Bias.FORWARD), webform);
1982: // webForm.getDomDocument().reparentComponent(componentRootElement, /*e,*/ webForm.createDomPosition(parent, 0, Bias.FORWARD));
1983: reparentComponent(componentRootElement, /*e,*/
1984: createDomPosition(parent, 0,
1985: Bias.FORWARD));
1986: }
1987:
1988: // parentBox = pb;
1989: // CssBox pb = webForm.findCssBoxForElement(parent);
1990: Box pb = designer
1991: .findBoxForSourceElement(parent);
1992: if (pb != null) {
1993: parentBox = pb;
1994: }
1995: }
1996:
1997: // prevent multiple updates for the same element -
1998: // only need a single refresh especially when just changing
1999: // from one grid position to another
2000: // webform.getDomSynchronizer().setUpdatesSuspended(bean, true);
2001: // webform.setUpdatesSuspended(componentRootElement, true);
2002: jsfForm.setUpdatesSuspended(componentRootElement,
2003: true);
2004:
2005: List<StyleData> set = new ArrayList<StyleData>(3);
2006: List<StyleData> remove = new ArrayList<StyleData>(3);
2007:
2008: // if ((pos != null) && (pos != Position.NONE)) {
2009: if ((pos != null) && (pos != DomPosition.NONE)) {
2010: if (moveSucceeded) {
2011: remove.add(new StyleData(
2012: XhtmlCss.POSITION_INDEX));
2013: remove.add(new StyleData(
2014: XhtmlCss.LEFT_INDEX));
2015: remove
2016: .add(new StyleData(
2017: XhtmlCss.TOP_INDEX));
2018: } else {
2019: java.awt.Toolkit.getDefaultToolkit().beep();
2020: }
2021: } else if (moveSucceeded) {
2022: // Translate coordinates from absolute/viewport
2023: // to absolute coordinates relative to the target
2024: // grid container
2025: set.add(new StyleData(XhtmlCss.POSITION_INDEX,
2026: // CssConstants.CSS_ABSOLUTE_VALUE));
2027: CssProvider.getValueService()
2028: .getAbsoluteValue()));
2029: set.add(getHorizontalCssSetting(x, box
2030: .getWidth(), box, parentBox,
2031: componentRootElement));
2032: set.add(getVerticalCssSetting(y, box
2033: .getHeight(), box, parentBox,
2034: componentRootElement));
2035: }
2036:
2037: // XhtmlCssEngine engine = webform.getMarkup().getCssEngine();
2038: // <removing design bean manipulation in engine>
2039: // engine.updateLocalStyleValues((RaveElement)e, set, remove);
2040: // ====
2041: // Util.updateLocalStyleValuesForElement(e,
2042: // (StyleData[])set.toArray(new StyleData[set.size()]),
2043: // (StyleData[])remove.toArray(new StyleData[remove.size()]));
2044: // WebForm.getDomProviderService().updateLocalStyleValuesForElement(componentRootElement,
2045: // set.toArray(new StyleData[set.size()]),
2046: // remove.toArray(new StyleData[remove.size()]));
2047: JsfSupportUtilities
2048: .updateLocalStyleValuesForElement(
2049: componentRootElement, set
2050: .toArray(new StyleData[set
2051: .size()]),
2052: remove.toArray(new StyleData[remove
2053: .size()]));
2054: // </removing design bean manipulation in engine>
2055: } finally {
2056: // webform.getDomSynchronizer().setUpdatesSuspended(bean, false);
2057: // webform.setUpdatesSuspended(componentRootElement, false);
2058: jsfForm.setUpdatesSuspended(componentRootElement,
2059: false);
2060: }
2061: }
2062: } finally {
2063: // doc.writeUnlock();
2064: // webform.getModel().writeUnlock(undoEvent);
2065: // webform.writeUnlock(writeLock);
2066: jsfForm.writeUnlock(writeLock);
2067: }
2068:
2069: // XXX #91531 User didn't want to have this kind of autoscroll behavior.
2070: // final Rectangle rect = boundingBox;
2071: // // #6331237 NPE.
2072: // if(rect != null) {
2073: // SwingUtilities.invokeLater(new Runnable() {
2074: // public void run() {
2075: // editor.scrollRectToVisible(rect);
2076: // }
2077: // });
2078: // }
2079: fireComponentsMoved(new DefaultDomDocumentEvent(this , null));
2080: }
2081:
2082: // XXX Copy aldo in designer/../GridHandler.
2083: /** Report whether the given element is absolutely positioned */
2084: private boolean isAbsolutelyPositioned(Element element) {
2085: boolean absolute;
2086: // Value val = CssLookup.getValue(element, XhtmlCss.POSITION_INDEX);
2087: CssValue cssValue = CssProvider.getEngineService()
2088: .getComputedValueForElement(element,
2089: XhtmlCss.POSITION_INDEX);
2090:
2091: // if ((val == CssValueConstants.ABSOLUTE_VALUE) || (val == CssValueConstants.FIXED_VALUE)) {
2092: if (CssProvider.getValueService().isAbsoluteValue(cssValue)
2093: || CssProvider.getValueService().isFixedValue(cssValue)) {
2094: absolute = true;
2095: } else {
2096: absolute = false;
2097: }
2098:
2099: return absolute;
2100: }
2101:
2102: /**
2103: * Given a target position (referring to the border top left corner) for
2104: * a box, update its horizontal CSS position properties (left/right) to
2105: * make the box appear at the target position.
2106: * This not only converts the coordinates to the margin edge (since the
2107: * CSS properties are relative to it), but also ensures that if a component
2108: * is for example only constrained on the right, the "right" property is
2109: * updated rather than "left".
2110: */
2111: // private StyleData getHorizontalCssSetting(int x, int newWidth, CssBox box, CssBox parentBox, Element e) {
2112: private StyleData getHorizontalCssSetting(int x, int newWidth,
2113: Box box, Box parentBox, Element e) {
2114: // int left = CssLookup.getLength(e, XhtmlCss.LEFT_INDEX);
2115: // int right = CssLookup.getLength(e, XhtmlCss.RIGHT_INDEX);
2116: // int left = CssUtilities.getCssLength(e, XhtmlCss.LEFT_INDEX);
2117: // int right = CssUtilities.getCssLength(e, XhtmlCss.RIGHT_INDEX);
2118: int left = CssProvider.getValueService().getCssLength(e,
2119: XhtmlCss.LEFT_INDEX);
2120: int right = CssProvider.getValueService().getCssLength(e,
2121: XhtmlCss.RIGHT_INDEX);
2122:
2123: // if ((left == CssBox.AUTO) && (right != CssBox.AUTO)) {
2124: if ((left == CssValue.AUTO) && (right != CssValue.AUTO)) {
2125: // int rx = right - (x - box.getX()) - (width - box.getWidth());
2126: // Point p = translateCoordinates(parentBox, rx, 0);
2127: // rx = p.x;
2128: //
2129: // // The CSS "right" property is relative to the Margin edge
2130: // rx += box.getRightMargin();
2131: int rx = translateRight(right, x, newWidth, box, parentBox);
2132:
2133: return new StyleData(XhtmlCss.RIGHT_INDEX, Integer
2134: .toString(rx)
2135: + "px"); // NOI18N
2136: } else {
2137: // Point p = translateCoordinates(parentBox, x, 0);
2138: // x = p.x;
2139: //
2140: // // The CSS "left" property is relative to the Margin edge
2141: // x -= box.getLeftMargin();
2142: int rx = translateLeft(x, box, parentBox);
2143:
2144: // return new StyleData(XhtmlCss.LEFT_INDEX, Integer.toString(x) + "px"); // NOI18N
2145: return new StyleData(XhtmlCss.LEFT_INDEX, Integer
2146: .toString(rx)
2147: + "px"); // NOI18N
2148: }
2149: }
2150:
2151: // XXX Copy also in designer/../GridHandler.
2152: // private int translateRight(int right, int x, int newWidth, CssBox box, CssBox parentBox) {
2153: private int translateRight(int right, int x, int newWidth, Box box,
2154: Box parentBox) {
2155: int rx = right - (x - box.getX()) - (newWidth - box.getWidth());
2156: // Point p = translateCoordinates(parentBox, rx, 0);
2157: Point p = JsfSupportUtilities.translateCoordinates(parentBox,
2158: rx, 0);
2159: rx = p.x;
2160:
2161: // The CSS "right" property is relative to the Margin edge
2162: rx += box.getRightMargin();
2163: return rx;
2164: }
2165:
2166: // XXX Copy also in designer/../GridHandler
2167: // private int translateLeft(int x, CssBox box, CssBox parentBox) {
2168: private int translateLeft(int x, Box box, Box parentBox) {
2169: // Point p = translateCoordinates(parentBox, x, 0);
2170: Point p = JsfSupportUtilities.translateCoordinates(parentBox,
2171: x, 0);
2172: x = p.x;
2173:
2174: // The CSS "left" property is relative to the Margin edge
2175: x -= box.getLeftMargin();
2176: return x;
2177: }
2178:
2179: // XXX Copy also in designer/../GridHandler.
2180: /** Same as setHorizontalCssPosition, but for the vertical dimension with
2181: * CSS top/bottom properties */
2182: // private StyleData getVerticalCssSetting(int y, int newHeight, CssBox box, CssBox parentBox, Element e) {
2183: private StyleData getVerticalCssSetting(int y, int newHeight,
2184: Box box, Box parentBox, Element e) {
2185: // int top = CssLookup.getLength(e, XhtmlCss.TOP_INDEX);
2186: // int bottom = CssLookup.getLength(e, XhtmlCss.BOTTOM_INDEX);
2187: // int top = CssUtilities.getCssLength(e, XhtmlCss.TOP_INDEX);
2188: // int bottom = CssUtilities.getCssLength(e, XhtmlCss.BOTTOM_INDEX);
2189: int top = CssProvider.getValueService().getCssLength(e,
2190: XhtmlCss.TOP_INDEX);
2191: int bottom = CssProvider.getValueService().getCssLength(e,
2192: XhtmlCss.BOTTOM_INDEX);
2193:
2194: // if ((top == CssBox.AUTO) && (bottom != CssBox.AUTO)) {
2195: if ((top == CssValue.AUTO) && (bottom != CssValue.AUTO)) {
2196: // int ry = bottom - (y - box.getY()) - (height - box.getHeight());
2197: // Point p = translateCoordinates(parentBox, 0, ry);
2198: // ry = p.y;
2199: //
2200: // // The CSS "bottom" property is relative to the Margin edge
2201: // ry += box.getEffectiveTopMargin();
2202: int ry = translateBottom(bottom, y, newHeight, box,
2203: parentBox);
2204:
2205: return new StyleData(XhtmlCss.BOTTOM_INDEX, Integer
2206: .toString(ry)
2207: + "px"); // NOI18N
2208: } else {
2209: // Point p = translateCoordinates(parentBox, 0, y);
2210: // y = p.y;
2211: //
2212: // // The CSS "top" property is relative to the Margin edge
2213: // y -= box.getEffectiveTopMargin();
2214: int ry = translateTop(y, box, parentBox);
2215:
2216: // return new StyleData(XhtmlCss.TOP_INDEX, Integer.toString(y) + "px"); // NOI18N
2217: return new StyleData(XhtmlCss.TOP_INDEX, Integer
2218: .toString(ry)
2219: + "px"); // NOI18N
2220: }
2221: }
2222:
2223: // XXX Copy also in designer/../GridHandler.
2224: // private int translateBottom(int bottom, int y, int newHeight, CssBox box, CssBox parentBox) {
2225: private int translateBottom(int bottom, int y, int newHeight,
2226: Box box, Box parentBox) {
2227: int ry = bottom - (y - box.getY())
2228: - (newHeight - box.getHeight());
2229: // Point p = translateCoordinates(parentBox, 0, ry);
2230: Point p = JsfSupportUtilities.translateCoordinates(parentBox,
2231: 0, ry);
2232: ry = p.y;
2233:
2234: // The CSS "bottom" property is relative to the Margin edge
2235: ry += box.getEffectiveTopMargin();
2236: return ry;
2237: }
2238:
2239: // XXX Copy also in designer/../GridHandler.
2240: // private int translateTop(int y, CssBox box, CssBox parentBox) {
2241: private int translateTop(int y, Box box, Box parentBox) {
2242: // Point p = translateCoordinates(parentBox, 0, y);
2243: Point p = JsfSupportUtilities.translateCoordinates(parentBox,
2244: 0, y);
2245: y = p.y;
2246:
2247: // The CSS "top" property is relative to the Margin edge
2248: y -= box.getEffectiveTopMargin();
2249: return y;
2250: }
2251:
2252: // // XXX Copy aldo in designer/../CssUtilities.
2253: // // FIXME This is very suspicious, and should be revisited.
2254: // public static final int AUTO = Integer.MAX_VALUE - 1;
2255: //
2256: // /** XXX Copy also in insync/FacesDnDSupport.
2257: // * XXX Copy also in designer/../CssUtilities
2258: // * XXX Provides the auto value as <code>AUTO</code>, revise that, it looks very dangerous.
2259: // * TODO At least move into designer/cssengine.
2260: // */
2261: // private static int getCssLength(Element element, int property) {
2262: //// Value val = getValue(element, property);
2263: // CssValue cssValue = CssProvider.getEngineService().getComputedValueForElement(element, property);
2264: //
2265: // // XXX #6460007 Possible NPE.
2266: // if (cssValue == null) {
2267: // // XXX What value to return?
2268: // return 0;
2269: // }
2270: //
2271: //// if (val == CssValueConstants.AUTO_VALUE) {
2272: // if (CssProvider.getValueService().isAutoValue(cssValue)) {
2273: // return AUTO;
2274: // }
2275: //
2276: //// return (int)val.getFloatValue();
2277: // return (int)cssValue.getFloatValue();
2278: // }
2279:
2280: // // XXX Copy also in designer/../GridHandler.
2281: // /** Given absolute coordinates x,y in the viewport, compute
2282: // * the CSS coordinates to assign to a box if it's parented by
2283: // * the given parentBox such that the coordinates will result
2284: // * in a box showing up at the absolute coordinates.
2285: // * That was a really convoluted explanation, so to be specific:
2286: // * If you have an absolutely positioned <div> at 100, 100,
2287: // * and you drag a button into it such that it's its child,
2288: // * and you drag it to screen coordinate 75, 150, then, in order
2289: // * for the button to be rendered at 75, 150 and be a child of
2290: // * the div its top/left coordinates must be -25, 50.
2291: // */
2292: //// private Point translateCoordinates(CssBox parentBox, int x, int y) {
2293: // private Point translateCoordinates(Box parentBox, int x, int y) {
2294: // while (parentBox != null) {
2295: //// if (parentBox.getBoxType().isPositioned()) {
2296: // if (parentBox.isPositioned()) {
2297: // x -= parentBox.getAbsoluteX();
2298: // y -= parentBox.getAbsoluteY();
2299: //
2300: // return new Point(x, y);
2301: // }
2302: //
2303: // if (parentBox.getPositionedBy() != null) {
2304: // parentBox = parentBox.getPositionedBy();
2305: // } else {
2306: // parentBox = parentBox.getParent();
2307: // }
2308: // }
2309: //
2310: // return new Point(x, y);
2311: // }
2312:
2313: private void moveComponentTo(Box box, int x, int y) {
2314: Element componentRootElement = box.getComponentRootElement();
2315: // We should already have a locked buffer with a user visible
2316: // undo event when this methhod is called
2317: // XXX Not here.
2318: // assert webform.getModel().isWriteLocked();
2319: // if (!webform.isWriteLocked()) {
2320: if (!jsfForm.isWriteLocked()) {
2321: ErrorManager
2322: .getDefault()
2323: .notify(
2324: ErrorManager.INFORMATIONAL,
2325: new IllegalStateException(
2326: "This method has to be called under write lock! It is not.")); // NOI18N
2327: }
2328:
2329: // prevent multiple updates for the same element - only need a single refresh
2330: try {
2331: // webform.getDomSynchronizer().setUpdatesSuspended(bean, true);
2332: // webform.setUpdatesSuspended(componentRootElement, true);
2333: jsfForm.setUpdatesSuspended(componentRootElement, true);
2334:
2335: // CssBox parentBox = box.getParent();
2336: Box parentBox = box.getParent();
2337:
2338: List<StyleData> set = new ArrayList<StyleData>(3);
2339: // set.add(new StyleData(XhtmlCss.POSITION_INDEX, CssConstants.CSS_ABSOLUTE_VALUE));
2340: set.add(new StyleData(XhtmlCss.POSITION_INDEX, CssProvider
2341: .getValueService().getAbsoluteValue()));
2342: set.add(getHorizontalCssSetting(x, box.getWidth(), box,
2343: parentBox, componentRootElement));
2344: set.add(getVerticalCssSetting(y, box.getHeight(), box,
2345: parentBox, componentRootElement));
2346:
2347: // XhtmlCssEngine engine = webform.getMarkup().getCssEngine();
2348: // <removing design bean manipulation in engine>
2349: // engine.updateLocalStyleValues((RaveElement)e, set, null);
2350: // ====
2351: // Util.updateLocalStyleValuesForElement(e,
2352: // (StyleData[])set.toArray(new StyleData[set.size()]), null);
2353: // WebForm.getDomProviderService().updateLocalStyleValuesForElement(componentRootElement,
2354: // set.toArray(new StyleData[set.size()]), null);
2355: JsfSupportUtilities.updateLocalStyleValuesForElement(
2356: componentRootElement, set.toArray(new StyleData[set
2357: .size()]), null);
2358: // </removing design bean manipulation in engine>
2359: } finally {
2360: // webform.getDomSynchronizer().setUpdatesSuspended(bean, false);
2361: // webform.setUpdatesSuspended(componentRootElement, false);
2362: jsfForm.setUpdatesSuspended(componentRootElement, false);
2363: }
2364:
2365: fireComponentMovedTo(new DefaultDomDocumentEvent(this , null));
2366: }
2367:
2368: // XXX Moved from designer/../GridHandler.
2369: public void frontComponents(Box[] boxes) {
2370: // Document doc = webform.getDocument();
2371:
2372: // UndoEvent undoEvent = webform.getModel().writeLock(NbBundle.getMessage(GridHandler.class, "BringToFront")); // NOI18N
2373: // DomProvider.WriteLock writeLock = webform.writeLock(NbBundle.getMessage(GridHandler.class, "BringToFront")); // NOI18N
2374: // DomProvider.WriteLock writeLock = jsfForm.writeLock(NbBundle.getMessage(DomDocumentImpl.class, "LBL_BringToFront")); // NOI18N
2375: UndoEvent writeLock = jsfForm.writeLock(NbBundle.getMessage(
2376: DomDocumentImpl.class, "LBL_BringToFront")); // NOI18N
2377: try {
2378: // doc.writeLock(NbBundle.getMessage(GridHandler.class, "BringToFront")); // NOI18N
2379:
2380: // int num = boxes.size();
2381: int num = boxes.length;
2382:
2383: // for (int i = 0; i < num; i++) {
2384: // CssBox box = boxes.get(i);
2385: // for (CssBox box : boxes) {
2386: for (Box box : boxes) {
2387: // MarkupDesignBean bean = box.getDesignBean();
2388: // MarkupDesignBean bean = CssBox.getMarkupDesignBeanForCssBox(box);
2389: // Element componentRootElement = CssBox.getElementForComponentRootCssBox(box);
2390: Element componentRootElement = box
2391: .getComponentRootElement();
2392:
2393: // assert bean != null;
2394:
2395: // Element e = box.getElement();
2396:
2397: // if (e == null) {
2398: // e = bean.getElement();
2399: // }
2400:
2401: // assert e != null;
2402: if (componentRootElement == null) {
2403: ErrorManager.getDefault().notify(
2404: ErrorManager.INFORMATIONAL,
2405: new NullPointerException(
2406: "There is no component root element for box="
2407: + box));
2408: continue;
2409: }
2410:
2411: // Locate the highest z index in box' parent
2412: // int highest = CssBox.AUTO;
2413: int highest = CssValue.AUTO;
2414: // CssBox parent = box.getParent();
2415: Box parent = box.getParent();
2416:
2417: // #6358276 NPE.
2418: if (parent != null) {
2419: // for (int j = 0, m = parent.getBoxCount(); j < m; j++) {
2420: // CssBox sibling = parent.getBox(j);
2421: for (Box sibling : parent.getChildren()) {
2422:
2423: if (sibling == box) {
2424: continue;
2425: }
2426:
2427: // if ((highest == CssBox.AUTO) ||
2428: // ((sibling.getZ() != CssBox.AUTO) && (sibling.getZ() > highest))) {
2429: if ((highest == CssValue.AUTO)
2430: || ((sibling.getZ() != CssValue.AUTO) && (sibling
2431: .getZ() > highest))) {
2432: highest = sibling.getZ();
2433: }
2434: }
2435: }
2436:
2437: // if (highest == CssBox.AUTO) {
2438: if (highest == CssValue.AUTO) {
2439: highest = 500;
2440: } else {
2441: highest++;
2442: }
2443:
2444: try {
2445: // doc.getWebForm().getDomSynchronizer().setUpdatesSuspended(bean, true);
2446: // doc.getWebForm().setUpdatesSuspended(componentRootElement, true);
2447: // webform.setUpdatesSuspended(componentRootElement, true);
2448: jsfForm.setUpdatesSuspended(componentRootElement,
2449: true);
2450:
2451: // XhtmlCssEngine engine = webform.getMarkup().getCssEngine();
2452:
2453: List<StyleData> set = new ArrayList<StyleData>(1);
2454: set.add(new StyleData(XhtmlCss.Z_INDEX, Integer
2455: .toString(highest)));
2456: // <removing design bean manipulation in engine>
2457: // engine.updateLocalStyleValues((RaveElement)e, set, null);
2458: // ====
2459: // Util.updateLocalStyleValuesForElement(e,
2460: // (StyleData[])set.toArray(new StyleData[set.size()]), null);
2461: // WebForm.getDomProviderService().updateLocalStyleValuesForElement(componentRootElement,
2462: // set.toArray(new StyleData[set.size()]), null);
2463: JsfSupportUtilities
2464: .updateLocalStyleValuesForElement(
2465: componentRootElement, set
2466: .toArray(new StyleData[set
2467: .size()]), null);
2468: // </removing design bean manipulation in engine>
2469: } finally {
2470: // doc.getWebForm().getDomSynchronizer().setUpdatesSuspended(bean, false);
2471: // doc.getWebForm().setUpdatesSuspended(componentRootElement, false);
2472: // webform.setUpdatesSuspended(componentRootElement, false);
2473: jsfForm.setUpdatesSuspended(componentRootElement,
2474: false);
2475: }
2476: }
2477: } finally {
2478: // doc.writeUnlock();
2479: // webform.getModel().writeUnlock(undoEvent);
2480: // webform.writeUnlock(writeLock);
2481: jsfForm.writeUnlock(writeLock);
2482: }
2483: }
2484:
2485: // XXX Moved from designer/../GridHandler.
2486: // public void back(WebForm webform, List<CssBox> boxes) {
2487: public void backComponents(Box[] boxes) {
2488: // Document doc = webform.getDocument();
2489:
2490: // UndoEvent undoEvent = webform.getModel().writeLock(NbBundle.getMessage(GridHandler.class, "SendToBack")); // NOI18N
2491: // DomProvider.WriteLock writeLock = webform.writeLock(NbBundle.getMessage(GridHandler.class, "SendToBack")); // NOI18N
2492: // DomProvider.WriteLock writeLock = jsfForm.writeLock(NbBundle.getMessage(DomDocumentImpl.class, "LBL_SendToBack")); // NOI18N
2493: UndoEvent writeLock = jsfForm.writeLock(NbBundle.getMessage(
2494: DomDocumentImpl.class, "LBL_SendToBack")); // NOI18N
2495: try {
2496: // doc.writeLock(NbBundle.getMessage(GridHandler.class, "SendToBack")); // NOI18N
2497:
2498: // int num = boxes.size();
2499: int num = boxes.length;
2500:
2501: // for (int i = 0; i < num; i++) {
2502: // CssBox box = boxes.get(i);
2503: // for (CssBox box : boxes) {
2504: for (Box box : boxes) {
2505: // MarkupDesignBean bean = box.getDesignBean();
2506: // MarkupDesignBean bean = CssBox.getMarkupDesignBeanForCssBox(box);
2507: // Element componentRootElement = CssBox.getElementForComponentRootCssBox(box);
2508: Element componentRootElement = box
2509: .getComponentRootElement();
2510: // assert bean != null;
2511:
2512: // Element e = box.getElement();
2513: // Element e = componentRootElement;
2514:
2515: // if (e == null) {
2516: // e = bean.getElement();
2517: // }
2518:
2519: // assert e != null;
2520: if (componentRootElement == null) {
2521: ErrorManager.getDefault().notify(
2522: ErrorManager.INFORMATIONAL,
2523: new NullPointerException(
2524: "There is no component root element for box="
2525: + box));
2526: continue;
2527: }
2528:
2529: // Locate the lowest z index in box' parent
2530: // XXX is auto less than 0?
2531: // int lowest = CssBox.AUTO;
2532: int lowest = CssValue.AUTO;
2533: // CssBox parent = box.getParent();
2534: Box parent = box.getParent();
2535:
2536: // #6358276 NPE.
2537: if (parent != null) {
2538: // for (int j = 0, m = parent.getBoxCount(); j < m; j++) {
2539: // CssBox sibling = parent.getBox(j);
2540: for (Box sibling : parent.getChildren()) {
2541: if (sibling == box) {
2542: continue;
2543: }
2544:
2545: // if ((lowest == CssBox.AUTO) ||
2546: // ((sibling.getZ() != CssBox.AUTO) && (sibling.getZ() < lowest))) {
2547: // lowest = sibling.getZ();
2548: // }
2549: if ((lowest == CssValue.AUTO)
2550: || ((sibling.getZ() != CssValue.AUTO) && (sibling
2551: .getZ() < lowest))) {
2552: lowest = sibling.getZ();
2553: }
2554: }
2555: }
2556:
2557: // if (lowest == CssBox.AUTO) {
2558: if (lowest == CssValue.AUTO) {
2559: lowest = 500;
2560: } else {
2561: lowest--;
2562: }
2563:
2564: try {
2565: // webform.getDomSynchronizer().setUpdatesSuspended(bean, true);
2566: // webform.setUpdatesSuspended(componentRootElement, true);
2567: jsfForm.setUpdatesSuspended(componentRootElement,
2568: true);
2569:
2570: // XhtmlCssEngine engine = webform.getMarkup().getCssEngine();
2571:
2572: List<StyleData> set = new ArrayList<StyleData>(1);
2573: set.add(new StyleData(XhtmlCss.Z_INDEX, Integer
2574: .toString(lowest)));
2575: // <removing design bean manipulation in engine>
2576: // engine.updateLocalStyleValues((RaveElement)e, set, null);
2577: // ====
2578: // Util.updateLocalStyleValuesForElement(e,
2579: // (StyleData[])set.toArray(new StyleData[set.size()]), null);
2580: // WebForm.getDomProviderService().updateLocalStyleValuesForElement(componentRootElement,
2581: // set.toArray(new StyleData[set.size()]), null);
2582: JsfSupportUtilities
2583: .updateLocalStyleValuesForElement(
2584: componentRootElement, set
2585: .toArray(new StyleData[set
2586: .size()]), null);
2587: // </removing design bean manipulation in engine>
2588: } finally {
2589: // webform.getDomSynchronizer().setUpdatesSuspended(bean, false);
2590: // webform.setUpdatesSuspended(componentRootElement, false);
2591: jsfForm.setUpdatesSuspended(componentRootElement,
2592: false);
2593: }
2594: }
2595: } finally {
2596: // doc.writeUnlock();
2597: // webform.getModel().writeUnlock(undoEvent);
2598: // webform.writeUnlock(writeLock);
2599: jsfForm.writeUnlock(writeLock);
2600: }
2601: }
2602:
2603: // XXX Moved from designer/../GridHandler.
2604: /** Resize the given component to new dimensions.
2605: * Note that the x,y position might change too, for example, when
2606: * you resize the component by dragging a selection handle on the
2607: * top or left edges of the component.
2608: *
2609: * <p>
2610: * @param editor The editor containing the resized component
2611: * @param component Component being resized
2612: * @param element The DOM element for the component
2613: * @param newX The left edge of the component after resize
2614: * @param xMoved True iff the left edge position changed during the resize
2615: * @param newY The top edge of the component after resize
2616: * @param yMoved True iff the top edge position moved during the resize
2617: * @param newWidth The new width after resize
2618: * @param newHeight The new height after resize
2619: * @param box Box being resized
2620: * @param snapDisabled If true, skip snapping
2621: * @todo Should I use floating point coordinates instead?
2622: */
2623: // public void resize(DesignerPane editor, Element componentRootElement, /*MarkupDesignBean bean,*/ int newX, boolean xMoved,
2624: // int newY, boolean yMoved, int newWidth, boolean widthChanged, int newHeight,
2625: // boolean heightChanged, CssBox box, boolean snapDisabled) {
2626: public void resizeComponent(Designer designer,
2627: Element componentRootElement, /*MarkupDesignBean bean,*/
2628: int newX, boolean xMoved, int newY, boolean yMoved,
2629: int newWidth, boolean widthChanged, int newHeight,
2630: boolean heightChanged, Box box, boolean snapEnabled) {
2631: // Locate a grid layout parent
2632: // Document doc = editor.getDocument();
2633: // WebForm webform = doc.getWebForm();
2634: // WebForm webform = editor.getWebForm();
2635:
2636: int x = newX;
2637: int y = newY;
2638:
2639: if (snapEnabled) {
2640: // x = snapX(newX, box.getPositionedBy());
2641: // y = snapY(newY, box.getPositionedBy());
2642: x = designer.snapX(newX, box.getPositionedBy());
2643: y = designer.snapY(newY, box.getPositionedBy());
2644: }
2645:
2646: Element element = box.getElement();
2647:
2648: if (element == null) {
2649: // element = bean.getElement();
2650: element = componentRootElement;
2651: }
2652:
2653: boolean absolute = isAbsolutelyPositioned(element);
2654:
2655: // UndoEvent undoEvent = webform.getModel().writeLock(NbBundle.getMessage(GridHandler.class, "ResizeComponent")); // NOI18N
2656: // DomProvider.WriteLock writeLock = webform.writeLock(NbBundle.getMessage(GridHandler.class, "ResizeComponent")); // NOI18N
2657: // DomProvider.WriteLock writeLock = jsfForm.writeLock(NbBundle.getMessage(DomDocumentImpl.class, "LBL_ResizeComponent")); // NOI18N
2658: UndoEvent writeLock = jsfForm.writeLock(NbBundle.getMessage(
2659: DomDocumentImpl.class, "LBL_ResizeComponent")); // NOI18N
2660: // Gotta set width and height attributes!
2661: try {
2662: // doc.writeLock(NbBundle.getMessage(GridHandler.class, "ResizeComponent")); // NOI18N
2663:
2664: // prevent multiple updates for the same element - only need a single refresh
2665: // webform.getDomSynchronizer().setUpdatesSuspended(bean, true);
2666: // webform.setUpdatesSuspended(componentRootElement, true);
2667: jsfForm.setUpdatesSuspended(componentRootElement, true);
2668:
2669: List<StyleData> set = new ArrayList<StyleData>(5);
2670: List<StyleData> remove = new ArrayList<StyleData>(3);
2671:
2672: if (absolute && (xMoved || yMoved)) {
2673: // set.add(new StyleData(XhtmlCss.POSITION_INDEX, CssConstants.CSS_ABSOLUTE_VALUE));
2674: set.add(new StyleData(XhtmlCss.POSITION_INDEX,
2675: CssProvider.getValueService()
2676: .getAbsoluteValue()));
2677:
2678: // CssBox parentBox = box.getParent();
2679: Box parentBox = box.getParent();
2680:
2681: if (xMoved) {
2682: set.add(getHorizontalCssSetting(x, newWidth, box,
2683: parentBox, element));
2684: }
2685:
2686: if (yMoved) {
2687: set.add(getVerticalCssSetting(y, newHeight, box,
2688: parentBox, element));
2689: }
2690: }
2691:
2692: if (widthChanged) {
2693: // if (!DndHandler.setDesignProperty(bean, HtmlAttribute.WIDTH, newWidth, webform)) {
2694: // if (!WebForm.getDomProviderService().setDesignProperty(bean, HtmlAttribute.WIDTH, newWidth)) {
2695: // if (!WebForm.getDomProviderService().setStyleAttribute(componentRootElement, HtmlAttribute.WIDTH, newWidth)) {
2696: if (!JsfSupportUtilities.setStyleAttribute(
2697: componentRootElement, HtmlAttribute.WIDTH,
2698: newWidth)) {
2699: set.add(new StyleData(XhtmlCss.WIDTH_INDEX, Integer
2700: .toString(newWidth)
2701: + "px")); // NOI18N
2702: } else {
2703: // Ensure that we don't have a conflict
2704: remove.add(new StyleData(XhtmlCss.WIDTH_INDEX));
2705: }
2706: }
2707:
2708: if (heightChanged) {
2709: // if (!DndHandler.setDesignProperty(bean, HtmlAttribute.HEIGHT, newHeight, webform)) {
2710: // if (!WebForm.getDomProviderService().setDesignProperty(bean, HtmlAttribute.HEIGHT, newHeight)) {
2711: if (!JsfSupportUtilities.setStyleAttribute(
2712: componentRootElement, HtmlAttribute.HEIGHT,
2713: newHeight)) {
2714: set.add(new StyleData(XhtmlCss.HEIGHT_INDEX,
2715: Integer.toString(newHeight) + "px")); // NOI18N
2716: } else {
2717: // Ensure that we don't have a conflict
2718: remove.add(new StyleData(XhtmlCss.HEIGHT_INDEX));
2719: }
2720: }
2721:
2722: // XhtmlCssEngine engine = webform.getMarkup().getCssEngine();
2723:
2724: // <removing design bean manipulation in engine>
2725: // engine.updateLocalStyleValues((RaveElement)element, set, remove);
2726: // ====
2727: // Util.updateLocalStyleValuesForElement(element,
2728: // (StyleData[])set.toArray(new StyleData[set.size()]),
2729: // (StyleData[])remove.toArray(new StyleData[remove.size()]));
2730: // WebForm.getDomProviderService().updateLocalStyleValuesForElement(element,
2731: // set.toArray(new StyleData[set.size()]),
2732: // remove.toArray(new StyleData[remove.size()]));
2733: JsfSupportUtilities.updateLocalStyleValuesForElement(
2734: element, set.toArray(new StyleData[set.size()]),
2735: remove.toArray(new StyleData[remove.size()]));
2736: // </removing design bean manipulation in engine>
2737: } finally {
2738: // webform.getDomSynchronizer().setUpdatesSuspended(bean, false);
2739: // webform.setUpdatesSuspended(componentRootElement, false);
2740: jsfForm.setUpdatesSuspended(componentRootElement, false);
2741: // doc.writeUnlock();
2742: // webform.getModel().writeUnlock(undoEvent);
2743: // webform.writeUnlock(writeLock);
2744: jsfForm.writeUnlock(writeLock);
2745: }
2746: }
2747:
2748: // XXX Moved from designer/../GridHandler.
2749: public void snapToGrid(Designer designer) {
2750: //// GridHandler handler = GridHandler.getInstance();
2751: //// DesignerPane editor = webForm.getPane();
2752: // SelectionManager sm = webForm.getSelection();
2753: //// Iterator it = sm.iterator();
2754: // Element[] componentRootElements = sm.getSelectedComponentRootElements();
2755: //// ModelViewMapper mapper = webform.getMapper();
2756: Element[] componentRootElements = designer
2757: .getSelectedComponents();
2758:
2759: boolean haveMoved = false;
2760: // Document doc = webform.getDocument();
2761:
2762: // UndoEvent undoEvent = webform.getModel().writeLock(NbBundle.getMessage(AlignAction.class, "LBL_SnapToGrid")); // NOI18N
2763: // DomProvider.WriteLock writeLock = webForm.writeLock(NbBundle.getMessage(GridHandler.class, "LBL_SnapToGrid")); // NOI18N
2764: // DomProvider.WriteLock writeLock = jsfForm.writeLock(NbBundle.getMessage(DomDocumentImpl.class, "LBL_SnapToGrid")); // NOI18N
2765: UndoEvent writeLock = jsfForm.writeLock(NbBundle.getMessage(
2766: DomDocumentImpl.class, "LBL_SnapToGrid")); // NOI18N
2767: try {
2768: // doc.writeLock(NbBundle.getMessage(AlignAction.class, "LBL_SnapToGrid")); // NOI18N
2769:
2770: // while (it.hasNext()) {
2771: // MarkupDesignBean bean = (MarkupDesignBean)it.next();
2772: for (Element componentRootElement : componentRootElements) {
2773: // MarkupDesignBean bean = WebForm.getDomProviderService().getMarkupDesignBeanForElement(componentRootElement);
2774: // CssBox box = mapper.findBox(bean);
2775: // CssBox box = ModelViewMapper.findBoxForComponentRootElement(webForm.getPane().getPageBox(), componentRootElement);
2776: Box box = designer
2777: .findBoxForComponentRootElement(componentRootElement);
2778:
2779: if (box == null) {
2780: continue;
2781: }
2782:
2783: // boolean canAlign = box.getBoxType().isAbsolutelyPositioned();
2784: boolean canAlign = box.isAbsolutelyPositioned();
2785:
2786: if (!canAlign) {
2787: continue;
2788: }
2789:
2790: int x = box.getAbsoluteX();
2791: int y = box.getAbsoluteY();
2792:
2793: // Snap to grid.
2794: // x = snapX(x, box.getPositionedBy());
2795: // y = snapY(y, box.getPositionedBy());
2796: x = designer.snapX(x, box.getPositionedBy());
2797: y = designer.snapY(y, box.getPositionedBy());
2798:
2799: // moveTo(editor, /*bean,*/ box, x, y /*, false*/);
2800: // webForm.getDomDocument().moveComponentTo(box, x, y);
2801: moveComponentTo(box, x, y);
2802:
2803: haveMoved = true;
2804: }
2805: } finally {
2806: // doc.writeUnlock();
2807: // webform.getModel().writeUnlock(undoEvent);
2808: // webForm.writeUnlock(writeLock);
2809: jsfForm.writeUnlock(writeLock);
2810: }
2811:
2812: // if (!haveMoved) {
2813: // StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage(GridHandler.class, "MSG_AlignAbsolute"));
2814: // UIManager.getLookAndFeel().provideErrorFeedback(webForm.getPane());
2815: // }
2816:
2817: // fireComponentsMoved(new DefaultDomDocumentEvent(this, null));
2818: }
2819:
2820: // XXX Moved from designer/../GridHandler.
2821: public void align(Designer designer, JsfForm.Alignment alignment) {
2822: // Primary
2823: // SelectionManager sm = webForm.getSelection();
2824: //
2825: // if (sm.isSelectionEmpty()) {
2826: // return;
2827: // }
2828: //
2829: // sm.pickPrimary();
2830: Element primaryComponnetRootElement = designer
2831: .getPrimarySelectedComponent();
2832:
2833: // ModelViewMapper mapper = webform.getMapper();
2834: // CssBox primaryBox = mapper.findBox(sm.getPrimary());
2835: // CssBox primaryBox = ModelViewMapper.findBox(webForm.getPane().getPageBox(), sm.getPrimary());
2836: Box primaryBox = designer
2837: .findBoxForComponentRootElement(primaryComponnetRootElement);
2838:
2839: if (primaryBox == null) {
2840: return;
2841: }
2842:
2843: boolean haveMoved = false;
2844: // Document doc = webform.getDocument();
2845:
2846: // UndoEvent undoEvent = webform.getModel().writeLock(NbBundle.getMessage(SelectionManager.class, "Align")); // NOI18N
2847: // DomProvider.WriteLock writeLock = webForm.writeLock(NbBundle.getMessage(SelectionManager.class, "Align")); // NOI18N
2848: // DomProvider.WriteLock writeLock = jsfForm.writeLock(NbBundle.getMessage(DomDocumentImpl.class, "LBL_Align")); // NOI18N
2849: UndoEvent writeLock = jsfForm.writeLock(NbBundle.getMessage(
2850: DomDocumentImpl.class, "LBL_Align")); // NOI18N
2851: try {
2852: // doc.writeLock(NbBundle.getMessage(SelectionManager.class, "Align")); // NOI18N
2853:
2854: // GridHandler handler = GridHandler.getInstance();
2855: // DesignerPane editor = webForm.getPane();
2856: // boolean canAlign = primaryBox.getBoxType().isAbsolutelyPositioned();
2857: boolean canAlign = primaryBox.isAbsolutelyPositioned();
2858:
2859: int x = primaryBox.getAbsoluteX();
2860: int y = primaryBox.getAbsoluteY();
2861: int w = primaryBox.getWidth();
2862: int h = primaryBox.getHeight();
2863: // Iterator it = sm.iterator();
2864: //
2865: // while (canAlign && it.hasNext()) {
2866: // MarkupDesignBean bean = (MarkupDesignBean)it.next();
2867: // for (Element componentRootElement : sm.getSelectedComponentRootElements()) {
2868: for (Element componentRootElement : designer
2869: .getSelectedComponents()) {
2870: // MarkupDesignBean bean = WebForm.getDomProviderService().getMarkupDesignBeanForElement(componentRootElement);
2871: // CssBox box = mapper.findBox(bean);
2872: // CssBox box = ModelViewMapper.findBoxForComponentRootElement(webForm.getPane().getPageBox(), componentRootElement);
2873: Box box = designer
2874: .findBoxForComponentRootElement(componentRootElement);
2875:
2876: if (box == null) {
2877: continue;
2878: }
2879:
2880: // XXX Should I use isPositioned() instead? (e.g. are relative
2881: // positioned boxes alignable?
2882: // if (!box.getBoxType().isAbsolutelyPositioned()) {
2883: if (!box.isAbsolutelyPositioned()) {
2884: continue;
2885: }
2886:
2887: haveMoved = true;
2888:
2889: /*
2890: Element element = FacesSupport.getElement(fob.component);
2891: if (element == null) {
2892: continue;
2893: }
2894: */
2895: switch (alignment) {
2896: case TOP:
2897: // moveTo(editor, /*bean,*/ box, box.getAbsoluteX(), y/*, true*/);
2898: // webForm.getDomDocument().moveComponentTo(box, box.getAbsoluteX(), y);
2899: moveComponentTo(box, box.getAbsoluteX(), y);
2900:
2901: break;
2902:
2903: case MIDDLE:
2904: // moveTo(editor, /*bean,*/ box, box.getAbsoluteX(),
2905: // (y + (h / 2)) - (box.getHeight() / 2)/*, true*/);
2906: // webForm.getDomDocument().moveComponentTo(box, box.getAbsoluteX(), (y + (h / 2)) - (box.getHeight() / 2));
2907: moveComponentTo(box, box.getAbsoluteX(),
2908: (y + (h / 2)) - (box.getHeight() / 2));
2909:
2910: break;
2911:
2912: case BOTTOM:
2913: // moveTo(editor, /*bean,*/ box, box.getAbsoluteX(),
2914: // (y + h) - box.getHeight()/*, true*/);
2915: // webForm.getDomDocument().moveComponentTo(box, box.getAbsoluteX(), (y + h) - box.getHeight());
2916: moveComponentTo(box, box.getAbsoluteX(), (y + h)
2917: - box.getHeight());
2918:
2919: break;
2920:
2921: case LEFT:
2922: // moveTo(editor, /*bean,*/ box, x, box.getAbsoluteY()/*, true*/);
2923: // webForm.getDomDocument().moveComponentTo(box, x, box.getAbsoluteY());
2924: moveComponentTo(box, x, box.getAbsoluteY());
2925:
2926: break;
2927:
2928: case CENTER:
2929: // moveTo(editor, /*bean,*/ box, (x + (w / 2)) - (box.getWidth() / 2),
2930: // box.getAbsoluteY()/*, true*/);
2931: // webForm.getDomDocument().moveComponentTo(box, (x + (w / 2)) - (box.getWidth() / 2), box.getAbsoluteY());
2932: moveComponentTo(box, (x + (w / 2))
2933: - (box.getWidth() / 2), box.getAbsoluteY());
2934:
2935: break;
2936:
2937: case RIGHT:
2938: // moveTo(editor, /*bean,*/ box, (x + w) - box.getWidth(), box.getAbsoluteY()/*, true*/);
2939: // webForm.getDomDocument().moveComponentTo(box, (x + w) - box.getWidth(), box.getAbsoluteY());
2940: moveComponentTo(box, (x + w) - box.getWidth(), box
2941: .getAbsoluteY());
2942:
2943: break;
2944: }
2945: }
2946: } finally {
2947: // doc.writeUnlock();
2948: // webform.getModel().writeUnlock(undoEvent);
2949: // webForm.writeUnlock(writeLock);
2950: jsfForm.writeUnlock(writeLock);
2951: }
2952:
2953: // if (!haveMoved) {
2954: // StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage(GridHandler.class,"MSG_AlignAbsolute"));
2955: // UIManager.getLookAndFeel().provideErrorFeedback(webForm.getPane());
2956: // }
2957:
2958: // fireComponentsMoved(new DefaultDomDocumentEvent(this, null));
2959: }
2960:
2961: // XXX Moved from designer/../DesignerCaret
2962: /**
2963: * @todo Check deletion back to first char in <body> !
2964: * @todo Check read-only state etc
2965: */
2966: public boolean deleteNextChar(Designer designer, DomRange range) {
2967: if (range == null) {
2968: return false;
2969: }
2970:
2971: // UndoEvent undoEvent = webform.getModel().writeLock(NbBundle.getMessage(DeleteNextCharAction.class, "DeleteText")); // NOI18N
2972: // DomProvider.WriteLock writeLock = jsfForm.writeLock(NbBundle.getMessage(DomDocumentImpl.class, "LBL_DeleteText")); // NOI18N
2973: UndoEvent writeLock = jsfForm.writeLock(NbBundle.getMessage(
2974: DomDocumentImpl.class, "LBL_DeleteText")); // NOI18N
2975: try {
2976: // TODO - compute previous visual position, decide if it's
2977: // isWithinEditableRegion(Position pos)
2978: // and if so, set the range to it and delete the range.
2979: // if (hasSelection()) {
2980: // removeSelection();
2981: if (!range.isEmpty()) {
2982: deleteRangeContents(range);
2983: return true;
2984: }
2985:
2986: // Document doc = component.getDocument();
2987: // Position mark = range.getMark();
2988: DomPosition mark = range.getMark();
2989: // Position dot = ModelViewMapper.computeArrowRight(doc.getWebForm(), mark);
2990: // Position dot = ModelViewMapper.computeArrowRight(component.getWebForm(), mark);
2991: // DomPosition dot = ModelViewMapper.computeArrowRight(component.getWebForm(), mark);
2992: DomPosition dot = designer.computeNextPosition(mark);
2993:
2994: // if ((dot == Position.NONE) || !isWithinEditableRegion(dot)) {
2995: // if ((dot == DomPosition.NONE) || !isWithinEditableRegion(dot)) {
2996: if ((dot == DomPosition.NONE)
2997: || !designer.isInsideEditableRegion(dot)) {
2998: // UIManager.getLookAndFeel().provideErrorFeedback(component); // beep
2999:
3000: return false;
3001: }
3002:
3003: range.setRange(mark.getNode(), mark.getOffset(), dot
3004: .getNode(), dot.getOffset());
3005: // range.deleteContents();
3006: // removeSelection();
3007: deleteRangeContents(range);
3008:
3009: return true;
3010: } finally {
3011: // doc.writeUnlock();
3012: jsfForm.writeUnlock(writeLock);
3013: }
3014: }
3015:
3016: // XXX Moved from designer/../DesignerCaret.
3017: /**
3018: * @todo Check deletion back to first char in <body> !
3019: * @todo Check read-only state etc
3020: */
3021: public boolean deletePreviousChar(Designer designer, DomRange range) {
3022: if (range == null) {
3023: return false;
3024: }
3025:
3026: // UndoEvent undoEvent = webform.getModel().writeLock(NbBundle.getMessage(DeleteNextCharAction.class, "DeleteText")); // NOI18N
3027: // DomProvider.WriteLock writeLock = jsfForm.writeLock(NbBundle.getMessage(DomDocumentImpl.class, "LBL_DeleteText")); // NOI18N
3028: UndoEvent writeLock = jsfForm.writeLock(NbBundle.getMessage(
3029: DomDocumentImpl.class, "LBL_DeleteText")); // NOI18N
3030: try {
3031: // TODO - compute previous visual position, decide if it's
3032: // isWithinEditableRegion(Position pos)
3033: // and if so, set the range to it and delete the range.
3034: // if (hasSelection()) {
3035: // removeSelection();
3036: if (!range.isEmpty()) {
3037: deleteRangeContents(range);
3038:
3039: return true;
3040: }
3041:
3042: // Document doc = component.getDocument();
3043: // Position mark = range.getMark();
3044: DomPosition mark = range.getMark();
3045: // Position dot = ModelViewMapper.computeArrowLeft(doc.getWebForm(), mark);
3046: // Position dot = ModelViewMapper.computeArrowLeft(component.getWebForm(), mark);
3047: // DomPosition dot = ModelViewMapper.computeArrowLeft(component.getWebForm(), mark);
3048: DomPosition dot = designer.computePreviousPosition(mark);
3049:
3050: // if ((dot == Position.NONE) || !isWithinEditableRegion(dot)) {
3051: // if ((dot == DomPosition.NONE) || !isWithinEditableRegion(dot)) {
3052: if ((dot == DomPosition.NONE)
3053: || !designer.isInsideEditableRegion(dot)) {
3054: // UIManager.getLookAndFeel().provideErrorFeedback(component); // beep
3055:
3056: return false;
3057: }
3058:
3059: range.setRange(dot.getNode(), dot.getOffset(), mark
3060: .getNode(), mark.getOffset());
3061:
3062: // XXX DEBUGGING ONLY
3063: /*
3064: Element element = doc.getBody();
3065: if (element != null) {
3066: System.out.println("BEFORE DELETION: " + org.netbeans.modules.visualweb.css2.FacesSupport.getHtmlStream(element));
3067: }
3068: */
3069: // range.deleteContents();
3070: // removeSelection();
3071: deleteRangeContents(range);
3072:
3073: // XXX DEBUGGING ONLY
3074:
3075: /*
3076: if (element != null) {
3077: System.out.println("BEFORE DELETION: " + org.netbeans.modules.visualweb.css2.FacesSupport.getHtmlStream(element));
3078: }
3079: */
3080: return true;
3081: } finally {
3082: // doc.writeUnlock();
3083: // webform.getModel().writeUnlock(undoEvent);
3084: jsfForm.writeUnlock(writeLock);
3085: }
3086:
3087: }
3088:
3089: public void deleteComponents(Element[] componentRootElements) {
3090: // UndoEvent undoEvent = webform.getModel().writeLock(NbBundle.getMessage(SelectionTopComp.class, "DeleteSelection")); // NOI18N
3091: // DomProvider.WriteLock writeLock = jsfForm.writeLock(NbBundle.getMessage(DomDocumentImpl.class, "LBL_DeleteComponents")); // NOI18N
3092: UndoEvent writeLock = jsfForm.writeLock(NbBundle.getMessage(
3093: DomDocumentImpl.class, "LBL_DeleteComponents")); // NOI18N
3094: try {
3095: for (Element componentRootElement : componentRootElements) {
3096: if (JsfSupportUtilities
3097: .isSpecialComponent(componentRootElement)) {
3098: continue;
3099: }
3100:
3101: DesignBean designBean = MarkupUnit
3102: .getMarkupDesignBeanForElement(componentRootElement);
3103: if (designBean == null) {
3104: return;
3105: }
3106: jsfForm.deleteDesignBean(designBean);
3107: }
3108: } finally {
3109: // doc.writeUnlock();
3110: // webform.getModel().writeUnlock(undoEvent);
3111: jsfForm.writeUnlock(writeLock);
3112:
3113: }
3114: }
3115:
3116: // XXX
3117: boolean isRenderedNode(Node node) {
3118: return jsfForm.isRenderedNode(node);
3119: }
3120:
3121: JsfForm getJsfForm() {
3122: return jsfForm;
3123: }
3124: }
|