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: package org.netbeans.modules.visualweb.insync;
0042:
0043: import org.netbeans.modules.visualweb.api.designer.cssengine.StyleData;
0044: import org.netbeans.modules.visualweb.designer.html.HtmlAttribute;
0045: import org.netbeans.modules.visualweb.insync.faces.FacesBean;
0046: import org.netbeans.modules.visualweb.insync.live.SourceLiveRoot;
0047: import org.netbeans.modules.visualweb.insync.markup.JspxSerializer;
0048: import java.io.BufferedInputStream;
0049: import java.io.BufferedReader;
0050: import org.netbeans.modules.visualweb.api.designer.cssengine.CssProvider;
0051: import org.netbeans.modules.visualweb.api.designer.cssengine.CssValue;
0052: import org.netbeans.modules.visualweb.api.designer.cssengine.XhtmlCss;
0053: import org.netbeans.modules.visualweb.api.designer.markup.MarkupService;
0054: import com.sun.rave.designtime.Customizer2;
0055: import com.sun.rave.designtime.DesignBean;
0056: import com.sun.rave.designtime.DesignContext;
0057: import com.sun.rave.designtime.DesignInfo;
0058: import com.sun.rave.designtime.DesignProject;
0059: import com.sun.rave.designtime.DesignProperty;
0060: import com.sun.rave.designtime.markup.MarkupDesignBean;
0061: import org.netbeans.modules.visualweb.insync.beans.Bean;
0062: import org.netbeans.modules.visualweb.insync.faces.FacesPageUnit;
0063: import org.netbeans.modules.visualweb.insync.faces.HtmlBean;
0064: import org.netbeans.modules.visualweb.insync.faces.MarkupBean;
0065: import org.netbeans.modules.visualweb.insync.live.BeansDesignBean;
0066: import org.netbeans.modules.visualweb.insync.live.LiveUnit;
0067: import org.netbeans.modules.visualweb.insync.markup.MarkupUnit;
0068: import org.netbeans.modules.visualweb.insync.models.FacesModel;
0069: import org.netbeans.modules.visualweb.insync.models.FacesModelSet;
0070: import org.netbeans.modules.visualweb.project.jsf.api.JsfProjectUtils;
0071: import org.netbeans.modules.visualweb.xhtml.F_Verbatim;
0072: import java.beans.PropertyDescriptor;
0073: import java.io.File;
0074: import java.io.InputStream;
0075: import java.io.InputStreamReader;
0076: import java.io.IOException;
0077: import java.io.StringWriter;
0078: import java.net.MalformedURLException;
0079: import java.net.URL;
0080: import java.util.ArrayList;
0081: import java.util.List;
0082: import javax.faces.component.UIComponent;
0083: import javax.swing.text.Segment;
0084: import javax.swing.text.StyledDocument;
0085: import org.apache.xml.serialize.OutputFormat;
0086: import org.netbeans.api.project.FileOwnerQuery;
0087: import org.netbeans.api.project.Project;
0088:
0089: import org.openide.ErrorManager;
0090: import org.openide.cookies.EditorCookie;
0091: import org.openide.cookies.LineCookie;
0092: import org.openide.filesystems.FileObject;
0093: import org.openide.filesystems.FileStateInvalidException;
0094: import org.openide.filesystems.FileUtil;
0095: import org.openide.loaders.DataObject;
0096: import org.openide.loaders.DataObjectNotFoundException;
0097: import org.openide.text.Line;
0098: import org.netbeans.modules.visualweb.extension.openide.util.Trace;
0099: import org.openide.util.NbBundle;
0100: import org.openide.windows.IOProvider;
0101: import org.openide.windows.InputOutput;
0102: import org.openide.windows.OutputEvent;
0103: import org.openide.windows.OutputListener;
0104: import org.openide.windows.OutputWriter;
0105: import org.w3c.dom.Document;
0106: import org.w3c.dom.DocumentFragment;
0107: import org.w3c.dom.Element;
0108: import org.w3c.dom.Node;
0109:
0110: import org.w3c.dom.NodeList;
0111:
0112: /**
0113: * Common utility methods for helping with NB, Swing and DOM objects.
0114: *
0115: * @author Carl Quinn
0116: * @author Tor Norbye
0117: */
0118: public final class Util {
0119: private Util() {
0120: }
0121:
0122: /**
0123: * Get/find the NB DataObject for a given FileObject
0124: *
0125: * @param file The given FileObject.
0126: * @return The corresponding DataObject.
0127: */
0128: public static DataObject findDataObject(FileObject file) {
0129: if (file != null && !file.isValid())
0130: return null;
0131: try {
0132: return DataObject.find(file);
0133: } catch (DataObjectNotFoundException e) {
0134: return null;
0135: }
0136: }
0137:
0138: // /**
0139: // * Find/get the corresponding Project GenericItem given a NB FileObject
0140: // *
0141: // * @param file The given FileObject.
0142: // * @return The corresponding GenericItem
0143: // */
0144: // public static GenericItem findItem(FileObject file) {
0145: // DataObject dobj = findDataObject(file);
0146: // return dobj != null ? GenericItem.findItem(dobj) : null;
0147: // }
0148:
0149: /**
0150: * Get the NB (data) cookie of a specified type for a given FileObject.
0151: *
0152: * @param file The given FileObject.
0153: * @param type The cookie type to get.
0154: * @return The cookie.
0155: */
0156: public static org.openide.nodes.Node.Cookie getCookie(
0157: FileObject file, Class type) {
0158: DataObject dobj = findDataObject(file);
0159: return dobj != null ? dobj.getCookie(type) : null;
0160: }
0161:
0162: /**
0163: * Retrieve the swing Abstract Document from a given data object.
0164: *
0165: * @param file The file object to retrieve the document from
0166: * @param open If true, open the document if it's not already open. If false, this method will
0167: * return null for data object whose document is not already open.
0168: * @return The document, or null if the data object is not openable (or if the document is not
0169: * open and you did not set the open parameter to true.)
0170: */
0171: public static StyledDocument retrieveDocument(FileObject file,
0172: boolean open) {
0173:
0174: DataObject dobj;
0175: try {
0176: dobj = DataObject.find(file);
0177: } catch (DataObjectNotFoundException e) {
0178: return null;
0179: }
0180:
0181: EditorCookie edit = (EditorCookie) dobj
0182: .getCookie(EditorCookie.class);
0183: if (edit == null)
0184: return null;
0185:
0186: StyledDocument doc = null;
0187: if (open) {
0188: try {
0189: doc = edit.openDocument(); // opens, blocking if needed
0190: } catch (java.io.IOException e) {
0191: ErrorManager.getDefault().notify(e);
0192: }
0193: } else {
0194: doc = edit.getDocument(); // gets iff open, & does not block
0195: }
0196: return doc;
0197: }
0198:
0199: /**
0200: * Load a swing abstract document into a buffer. Use doc.getLength() to get the length in chars.
0201: *
0202: *
0203: * @param doc
0204: * @return BufferResult with the allocated char[] buffer and size or null and 0.
0205: */
0206: public static BufferResult loadDocumentBuffer(StyledDocument doc) {
0207: try {
0208: int len = doc.getLength();
0209: Segment seg = new Segment();
0210: doc.getText(0, len, seg);
0211: // make sure we leave at least one pad char for gjc 2.2+ Scanner
0212: if (seg.array.length == len) {
0213: char[] buf = new char[len + 1];
0214: System.arraycopy(seg.array, 0, buf, 0, len);
0215: return new BufferResultImpl(buf, doc.getLength());
0216: } else {
0217: return new BufferResultImpl(seg.array, doc.getLength());
0218: }
0219: } catch (javax.swing.text.BadLocationException ex) {
0220: // we know the location we passed is good...
0221: ErrorManager.getDefault().notify(
0222: ErrorManager.INFORMATIONAL, ex);
0223: }
0224: return new BufferResultImpl(null, 0);
0225: }
0226:
0227: public static final String JAVA_EXT = "java"; // NOI18N
0228: public static final String JSP_EXT = "jsp"; // NOI18N
0229: public static final String JSPF_EXT = "jspf"; // NOI18N
0230: public static final String XML_EXT = "xml"; // NOI18N
0231:
0232: public static BufferResult loadFileObjectBuffer(
0233: FileObject fileObject) {
0234: BufferedReader bufferedReader = null;
0235: String encoding = null;
0236: String fileExt = fileObject.getExt();
0237: try {
0238: BufferedInputStream inputStream = new BufferedInputStream(
0239: fileObject.getInputStream());
0240: if (fileObject.getExt().equals(JAVA_EXT)) {
0241: //NB60 encoding = org.netbeans.modules.java.Util.getFileEncoding(fileObject); // Talk to Wiston or Java folks
0242: }
0243: if (fileExt.equals(JSP_EXT) || fileExt.equals(JSPF_EXT)
0244: || fileExt.equals(XML_EXT)) {
0245: encoding = EncodingHelper.detectEncoding(inputStream);
0246: } else {
0247: encoding = getFileEncoding(fileObject);
0248: }
0249: if (encoding != null) {
0250: bufferedReader = new BufferedReader(
0251: new InputStreamReader(inputStream, encoding));
0252: } else {
0253: bufferedReader = new BufferedReader(
0254: new InputStreamReader(inputStream));
0255: }
0256: // Read the data line by line (we deal only with files of type .jsp, .java, .xml)
0257: // and add new line as line separator. This is to emulate how StyledDocument keeps
0258: // the data internally.
0259: // See http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/text/DefaultEditorKit.html (Newlines)
0260:
0261: String aLine;
0262: StringBuffer strBuilder = new StringBuffer((int) fileObject
0263: .getSize() + 1);
0264: while ((aLine = bufferedReader.readLine()) != null) {
0265: strBuilder.append(aLine + "\n");
0266: }
0267: strBuilder.append(' ');
0268: return new BufferResultImpl(strBuilder.toString()
0269: .toCharArray(), strBuilder.length() - 1);
0270: } catch (IOException ex) {
0271: ErrorManager.getDefault().notify(
0272: ErrorManager.INFORMATIONAL, ex);
0273: } finally {
0274: if (bufferedReader != null) {
0275: try {
0276: bufferedReader.close();
0277: } catch (IOException ex) {
0278: ErrorManager.getDefault().notify(
0279: ErrorManager.INFORMATIONAL, ex);
0280: }
0281: }
0282: }
0283: return new BufferResultImpl(null, 0);
0284: }
0285:
0286: private static final String ATTR_FILE_ENCODING = "Content-Encoding"; // NOI18N
0287:
0288: /**
0289: * Grab the file object's idea of the source encoding
0290: */
0291: private static String getFileEncoding(FileObject someFile) {
0292: return (String) someFile.getAttribute(ATTR_FILE_ENCODING);
0293: }
0294:
0295: public static BufferResult loadDocumentOrFileObjectBuffer(
0296: FileObject fileObject) {
0297: StyledDocument styledDocument = retrieveDocument(fileObject,
0298: false);
0299: if (styledDocument == null) {
0300: return loadFileObjectBuffer(fileObject);
0301: } else {
0302: return loadDocumentBuffer(styledDocument);
0303: }
0304: }
0305:
0306: /** XXX Result encapsulating buffer and size read.
0307: * Investigate why the size is separate, and not used buffer size directly.
0308: * It is very suspicious. */
0309: public interface BufferResult {
0310: public char[] getBuffer();
0311:
0312: public int getSize();
0313: } // End of BufferResult.
0314:
0315: private static class BufferResultImpl implements BufferResult {
0316: private final char[] buffer;
0317: private final int size;
0318:
0319: public BufferResultImpl(char[] buffer, int size) {
0320: this .buffer = buffer;
0321: this .size = size;
0322: }
0323:
0324: public char[] getBuffer() {
0325: return buffer;
0326: }
0327:
0328: public int getSize() {
0329: return size;
0330: }
0331: } // End of BufferResutlImpl.
0332:
0333: /**
0334: * Update a Project GenericItem's property to a given value, removing the property if the value
0335: * is null or blank, and not touching the property if the new value is not a change.
0336: * @param item The item whose property is to be set.
0337: * @param name The property name to set.
0338: * @param newval The new property value.
0339: */
0340: public static void updateItemProperty(FileObject file, String name,
0341: String newval) {
0342: // PROJECTTODO2: cleanup, find a different way to do this ? Like use project API instead ?
0343: //System.err.println("updateItemProperty on:" + item + " name:" + name + " val:" + newval);
0344: String oldval = (String) file.getAttribute(name);
0345: if (oldval == null)
0346: oldval = ""; // make sure pm's none is the same as our none--very unlikely to be null
0347: if (!oldval.equals(newval)) {
0348: try {
0349: if (newval != null && newval.length() > 0)
0350: file.setAttribute(name, newval); // have new value: add it
0351: else
0352: file.setAttribute(name, null); // have no value: remove property
0353: } catch (IOException e) {
0354: e.printStackTrace();
0355: }
0356: }
0357: }
0358:
0359: // <markup_separation> moved to designer/markup
0360: // /**
0361: // * Show the given line in a particular file.
0362: // *
0363: // * @param filename The full path to the file, or null. Exactly one of filename or fileObject
0364: // * should be non null.
0365: // * @param fileObject The FileObject for the file or null. Exactly one of filename or fileObject
0366: // * should be non null.
0367: // * @param lineno The line number
0368: // * @param openFirst Usually you'll want to pass false. When set to true, this will first open
0369: // * the file, then request the given line number; this works around certain bugs for
0370: // * some editor types like CSS files.
0371: // */
0372: // public static void show(String filename, FileObject fileObject, int lineno, int column,
0373: // boolean openFirst) {
0374: // assert (filename != null && fileObject == null) || (filename == null && fileObject != null);
0375: // if (fileObject != null) {
0376: // show(fileObject, lineno, column, openFirst);
0377: // }
0378: // else {
0379: // File file = new File(filename);
0380: // FileObject fo = FileUtil.toFileObject(file);
0381: // if (fo != null) {
0382: // show(fo, lineno, column, openFirst);
0383: // }
0384: // }
0385: // }
0386: //
0387: // /**
0388: // * @param fo
0389: // * @param lineno
0390: // * @param column
0391: // * @param openFirst
0392: // * @return
0393: // */
0394: // private static boolean show(FileObject fo, int lineno, int column, boolean openFirst) {
0395: // DataObject dobj;
0396: // try {
0397: // dobj = DataObject.find(fo);
0398: // }
0399: // catch (DataObjectNotFoundException ex) {
0400: // ErrorManager.getDefault().notify(ex);
0401: // return false;
0402: // }
0403: //
0404: // // Try to open doc before showing the line. This SHOULD not be
0405: // // necessary, except without this the IDE hangs in its attempt
0406: // // to open the file when the file in question is a CSS file.
0407: // // Probably a bug in the xml/css module's editorsupport code.
0408: // // This has the negative effect of first flashing the top
0409: // // of the file before showing the destination line, so
0410: // // this operation is made conditional so only clients who
0411: // // actually need it need to use it.
0412: // if (openFirst) {
0413: // EditorCookie ec = (EditorCookie)dobj.getCookie(EditorCookie.class);
0414: // if (ec != null) {
0415: // try {
0416: // ec.openDocument(); // ensure that it has been opened - REDUNDANT?
0417: // //ec.open();
0418: // }
0419: // catch (IOException ex) {
0420: // ErrorManager.getDefault().notify(ex);
0421: // }
0422: // }
0423: // }
0424: //
0425: // LineCookie lc = (LineCookie)dobj.getCookie(LineCookie.class);
0426: // if (lc != null) {
0427: // Line.Set ls = lc.getLineSet();
0428: // if (ls != null) {
0429: // // -1: convert line numbers to be zero-based
0430: // Line line = ls.getCurrent(lineno-1);
0431: // // TODO - pass in a column too?
0432: // line.show(Line.SHOW_GOTO, column);
0433: // return true;
0434: // }
0435: // }
0436: // return false;
0437: // }
0438: // </markup_separation>
0439:
0440: /**
0441: * Locate an element of the given tag name as a direct child of the given parent. If no element
0442: * of that tag name is found it will either return null if the create flag is false, or if the
0443: * create flag is true, the element will be created and inserted before it is returned.
0444: * <p>
0445: * @todo Combine with ensureElement! This method might be slightly faster since it does not
0446: * search the whole hierarchy for a match; it is intended to build up specific structures, such
0447: * as <html><head><link>... - it knows it should only look for "head" directly under "html".
0448: *
0449: * @param tag The tag name of the tag to be found or created
0450: * @param parent The element parent under which we want to search
0451: * @param create If true, create the element if it doesn't exist, otherwise return null if the
0452: * tag is not found.
0453: */
0454: public static Element findChild(String tag, Node parent,
0455: boolean create) {
0456: NodeList list = parent.getChildNodes();
0457: int len = list.getLength();
0458: for (int i = 0; i < len; i++) {
0459: org.w3c.dom.Node child = list.item(i);
0460: if (child.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
0461: Element element = (Element) child;
0462: if (tag.equals(element.getTagName()))
0463: return element;
0464: }
0465: }
0466: if (create) {
0467: Document document = parent.getOwnerDocument();
0468: Element element = document.createElement(tag);
0469: parent.appendChild(element);
0470: return element;
0471: }
0472: return null;
0473: }
0474:
0475: /**
0476: * Find the given tag anywhere in the subtree of the given node
0477: * (possibly including the node itself).
0478: * @param tag The name of the tag element to be found
0479: * @param node The root node to begin the search
0480: * @return The first element in the node tree with the given tag name
0481: */
0482: public static Element findDescendant(String tag, Node node) {
0483: if (node.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
0484: Element element = (Element) node;
0485: if (tag.equals(element.getTagName()))
0486: return element;
0487: }
0488: NodeList list = node.getChildNodes();
0489: int len = list.getLength();
0490: for (int i = 0; i < len; i++) {
0491: org.w3c.dom.Node child = list.item(i);
0492: Element e = findDescendant(tag, child);
0493: if (e != null) {
0494: return e;
0495: }
0496: }
0497: return null;
0498: }
0499:
0500: public static List/*<FileObject>*/getWebPages(Project project,
0501: boolean includePages, boolean includeFragments) {
0502: List list = new ArrayList(20);
0503: FileObject fobj = JsfProjectUtils.getDocumentRoot(project);
0504: addWebPages(list, fobj, includePages, includeFragments);
0505:
0506: return list;
0507: }
0508:
0509: private static void addWebPages(List list, FileObject folder,
0510: boolean includePages, boolean includeFragments) {
0511: if (folder == null) {
0512: throw (new IllegalArgumentException("Null folder."));
0513: }
0514: if (list == null) {
0515: throw (new IllegalArgumentException("Null list."));
0516: }
0517:
0518: FileObject[] children = folder.getChildren();
0519:
0520: for (int i = 0; i < children.length; i++) {
0521: FileObject fo = children[i];
0522:
0523: if (fo.isFolder()) {
0524: addWebPages(list, fo, includePages, includeFragments);
0525: } else {
0526: if (isWebPage(fo)) {
0527: boolean isFragment = "jspf".equals(fo.getExt()); // NOI18N
0528:
0529: if (isFragment) {
0530: if (includeFragments) {
0531: list.add(fo);
0532: }
0533: } else if (includePages) {
0534: list.add(fo);
0535: }
0536: }
0537: }
0538: }
0539: }
0540:
0541: /**
0542: * The following mime types are valid mime types for files
0543: * that will be considered webforms in the WebAppProject
0544: */
0545: private static final String[] FORM_MIME_TYPES = new String[] { "text/x-jsp" }; // NOI18N
0546:
0547: public static boolean isWebPage(FileObject fo) {
0548: String mime = fo.getMIMEType();
0549:
0550: String[] mimeTypes = FORM_MIME_TYPES;
0551:
0552: for (int i = 0; i < mimeTypes.length; i++) {
0553: if (mimeTypes[i].equals(mime)
0554: && FacesModel.getJavaForJsp(fo) != null) {
0555: return true;
0556: }
0557: }
0558:
0559: return false;
0560: }
0561:
0562: public static String[] getMimeTypes() {
0563: return FORM_MIME_TYPES;
0564: }
0565:
0566: public static URL resolveUrl(URL base, Document document, String src) {
0567: if (src == null) {
0568: src = "";
0569: }
0570:
0571: // TODO after Reef: push this into superclass
0572: URL reference = null;
0573:
0574: // Relative to the web folder?
0575: if (src.startsWith("/")) { // NOI18N
0576:
0577: // What if it's a local file, e.g. /home/tor/foo.jspf?? that wouldn't work at deploy time anyway..
0578: try {
0579: // <markup_separation>
0580: // MarkupUnit markup = ((RaveDocument)document).getMarkup();
0581: // FileObject fo = markup.getFileObject();
0582: // ====
0583: FileObject fo = getFileObject(document);
0584: // </markup_separation>
0585: Project project = FileOwnerQuery.getOwner(fo);
0586:
0587: if (project != null) {
0588: FileObject webroot = JsfProjectUtils
0589: .getDocumentRoot(project);
0590: reference = FileUtil.toFile(webroot).toURI()
0591: .toURL();
0592: }
0593:
0594: src = src.substring(1); // strip off leading "/" or URL class will ignore base
0595: } catch (Exception ex) {
0596: reference = base;
0597: }
0598: } else {
0599: reference = base;
0600: }
0601:
0602: try {
0603: URL u = new URL(reference, src); // XXX what if it's absolute?
0604:
0605: return u;
0606: } catch (MalformedURLException ex) {
0607: ErrorManager.getDefault().notify(
0608: ErrorManager.INFORMATIONAL, ex);
0609:
0610: return null;
0611: }
0612: }
0613:
0614: public static FileObject getFileObject(Document doc) {
0615: MarkupUnit unit = MarkupUnit.getMarkupUnitForDocument(doc);
0616: if (unit == null) {
0617: return null;
0618: }
0619: return unit.getFileObject();
0620: }
0621:
0622: public static void customizeCreation(DesignBean[] beans,
0623: FacesModel facesModel) {
0624: for (int i = 0; i < beans.length; i++) {
0625: DesignBean lb = beans[i];
0626: DesignInfo lbi = lb.getDesignInfo();
0627:
0628: if (lbi != null) {
0629: Customizer2 customizer = null; //lbi.getCreateCustomizer(lb);
0630:
0631: if (customizer != null) {
0632: CustomizerDisplayer lcd = new CustomizerDisplayer(
0633: lb, customizer, customizer.getHelpKey(),
0634: facesModel);
0635: lcd.show();
0636: }
0637: }
0638: }
0639: }
0640:
0641: // Moved from FacesDnDSupport.
0642: /**
0643: * Return true iff the given DesignBean is the body bean, or the form bean, OR THE LIVE BEAN
0644: * CONTAINER. These beans have special behavior since they are not draggable, not deletable,
0645: * etc.
0646: * TODO Move this into insync.
0647: * @todo Prevent deletion of f:subview in page fragments!
0648: */
0649: public static boolean isSpecialBean(
0650: /*WebForm webform,*/DesignBean bean) {
0651: // FacesModel model = webform.getModel();
0652: if (bean == null) {
0653: // XXX Log NPE?
0654: return false;
0655: }
0656: DesignContext context = bean.getDesignContext();
0657: // XXX Casting is error-prone.
0658: FacesModel model = ((LiveUnit) context).getModel();
0659: if (model == null) {
0660: // XXX #6469393 Possible NPE.
0661: return false;
0662: }
0663:
0664: if (bean == model.getRootBean()) {
0665: return true;
0666: }
0667:
0668: FacesPageUnit facesUnit = model.getFacesUnit();
0669:
0670: if (facesUnit != null) {
0671: MarkupBean formBean = facesUnit.getDefaultParent();
0672: MarkupBean markup = getMarkupBean(bean);
0673:
0674: if (markup == null) {
0675: return false;
0676: }
0677:
0678: if (markup == formBean) {
0679: return true;
0680: }
0681:
0682: // RaveElement e = (RaveElement)markup.getElement();
0683: // if (e.getRendered() != null) {
0684: // e = (RaveElement)e.getRendered();
0685: Element e = markup.getElement();
0686: Element rendered = MarkupService
0687: .getRenderedElementForElement(e);
0688: if (rendered != null) {
0689: e = rendered;
0690:
0691: // Anything from the body or up is special -- cannot be removed
0692: // Node curr = webform.getBody();
0693: Node curr = InSyncServiceProvider
0694: .get()
0695: .getHtmlBodyForMarkupFile(model.getMarkupFile());
0696:
0697: while (curr != null) {
0698: if (curr == e) {
0699: return true;
0700: }
0701:
0702: curr = curr.getParentNode();
0703: }
0704: } else {
0705: // Anything from the body or up is special -- cannot be removed
0706: // Node curr = webform.getBody().getSource();
0707: Element body = InSyncServiceProvider
0708: .get()
0709: .getHtmlBodyForMarkupFile(model.getMarkupFile());
0710: Node curr = MarkupService
0711: .getSourceElementForElement(body);
0712:
0713: while (curr != null) {
0714: if (curr == e) {
0715: return true;
0716: }
0717:
0718: curr = curr.getParentNode();
0719: }
0720: }
0721: }
0722:
0723: return false;
0724: }
0725:
0726: // Moved from FacesDnDSupport.
0727: /**
0728: * Return the MarkupBean for the live bean. May be null, for non markup live beans.
0729: *
0730: * @param lb The live bean to get the faces bean for. May be null.
0731: * @return the MarkupBean corresponding to the live bean, or null.
0732: */
0733: public static MarkupBean getMarkupBean(DesignBean lb) {
0734: if (!(lb instanceof BeansDesignBean)) {
0735: return null;
0736: }
0737:
0738: Bean b = ((BeansDesignBean) lb).getBean();
0739:
0740: if (b instanceof MarkupBean) {
0741: return (MarkupBean) b;
0742: }
0743:
0744: return null;
0745: }
0746:
0747: /** Strip the given string to the given maximum length of
0748: * characters. If the string is not that long, just return
0749: * it. If it needs to be truncated, truncate it and append
0750: * "...". maxLength must be at least 4. */
0751: public static String truncateString(String s, int maxLength) {
0752: assert maxLength >= 4;
0753:
0754: // if(DEBUG) {
0755: // debugLog(DesignerUtils.class.getName() + ".truncateString(String, int)");
0756: // }
0757: if (s == null) {
0758: throw (new IllegalArgumentException(
0759: "Null string to truncate."));// NOI18N
0760: }
0761:
0762: if (s.length() > maxLength) {
0763: // Should "..." be localizable?
0764: return s.substring(0, maxLength - 3) + "...";
0765: } else {
0766: return s;
0767: }
0768: }
0769:
0770: // Moved from FacesDnDSupport.
0771: public static DesignBean findParent(String className,
0772: DesignBean droppee, Node parentNode, boolean searchUp,
0773: FacesModel facesModel) {
0774: if (isGridMode(facesModel) && (droppee == null)
0775: && (facesModel.getLiveUnit() != null)) {
0776: MarkupBean bean = facesModel.getFacesUnit()
0777: .getDefaultParent();
0778:
0779: if (bean != null) {
0780: droppee = facesModel.getLiveUnit().getDesignBean(bean);
0781: }
0782: }
0783:
0784: DesignBean parent = droppee;
0785:
0786: if (searchUp) {
0787: for (; (parent != null) && !parent.isContainer(); parent = parent
0788: .getBeanParent()) {
0789: ;
0790: }
0791: }
0792:
0793: LiveUnit unit = facesModel.getLiveUnit();
0794:
0795: if (searchUp) {
0796: boolean isHtmlBean = className.startsWith(HtmlBean.PACKAGE)
0797: &&
0798: // f:verbatim is explicitly allowed where jsf components can go
0799: // XXX Why not F_Verbatim.class.getName() ?
0800: !(HtmlBean.PACKAGE + "F_Verbatim")
0801: .equals(className); // NOI18N
0802:
0803: if (isHtmlBean) {
0804: // We can't drop anywhere below a "renders children" JSF
0805: // component
0806: parent = findHtmlContainer(parent);
0807: }
0808: }
0809:
0810: // Validate the parent: walk up the parent chain until you find
0811: // a parent which will accept the child.
0812: for (; parent != null; parent = parent.getBeanParent()) {
0813: if (unit.canCreateBean(className, parent, null)) {
0814: // Found it
0815: break;
0816: }
0817:
0818: if (!searchUp) {
0819: return null;
0820: }
0821: }
0822:
0823: if ((parent == null) && (parentNode != null)) {
0824: // Adjust hierarchy: we should pass in a parent
0825: // pointer based on where we are: locate the closest
0826: // jsf parent above
0827: Node n = parentNode;
0828: MarkupBean mb = null;
0829:
0830: while (n != null) {
0831: if (n instanceof Element) {
0832: Element e = (Element) n;
0833: // mb = FacesSupport.getMarkupBean(webform.getDocument(), e);
0834: mb = getMarkupBean(facesModel, e);
0835:
0836: if (mb != null) {
0837: break;
0838: }
0839: }
0840:
0841: n = n.getParentNode();
0842: }
0843:
0844: if (mb != null) {
0845: DesignBean lmb = facesModel.getLiveUnit()
0846: .getDesignBean(mb);
0847:
0848: if (lmb.isContainer()) {
0849: parent = lmb;
0850: }
0851: }
0852:
0853: if (parent == null) {
0854: parent = facesModel.getRootBean();
0855: }
0856: }
0857:
0858: return parent;
0859: }
0860:
0861: // Moved from FacesDnDSupport.
0862: /**
0863: * Return true if this document is in "grid mode" (objects
0864: * should be positioned by absolute coordinates instead of in
0865: * "flow" order.
0866: *
0867: * @return true iff the document should be in grid mode
0868: */
0869: public static boolean isGridMode(FacesModel facesModel) {
0870: Element b = facesModel.getHtmlBody();
0871:
0872: if (b == null) {
0873: return false;
0874: }
0875:
0876: // Value val = CssLookup.getValue(b, XhtmlCss.RAVELAYOUT_INDEX);
0877: CssValue cssValue = CssProvider.getEngineService()
0878: .getComputedValueForElement(b,
0879: XhtmlCss.RAVELAYOUT_INDEX);
0880:
0881: // return val == CssValueConstants.GRID_VALUE;
0882: return CssProvider.getValueService().isGridValue(cssValue);
0883: }
0884:
0885: // Moved from FacesDnDSupport.
0886: /**
0887: * Find the nearest DesignBean container that allows html children.
0888: * This will typically be the parent you pass in, but if there
0889: * are any beans up in the hierarchy that renders their own
0890: * children, then the outermost such parent's parent will be used,
0891: * since "renders children" jsf components cannot contain markup.
0892: */
0893: public static DesignBean findHtmlContainer(DesignBean parent) {
0894: DesignBean curr = parent;
0895:
0896: for (; curr != null; curr = curr.getBeanParent()) {
0897: if (curr.getInstance() instanceof F_Verbatim) {
0898: // If you have a verbatim, we're okay to add html comps below it
0899: return parent;
0900: }
0901:
0902: if (curr.getInstance() instanceof UIComponent) {
0903: // XXX Maybe now, whitin insync one could provide a better check for the classloader.
0904:
0905: // Need to set the Thread's context classloader to be the Project's ClassLoader.
0906: ClassLoader oldContextClassLoader = Thread
0907: .currentThread().getContextClassLoader();
0908: try {
0909: Thread.currentThread().setContextClassLoader(
0910: InSyncServiceProvider.get()
0911: .getContextClassLoader(curr));
0912: if (((UIComponent) curr.getInstance())
0913: .getRendersChildren()) {
0914: parent = curr.getBeanParent();
0915:
0916: // Can't break here - there could be an outer
0917: // renders-children parent
0918: }
0919: } finally {
0920: Thread.currentThread().setContextClassLoader(
0921: oldContextClassLoader);
0922: }
0923: }
0924: }
0925:
0926: return parent;
0927: }
0928:
0929: // Moved from FacesDnDSupport.
0930: /**
0931: * Given an element which possibly maps to a markup bean, return the corresponding bean.
0932: */
0933: private static MarkupBean getMarkupBean(FacesModel model,
0934: Element elem) {
0935: // FacesModel model = doc.getWebForm().getModel();
0936:
0937: if (model == null) { // testsuite
0938: return null;
0939: }
0940:
0941: FacesPageUnit facesunit = model.getFacesUnit();
0942: MarkupBean bean = null;
0943:
0944: if (facesunit != null) {
0945: bean = facesunit.getMarkupBean(elem);
0946: // Find component for this element:
0947: }
0948:
0949: return bean;
0950: }
0951:
0952: // Moved from FacesDnDSupport.
0953: /** Given a node, return the nearest DesignBean that "contains" it */
0954: public/*private*/static DesignBean findParentBean(Node node) {
0955: while (node != null) {
0956: // if (node instanceof RaveElement) {
0957: // RaveElement element = (RaveElement)node;
0958: if (node instanceof Element) {
0959: Element element = (Element) node;
0960:
0961: // if (element.getDesignBean() != null) {
0962: // return element.getDesignBean();
0963: // }
0964: MarkupDesignBean markupDesignBean = InSyncServiceProvider
0965: .get().getMarkupDesignBeanForElement(element);
0966: if (markupDesignBean != null) {
0967: return markupDesignBean;
0968: }
0969: }
0970:
0971: node = node.getParentNode();
0972: }
0973:
0974: return null;
0975: }
0976:
0977: // Moved from FacesDnDSupport.
0978: /** Attempt to set the given attribute on the bean to the given length
0979: * and return true iff it succeeds.
0980: */
0981: public static boolean setDesignProperty(DesignBean bean,
0982: String attribute, int length) {
0983: DesignProperty prop = bean.getProperty(attribute);
0984:
0985: if (prop != null) {
0986: PropertyDescriptor desc = prop.getPropertyDescriptor();
0987: Class clz = desc.getPropertyType();
0988:
0989: // I can do == instead of isAssignableFrom because
0990: // both String and Integer are final!
0991: if (clz == String.class) {
0992: prop.setValue(Integer.toString(length));
0993:
0994: return true;
0995: } else if (clz == Integer.TYPE) {
0996: prop.setValue(new Integer(length));
0997:
0998: return true;
0999: }
1000: }
1001:
1002: return false;
1003: }
1004:
1005: public static boolean isPageRootContainerDesignBean(
1006: DesignBean designBean) {
1007: // XXX Bad way how to determine this is bean representing Page (not Session, etc.).
1008: if (designBean instanceof SourceLiveRoot) {
1009: DesignContext designContext = designBean.getDesignContext();
1010: if (designContext instanceof LiveUnit) {
1011: LiveUnit liveUnit = (LiveUnit) designContext;
1012: FacesModel facesModel = liveUnit.getModel();
1013: if (facesModel != null
1014: && facesModel.getMarkupFile() != null) {
1015: return true;
1016: }
1017: }
1018: }
1019: return false;
1020: }
1021:
1022: /**
1023: * Generate the html string from the given node. This will return
1024: * an empty string unless the Node is an Element or a DocumentFragment
1025: * or a Document.
1026: */
1027: public static String getHtmlStream(org.w3c.dom.Node node) {
1028: if (node.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
1029: return getHtmlStream((Element) node);
1030: } else if (node.getNodeType() == org.w3c.dom.Node.DOCUMENT_FRAGMENT_NODE) {
1031: return getHtmlStream((DocumentFragment) node);
1032: } else if (node.getNodeType() == org.w3c.dom.Node.DOCUMENT_NODE) {
1033: return getHtmlStream((org.w3c.dom.Document) node);
1034: } else if ((node.getNodeType() == org.w3c.dom.Node.TEXT_NODE)
1035: || (node.getNodeType() == org.w3c.dom.Node.CDATA_SECTION_NODE)) {
1036: return node.getNodeValue();
1037: } else {
1038: return ""; // NOI18N
1039: }
1040: }
1041:
1042: /** Generate the html string from the given element */
1043: public static String getHtmlStream(Element element) {
1044: StringWriter w = new StringWriter(); // XXX initial size?
1045: OutputFormat format = new OutputFormat(element
1046: .getOwnerDocument(), null, true); // default enc, do-indent
1047: format.setLineWidth(160);
1048: format.setIndent(4);
1049:
1050: JspxSerializer serializer = new JspxSerializer(w, format);
1051:
1052: try {
1053: serializer.serialize(element);
1054: } catch (java.io.IOException ex) {
1055: ErrorManager.getDefault().notify(
1056: ErrorManager.INFORMATIONAL, ex);
1057: }
1058:
1059: return w.getBuffer().toString();
1060: }
1061:
1062: /** Generate the html string from the given element. Does formatting. */
1063: public static String getHtmlStream(org.w3c.dom.Document document) {
1064: StringWriter w = new StringWriter(); // XXX initial size?
1065: // Bug Fix# 6452255 Source File error Fix HTML errors removes UTF-8 encoding in JSP
1066: // Use the document encoding from the original document
1067: OutputFormat format = new OutputFormat(document, document
1068: .getXmlEncoding(), true); // do-indent
1069: format.setLineWidth(160);
1070: format.setIndent(4);
1071:
1072: JspxSerializer serializer = new JspxSerializer(w, format);
1073:
1074: try {
1075: serializer.serialize(document);
1076: } catch (java.io.IOException ex) {
1077: ErrorManager.getDefault().notify(
1078: ErrorManager.INFORMATIONAL, ex);
1079: }
1080:
1081: return w.getBuffer().toString();
1082: }
1083:
1084: /** Generate the html string from the given document fragment */
1085: public static String getHtmlStream(DocumentFragment df) {
1086: OutputFormat format = new OutputFormat(df.getOwnerDocument()); // default enc, do-indent
1087: format.setLineWidth(160);
1088: format.setIndent(4);
1089:
1090: StringWriter w = new StringWriter(); // XXX initial size?
1091: JspxSerializer serializer = new JspxSerializer(w, format);
1092:
1093: try {
1094: serializer.serialize(df);
1095: } catch (java.io.IOException ex) {
1096: ErrorManager.getDefault().notify(
1097: ErrorManager.INFORMATIONAL, ex);
1098: }
1099:
1100: return w.getBuffer().toString();
1101: }
1102:
1103: public static boolean isBraveheartPage(Document dom) {
1104: if (dom == null) {
1105: return false;
1106: }
1107: // Many possibilities here:
1108: // (1) Scan through all tags, look to see if we find any ui: tags
1109: // (2) Look on the jsp:root, see if we include the braveheart taglib
1110: // (3) See if the top most tag under f:view is a braveheart one
1111: // (4) See if the body is a plain html <body> tag or if it's rendered from
1112: // another component
1113: Element element = dom.getDocumentElement();
1114:
1115: if (element.hasAttribute("xmlns:ui")) { // NOI18N
1116: assert element.getAttribute("xmlns:ui").equals(
1117: "http://www.sun.com/web/ui"); // NOI18N
1118:
1119: return true;
1120: }
1121:
1122: return false;
1123: }
1124:
1125: public static boolean isWoodstockPage(Document dom) {
1126: if (dom == null) {
1127: return false;
1128: }
1129: // Many possibilities here:
1130: // (1) Scan through all tags, look to see if we find any ui: tags
1131: // (2) Look on the jsp:root, see if we include the braveheart taglib
1132: // (3) See if the top most tag under f:view is a braveheart one
1133: // (4) See if the body is a plain html <body> tag or if it's rendered from
1134: // another component
1135: Element element = dom.getDocumentElement();
1136:
1137: if (element.hasAttribute("xmlns:webuijsf")) { // NOI18N
1138: assert element.getAttribute("xmlns:webuijsf").equals(
1139: "http://www.sun.com/webui/webuijsf"); // NOI18N
1140:
1141: return true;
1142: }
1143:
1144: return false;
1145: }
1146:
1147: ///////////////////////////////////
1148: // CSS style sheet modifications >>
1149:
1150: public static void addLocalStyleValueForElement(Element element,
1151: int style, String value) {
1152: List set = new ArrayList(1);
1153: set.add(new StyleData(style, value));
1154: updateLocalStyleValuesForElement(element, (StyleData[]) set
1155: .toArray(new StyleData[set.size()]), null);
1156: }
1157:
1158: public static void removeLocalStyleValueForElement(Element element,
1159: int style) {
1160: List remove = new ArrayList(1);
1161: remove.add(new StyleData(style));
1162: updateLocalStyleValuesForElement(element, null,
1163: (StyleData[]) remove.toArray(new StyleData[remove
1164: .size()]));
1165: }
1166:
1167: public static void updateLocalStyleValuesForElement(
1168: Element element, StyleData[] stylesToSet,
1169: StyleData[] stylesToRemove) {
1170: try {
1171: // String value = engine.getUpdatedLocalStyleValues(element, set, remove);
1172: String value = CssProvider.getEngineService()
1173: .getUpdatedLocalStyleValuesForElement(element,
1174: stylesToSet, stylesToRemove);
1175:
1176: // if (element instanceof RaveElement) {
1177: // RaveElement raveElement = (RaveElement)element;
1178: //// DesignBean markupBean = raveElement.getDesignBean();
1179: // DesignBean markupBean = InSyncService.getProvider().getMarkupDesignBeanForElement(raveElement);
1180: if (element != null) {
1181: // DesignBean markupBean = InSyncService.getProvider().getMarkupDesignBeanForElement(element);
1182: DesignBean markupBean = MarkupUnit
1183: .getMarkupDesignBeanForElement(element);
1184: if (markupBean != null) {
1185: DesignProperty property = markupBean
1186: .getProperty(HtmlAttribute.STYLE);
1187: if (property != null) {
1188: try {
1189: if ((value != null) && (value.length() > 0)) {
1190: property.setValue(value);
1191: } else {
1192: property.unset();
1193: }
1194:
1195: return;
1196: } catch (Exception ex) {
1197: ErrorManager.getDefault().notify(
1198: ErrorManager.INFORMATIONAL, ex);
1199: // For some reason the above throws exceptions
1200: // sometimes, not sure why org.w3c.dom.DOMException:
1201: // NOT_FOUND_ERR: An attempt is made to reference a
1202: // node in a context where it does not exist. TODO
1203: // - figure out WHY! For now just swallow since
1204: // there's nothing more we can do about it.
1205: // (Update: It think this may be fixed now)
1206: }
1207: }
1208: }
1209: }
1210:
1211: // If the above fails (shouldn't)
1212: // engine.setStyleAttributeValue(element, value);
1213: CssProvider.getEngineService().setStyleAttributeForElement(
1214: element, value);
1215: } catch (Exception ex) {
1216: ErrorManager.getDefault().notify(
1217: ErrorManager.INFORMATIONAL, ex);
1218: }
1219: }
1220:
1221: // CSS style sheet modifications <<
1222: ///////////////////////////////////
1223:
1224: // XXX Moved from InSyncServiceProvider.
1225: public static String computeFileName(Object location) {
1226: if (location instanceof String) {
1227: return (String) location;
1228: } else if (location instanceof URL) {
1229: // <markup_separation>
1230: // return MarkupUnit.fromURL(((URL)location).toExternalForm());
1231: // ====
1232: return fromURL(((URL) location).toExternalForm());
1233: // </markup_separation>
1234: } else if (location instanceof Element) {
1235: // Locate the filename for a given element
1236: Element element = (Element) location;
1237: element = MarkupService
1238: .getCorrespondingSourceElement(element);
1239:
1240: // <markup_separation>
1241: // // XXX I should derive this from the engine instead, after all
1242: // // the engine can know the unit! (Since engines cannot be used
1243: // // with multiple DOMs anyway)
1244: // FileObject fo = unit.getFileObject();
1245: // ====
1246: FileObject fo = getFileObject(element.getOwnerDocument());
1247: // </markup_separation>
1248: File f = FileUtil.toFile(fo);
1249:
1250: return f.toString();
1251: } else if (location != null) {
1252: return location.toString();
1253: }
1254:
1255: return "";
1256: }
1257:
1258: // XXX Moved from InSyncServiceProvider.
1259: public static int computeLineNumber(Object location, int lineno) {
1260: if (location instanceof Element) {
1261: /*
1262: // The location is an XhtmlElement -- so the line number
1263: // needs to be relative to it.... compute the line number
1264: // of the element
1265: if (lineno == -1)
1266: lineno = 0;
1267: Element element = (Element)location;
1268: RaveDocument doc = (RaveDocument)element.getOwnerDocument();
1269: lineno += doc.getLineNumber(element);
1270: */
1271: if (lineno == -1) {
1272: lineno = 0;
1273: }
1274:
1275: Element element = (Element) location;
1276: element = MarkupService
1277: .getCorrespondingSourceElement(element);
1278: // <markup_separation>
1279: // lineno += unit.computeLine(element);
1280: // ====
1281: lineno += computeLine(element.getOwnerDocument(), element);
1282: // </markup_separation>
1283: }
1284:
1285: return lineno;
1286: }
1287:
1288: // XXX Moved from InSyncServiceProvider.
1289: public static int computeLine(Document doc, Element element) {
1290: MarkupUnit unit = MarkupUnit.getMarkupUnitForDocument(doc);
1291: if (unit == null) {
1292: return 0;
1293: }
1294: return unit.computeLine(element);
1295: }
1296:
1297: // XXX Moved from InSyncServiceProvider.
1298: public static String fromURL(String url) {
1299: if (url.startsWith("file:")) { // NOI18N
1300: int n = url.length();
1301: StringBuffer sb = new StringBuffer(n);
1302: for (int i = 5; i < n; i++) {
1303: char c = url.charAt(i);
1304: // TODO -- any File.separatorChar manipulation perhaps?
1305: if (c == '%' && i < n - 3) {
1306: char d1 = url.charAt(i + 1);
1307: char d2 = url.charAt(i + 2);
1308: if (Character.isDigit(d1) && Character.isDigit(d2)) {
1309: String numString = "" + d1 + d2;
1310: try {
1311: int num = Integer.parseInt(numString, 16);
1312: if (num >= 0 && num <= 255) {
1313: sb.append((char) num);
1314: i += 2;
1315: continue;
1316: }
1317: } catch (NumberFormatException nex) {
1318: ErrorManager.getDefault().notify(
1319: ErrorManager.INFORMATIONAL, nex);
1320: }
1321: }
1322: sb.append(c);
1323: } else {
1324: sb.append(c);
1325: }
1326: }
1327: return sb.toString();
1328: }
1329: return url;
1330: }
1331:
1332: // XXX Moved from InSyncServiceProvider.
1333: public static URL getDocumentUrl(Document doc) {
1334: // if (!(doc instanceof RaveDocument)) {
1335: // return null;
1336: // }
1337: if (doc == null) {
1338: return null;
1339: }
1340:
1341: // RaveDocument rDoc = (RaveDocument)doc;
1342: // <removing set/getRoot from RaveDocument>
1343: // DesignProject designProject = rDoc.getRoot().getDesignBean().getDesignContext().getProject();
1344: MarkupUnit unit = MarkupUnit.getMarkupUnitForDocument(doc);
1345: DesignProject designProject;
1346: if (unit != null) {
1347: FacesModel facesModel = FacesModel.getInstance(unit
1348: .getFileObject());
1349: designProject = ((DesignContext) facesModel.getLiveUnit())
1350: .getProject();
1351: } else {
1352: designProject = null;
1353: }
1354: // <removing set/getRoot from RaveDocument>
1355: if (designProject instanceof FacesModelSet) {
1356: FacesModelSet fModelSet = (FacesModelSet) designProject;
1357: FileObject documentRoot = JsfProjectUtils
1358: .getDocumentRoot(fModelSet.getProject());
1359: try {
1360: return documentRoot.getURL();
1361: } catch (FileStateInvalidException fsie) {
1362: ErrorManager.getDefault().notify(
1363: ErrorManager.INFORMATIONAL, fsie);
1364: }
1365: }
1366:
1367: return null;
1368: }
1369:
1370: ////////////////////
1371: // Error Handling >>
1372: private static boolean clearErrors = false;
1373:
1374: public static void clearErrors(boolean delayed) {
1375: if (delayed) {
1376: clearErrors = true;
1377: } else {
1378: OutputWriter out = getOutputWriter();
1379: try {
1380: out.reset();
1381: } catch (IOException ioe) {
1382: // This is lame - our own output window shouldn't
1383: // throw IO exceptions!
1384: ErrorManager.getDefault().notify(ioe);
1385: }
1386: }
1387: }
1388:
1389: public static void selectErrors() {
1390: InputOutput io = getInputOutput();
1391: io.select();
1392: }
1393:
1394: public static void displayErrorForLocation(String message,
1395: Object location, int line, int column) {
1396: String fileName = InSyncServiceProvider.get().computeFileName(
1397: location);
1398: line = InSyncServiceProvider.get().computeLineNumber(location,
1399: line);
1400:
1401: // XXX There was no file found.
1402: if (fileName == null || "".equals(fileName)) { // NOI18N
1403: displayError(message, new DummyOutputListener());
1404: } else {
1405: File file = new File(fileName);
1406: FileObject fo = FileUtil.toFileObject(file);
1407:
1408: displayErrorForFileObject(message, fo,
1409: line >= 1 ? line : 1, column);
1410: }
1411: }
1412:
1413: public static void displayErrorForFileObject(String message,
1414: final FileObject fileObject, final int line,
1415: final int column) {
1416: // final XhtmlElement e = Util.getSource(element);
1417: OutputListener listener = new OutputListener() {
1418: public void outputLineSelected(OutputEvent ev) {
1419: }
1420:
1421: public void outputLineAction(OutputEvent ev) {
1422: // Util.show(null, unit.getFileObject(), unit.getLine(e),
1423: // 0, true);
1424: // <markup_separation>
1425: // Util.show(null, fileObject, lineNumber, 0, true);
1426: // ====
1427: if (fileObject != null) {
1428: showLineAt(fileObject, line, column);
1429: }
1430: // </markup_separation>
1431: }
1432:
1433: public void outputLineCleared(OutputEvent ev) {
1434: }
1435: };
1436:
1437: // XXX There needs to be a non-null listener.
1438: displayError(message, listener);
1439: }
1440:
1441: /**
1442: * Display the given error message to the user. The optional listener argument
1443: * (pass in null if not applicable) will make the line hyperlinked and the
1444: * listener is invoked to process any user clicks.
1445: * @param message The string to be displayed to the user
1446: * @param listener null, or a listener to be notified when the user clicks
1447: * the linked message
1448: */
1449: private static void displayError(String message,
1450: OutputListener listener) {
1451: OutputWriter out = getOutputWriter();
1452: try {
1453: if (clearErrors) {
1454: out.reset();
1455: clearErrors = false;
1456: }
1457:
1458: if (listener == null) {
1459: // #107754 Now the null is not accepted as a listener.
1460: listener = new DummyOutputListener();
1461: }
1462:
1463: // Write the error message to the output tab:
1464: out.println(message, listener);
1465: } catch (IOException ioe) {
1466: // This is lame - our own output window shouldn't throw IO exceptions!
1467: ErrorManager.getDefault().notify(ioe);
1468: }
1469: }
1470:
1471: private static void showLineAt(FileObject fo, int lineno, int column) {
1472: DataObject dobj;
1473: try {
1474: dobj = DataObject.find(fo);
1475: } catch (DataObjectNotFoundException ex) {
1476: ErrorManager.getDefault().notify(ex);
1477: return;
1478: }
1479:
1480: // Try to open doc before showing the line. This SHOULD not be
1481: // necessary, except without this the IDE hangs in its attempt
1482: // to open the file when the file in question is a CSS file.
1483: // Probably a bug in the xml/css module's editorsupport code.
1484: // This has the negative effect of first flashing the top
1485: // of the file before showing the destination line, so
1486: // this operation is made conditional so only clients who
1487: // actually need it need to use it.
1488: EditorCookie ec = (EditorCookie) dobj
1489: .getCookie(EditorCookie.class);
1490: if (ec != null) {
1491: try {
1492: ec.openDocument(); // ensure that it has been opened - REDUNDANT?
1493: //ec.open();
1494: } catch (IOException ex) {
1495: ErrorManager.getDefault().notify(ex);
1496: }
1497: }
1498:
1499: LineCookie lc = (LineCookie) dobj.getCookie(LineCookie.class);
1500: if (lc != null) {
1501: Line.Set ls = lc.getLineSet();
1502: if (ls != null) {
1503: // -1: convert line numbers to be zero-based
1504: Line line = ls.getCurrent(lineno - 1);
1505: // TODO - pass in a column too?
1506: line.show(Line.SHOW_GOTO, column);
1507: }
1508: }
1509: }
1510:
1511: private static InputOutput getInputOutput() {
1512: return IOProvider.getDefault().getIO(
1513: NbBundle.getMessage(Util.class, "LBL_Output"), false);
1514: }
1515:
1516: private static OutputWriter getOutputWriter() {
1517: InputOutput io = getInputOutput();
1518: return io.getOut();
1519: }
1520:
1521: // Error Handling <<
1522: ////////////////////
1523:
1524: public static Element getHtmlBodyForMarkupFile(FileObject markupFile) {
1525: FacesModel facesModel = FacesModel.getInstance(markupFile);
1526: if (facesModel == null) {
1527: return null;
1528: } else {
1529: return facesModel.getHtmlBody();
1530: }
1531: }
1532:
1533: public static Element getHtmlBodyForDocument(Document document) {
1534: FileObject markupFile = getFileObject(document);
1535: if (markupFile == null) {
1536: return null;
1537: } else {
1538: return getHtmlBodyForMarkupFile(markupFile);
1539: }
1540: }
1541:
1542: public static DocumentFragment getHtmlDomFragmentForDocument(
1543: Document document) {
1544: FileObject markupFile = getFileObject(document);
1545: if (markupFile == null) {
1546: return null;
1547: }
1548:
1549: FacesModel facesModel = FacesModel.getInstance(markupFile);
1550: if (facesModel == null) {
1551: return null;
1552: } else {
1553: return facesModel.getHtmlDomFragment();
1554: }
1555: }
1556:
1557: /**
1558: * Return true iff the given DesignBean is the form bean for this form OR THE LIVE BEAN CONTAINER,
1559: * since it acts like the form bean in many ways (not draggable, not deletable, etc.)
1560: */
1561: public static boolean isFormBean(FacesModel facesModel,
1562: DesignBean bean) {
1563: // FacesModel model = webform.getModel();
1564:
1565: if (bean == facesModel.getRootBean()) {
1566: return true;
1567: }
1568:
1569: FacesPageUnit facesUnit = facesModel.getFacesUnit();
1570: MarkupBean formBean = facesUnit.getDefaultParent();
1571:
1572: return getFacesBean(bean) == formBean;
1573: }
1574:
1575: /**
1576: * Return the FacesBean for the live bean. May be null, for non faces live beans.
1577: *
1578: * @param lb The live bean to get the faces bean for. May be null.
1579: * @return the FacesBean corresponding to the live bean, or null.
1580: */
1581: public static FacesBean getFacesBean(DesignBean lb) {
1582: if (!(lb instanceof BeansDesignBean)) {
1583: return null;
1584: }
1585:
1586: Bean b = ((BeansDesignBean) lb).getBean();
1587:
1588: if (b instanceof FacesBean) {
1589: return (FacesBean) b;
1590: }
1591:
1592: return null;
1593: }
1594:
1595: /**
1596: * Return the element for the live bean. May be null, for non faces beans for example.
1597: */
1598: public static Element getElement(DesignBean lb) {
1599: if (lb instanceof MarkupDesignBean) {
1600: return ((MarkupDesignBean) lb).getElement();
1601: } else {
1602: return null;
1603: }
1604: }
1605:
1606: private static class DummyOutputListener implements OutputListener {
1607: public void outputLineSelected(OutputEvent ev) {
1608: // No op.
1609: }
1610:
1611: public void outputLineAction(OutputEvent ev) {
1612: // No op.
1613: }
1614:
1615: public void outputLineCleared(OutputEvent ev) {
1616: // No op.
1617: }
1618: } // DummyOutputListener.
1619: }
|