001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.visualweb.xhtml;
042:
043: import org.netbeans.modules.visualweb.api.designer.cssengine.CssProvider;
044: import org.netbeans.modules.visualweb.api.insync.InSyncService;
045: import org.netbeans.modules.visualweb.api.insync.InSyncService.WriteLock;
046: import java.util.ArrayList;
047: import org.openide.util.NbBundle;
048: import org.w3c.dom.Element;
049: import org.w3c.dom.Node;
050: import org.w3c.dom.NodeList;
051:
052: import com.sun.rave.designtime.DisplayAction;
053: import com.sun.rave.designtime.DesignBean;
054: import com.sun.rave.designtime.DesignContext;
055: import com.sun.rave.designtime.DesignProperty;
056: import com.sun.rave.designtime.Result;
057: import com.sun.rave.designtime.impl.BasicDisplayAction;
058: import com.sun.rave.designtime.markup.MarkupDesignBean;
059: import com.sun.rave.designtime.markup.MarkupTableDesignInfo;
060: import org.netbeans.modules.visualweb.api.designerapi.DesignerServiceHack;
061: import org.netbeans.modules.visualweb.designer.html.HtmlAttribute;
062: import org.netbeans.modules.visualweb.designer.html.HtmlTag;
063:
064: /**
065: * DesignInfo for the Table component
066: *
067: * @author Tor Norbye
068: */
069:
070: public class TableDesignInfo extends XhtmlDesignInfo implements
071: MarkupTableDesignInfo {
072:
073: public Class getBeanClass() {
074: return Table.class;
075: }
076:
077: public Result beanCreatedSetup(DesignBean bean) {
078: try {
079: DesignContext context = bean.getDesignContext();
080:
081: // set the border to 1
082: DesignProperty borderProp = bean.getProperty("border"); // NOI18N
083: if (borderProp != null) {
084: //borderProp.setValue(new Integer(1));
085: borderProp.setValue("1"); // NOI18N
086: }
087:
088: DesignProperty styleProp = bean.getProperty("style"); // NOI18N
089: if (styleProp != null) {
090: String size = "width: 400px"; // NOI18N
091: String style = (String) styleProp.getValue();
092: // Special case: don't override width already set (could
093: // be positioned by designer etc.)
094: if (style != null && style.length() > 0) {
095: styleProp.setValue(style + "; " + size); // NOI18N
096: } else {
097: styleProp.setValue(size);
098: }
099: }
100:
101: // create an initial 3x3 grid of cells
102: for (int i = 0; i < 3; i++) {
103: DesignBean row = context.createBean(Tr.class.getName(),
104: bean, null);
105: if (row != null) {
106: for (int j = 0; j < 3; j++)
107: addTableCell(row);
108: }
109: }
110: } catch (Exception x) {
111: x.printStackTrace();
112: }
113: return Result.SUCCESS;
114: }
115:
116: public DisplayAction[] getContextItems(DesignBean bean) {
117: assert bean instanceof MarkupDesignBean;
118: MarkupDesignBean mbean = (MarkupDesignBean) bean;
119: return new DisplayAction[] { new AddRowAction(mbean),
120: new AddColumnAction(mbean) };
121: }
122:
123: public class AddRowAction extends BasicDisplayAction {
124: private MarkupDesignBean table;
125:
126: public AddRowAction(MarkupDesignBean table) {
127: super (NbBundle.getMessage(TableDesignInfo.class, "AddRow")); // NOI18N
128: this .table = table;
129: }
130:
131: public Result invoke() {
132: DesignContext context = table.getDesignContext();
133: // LiveUnit unit = (LiveUnit)context;
134:
135: if (initialized != table) {
136: initialize(table);
137: if (tableData == null) {
138: return Result.FAILURE;
139: }
140: }
141:
142: // UndoEvent event = null;
143: WriteLock writeLock = null;
144: try {
145: // Insert after end instead?
146: // event = unit.getModel().writeLock(getDisplayName());
147: writeLock = InSyncService.getProvider()
148: .writeLockContext(context, getDisplayName());
149:
150: DesignBean row = context.createBean(Tr.class.getName(),
151: table, null);
152: if (row != null) {
153: for (int j = 0; j < columns; j++) {
154: DesignBean td = context.createBean(Td.class
155: .getName(), row, null);
156: addTableCellContents(td);
157: }
158: }
159: } finally {
160: // unit.getModel().writeUnlock(event);
161: InSyncService.getProvider().writeUnlockContext(context,
162: writeLock);
163: }
164: return Result.SUCCESS;
165: }
166: }
167:
168: public class AddColumnAction extends BasicDisplayAction {
169: private MarkupDesignBean table;
170:
171: public AddColumnAction(MarkupDesignBean table) {
172: super (NbBundle.getMessage(TableDesignInfo.class, "AddCol"));
173: this .table = table;
174: }
175:
176: public Result invoke() {
177: DesignContext context = table.getDesignContext();
178: // LiveUnit unit = (LiveUnit)context;
179:
180: // UndoEvent event = null;
181: WriteLock writeLock = null;
182: try {
183: // event = unit.getModel().writeLock(NbBundle.getMessage(TableDesignInfo.class, "AddCol")); // NOI18N
184: writeLock = InSyncService.getProvider()
185: .writeLockContext(
186: context,
187: NbBundle
188: .getMessage(
189: TableDesignInfo.class,
190: "AddCol"));
191:
192: // Iterate over each row and add a cell to each
193: // XXX This won't work with CSS tables! How about we go and "clone" the
194: // cells at the end of the table instead?
195: for (int i = 0, n = table.getChildBeanCount(); i < n; i++) {
196: DesignBean child = table.getChildBean(i);
197: java.lang.Object bean = child.getInstance();
198: if (bean instanceof Tr) {
199: addTableCell(child);
200: } else if (bean instanceof Tbody
201: || bean instanceof Tfoot
202: || bean instanceof Thead) {
203: DesignBean container = child;
204: for (int j = 0, m = container
205: .getChildBeanCount(); j < m; j++) {
206: DesignBean child2 = container
207: .getChildBean(j);
208: bean = child2.getInstance();
209: if (bean instanceof Tr) {
210: addTableCell(child2);
211: }
212: }
213:
214: } // XXX what about Rowgroups?
215: }
216: } finally {
217: // unit.getModel().writeUnlock(event);
218: InSyncService.getProvider().writeUnlockContext(context,
219: writeLock);
220: }
221: return Result.SUCCESS;
222: }
223: }
224:
225: private void addTableCell(DesignBean row) {
226: DesignContext context = row.getDesignContext();
227: DesignBean td = context.createBean(Td.class.getName(), row,
228: null);
229: addTableCellContents(td);
230: }
231:
232: private void addTableCellContents(DesignBean td) {
233: DesignContext context = td.getDesignContext();
234: // Create a <br/> in every table cell to make the cell visible
235: // (if there is no content, browsers are free to leave the cell
236: // rendered without borders. I used to insert 's but
237: // <br/>'s behave better and is what Mozilla composer seems
238: // to do in recent versions too.
239: DesignBean br = context
240: .createBean(Br.class.getName(), td, null);
241:
242: }
243:
244: // ------ Implements MarkupTableDesignInfo ------------------------
245:
246: public int testResizeRow(MarkupDesignBean mdBean, int row,
247: int column, int height) {
248: // Table rows are always resizable. Arguably later I can make the minimum nonzero.
249: return height;
250: }
251:
252: public Result resizeRow(MarkupDesignBean mdBean, int row, int height) {
253: if (initialized != mdBean) {
254: initialize(mdBean);
255: if (tableData == null) {
256: return Result.FAILURE;
257: }
258: }
259: // First clear the heights on all cells in the row
260: clearRowSize(mdBean, row);
261:
262: // The CSS value to set on one of the cells
263: String heightValue = Integer.toString(height) + "px"; // NOI18N
264:
265: // Then find a cell to set the height on. Use the first eligible row
266: // that has no rowspan
267: for (int i = 0; i < columns; i++) {
268: MarkupDesignBean td = ds.getCellBean(tableData, row, i);
269: if (td != null && ds.getRowSpan(tableData, row, i) == 1) {
270: setCssProperty(td.getElement(),
271: // CssConstants.CSS_HEIGHT_PROPERTY,
272: CssProvider.getValueService()
273: .getHeightProperty(), heightValue);
274: break;
275: }
276: }
277:
278: return Result.SUCCESS;
279: }
280:
281: public Result clearRowSize(MarkupDesignBean mdBean, int row) {
282: if (initialized != mdBean) {
283: initialize(mdBean);
284: if (tableData == null) {
285: return Result.FAILURE;
286: }
287: }
288: for (int i = 0; i < columns; i++) {
289: MarkupDesignBean td = ds.getCellBean(tableData, row, i);
290: if (td != null) {
291: // XXX should we check ds.getRowSpan() to see if we should
292: // skip this one? That's tricky because heights on rowspanning
293: // cells also contribute to the row heights! So for now clear
294: // these.... in fact what about cells starting in previous rows
295: // but overlapping this one?
296: removeCssProperty(td.getElement(),
297: // CssConstants.CSS_HEIGHT_PROPERTY);
298: CssProvider.getValueService()
299: .getHeightProperty());
300: }
301: }
302: return Result.SUCCESS;
303: }
304:
305: public int testResizeColumn(MarkupDesignBean mdBean, int row,
306: int column, int width) {
307: // Table columns are always resizable. Arguably later I can make the minimum nonzero.
308:
309: // TODO: constrain the max to the remaining width available: table width - column assigned widths?
310: return width;
311: }
312:
313: public Result resizeColumn(MarkupDesignBean mdBean, int column,
314: int width) {
315: if (initialized != mdBean) {
316: initialize(mdBean);
317: if (tableData == null) {
318: return Result.FAILURE;
319: }
320: }
321:
322: // First clear the widths on all cells in the column
323: clearColumnSize(mdBean, column);
324:
325: // The CSS value to set on one of the cells
326: String widthValue = Integer.toString(width) + "px"; // NOI18N
327:
328: // Then find a cell to set the width on. Use the first eligible column
329: // that has no colspan
330: // otherwise branch up and then down.
331: for (int i = 0; i < rows; i++) {
332: MarkupDesignBean td = ds.getCellBean(tableData, i, column);
333: if (td != null && ds.getColSpan(tableData, i, column) == 1) {
334: setCssProperty(td.getElement(),
335: // CssConstants.CSS_WIDTH_PROPERTY,
336: CssProvider.getValueService()
337: .getWidthProperty(), widthValue);
338: break;
339: }
340: }
341:
342: return Result.SUCCESS;
343: }
344:
345: public Result clearColumnSize(MarkupDesignBean mdBean, int column) {
346: if (initialized != mdBean) {
347: initialize(mdBean);
348: if (tableData == null) {
349: return Result.FAILURE;
350: }
351: }
352:
353: for (int i = 0; i < rows; i++) {
354: MarkupDesignBean td = ds.getCellBean(tableData, i, column);
355: if (td != null) {
356: // XXX should we check ds.getColSpan() to see if we should
357: // skip this one? That's tricky because widths on colspanning
358: // cells also contribute to the column widths! So for now clear
359: // these.... in fact what about cells starting in previous columns
360: // but overlapping this one?
361: removeCssProperty(td.getElement(),
362: // CssConstants.CSS_WIDTH_PROPERTY);
363: CssProvider.getValueService()
364: .getWidthProperty());
365: }
366: }
367: return Result.SUCCESS;
368: }
369:
370: /** Points to most recently queried table - e.g. a cache of size 1. Helps
371: * since we get asked about the same table over and over and over again as
372: * the user mouses around the table. */
373: private MarkupDesignBean initialized;
374:
375: /**
376: * Scan the table data structure and learn information about the table
377: * such that we know where rowspans are, have DesignBeans for the cells
378: * so we can manipulate their sizes, etc.
379: */
380: private void initialize(MarkupDesignBean table) {
381: initialized = table;
382: ds = DesignerServiceHack.getDefault();
383: tableData = ds.getTableInfo(table);
384: rows = ds.getRowCount(tableData);
385: columns = ds.getColumnCount(tableData);
386: }
387:
388: // XXX Should these be weakly referenced so we can throw away our data?
389: // Or should we perhaps have a way to simply copy in the data?
390: private java.lang.Object tableData;
391: private DesignerServiceHack ds;
392: private int rows;
393: private int columns;
394:
395: // XXX Moved from designer/DesignerServiceProvider.
396: private static void setCssProperty(Element element,
397: String property, String value) {
398: int index = CssProvider.getEngineService()
399: .getXhtmlPropertyIndex(property);
400:
401: if (index != -1) {
402: // CssProvider.getEngineService().addLocalStyleValueForElement(element, index, value);
403: InSyncService.getProvider().addLocalStyleValueForElement(
404: element, index, value);
405: }
406: }
407:
408: private static void removeCssProperty(Element element,
409: String property) {
410: int index = CssProvider.getEngineService()
411: .getXhtmlPropertyIndex(property);
412:
413: if (index != -1) {
414: // CssProvider.getEngineService().removeLocalStyleValueForElement(element, index);
415: InSyncService.getProvider()
416: .removeLocalStyleValueForElement(element, index);
417: }
418: }
419:
420: }
|