/** * ContentReader.java * (c) Peter Bielik and Radek Burget, 2011-2012 * * SwingBox is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * SwingBox is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with SwingBox. If not, see <http://www.gnu.org/licenses/>. * */ package org.fit.cssbox.swingbox.util; import java.awt.Dimension; import java.io.IOException; import java.util.LinkedList; import java.util.List; import java.util.Vector; import javax.swing.text.DefaultStyledDocument.ElementSpec; import javax.swing.text.SimpleAttributeSet; import org.fit.cssbox.io.DocumentSource; import org.fit.cssbox.layout.BlockBox; import org.fit.cssbox.layout.BlockReplacedBox; import org.fit.cssbox.layout.BlockTableBox; import org.fit.cssbox.layout.ElementBox; import org.fit.cssbox.layout.InlineBlockReplacedBox; import org.fit.cssbox.layout.InlineBox; import org.fit.cssbox.layout.ListItemBox; import org.fit.cssbox.layout.ReplacedBox; import org.fit.cssbox.layout.TableBodyBox; import org.fit.cssbox.layout.TableBox; import org.fit.cssbox.layout.TableCaptionBox; import org.fit.cssbox.layout.TableCellBox; import org.fit.cssbox.layout.TableColumn; import org.fit.cssbox.layout.TableColumnGroup; import org.fit.cssbox.layout.TableRowBox; import org.fit.cssbox.layout.TextBox; import org.fit.cssbox.layout.Viewport; import org.fit.cssbox.layout.VisualContext; import org.fit.cssbox.swingbox.SwingBoxDocument; /** * This class is used by editor kit to convert input data to elements used in * document. * * @author Peter Bielik * @author burgetr */ public class ContentReader implements org.fit.cssbox.render.BoxRenderer { /** Resulting element list */ private List<ElementSpec> elements; /** Element counter for determining the drawing order */ private int order; /** * Instantiates a new content reader. */ public ContentReader() { //boxMap = new HashMap<Box, SimpleAttributeSet>(); } /** * Reads input data and converts them to "elements" * * @param docSource * the document source * @param cba * the instance of {@link CSSBoxAnalyzer} * @param dim * the dimension * @return the list of elements. Note that, this method returns instance of * LinkedList. * @throws IOException * Signals that an I/O exception has occurred. */ public List<ElementSpec> read(DocumentSource docSource, CSSBoxAnalyzer cba, Dimension dim) throws IOException { // ale ked sa pouzije setText() neviem nic o url, nic sa nenastavuje , // moze byt null // (URL) doc.getProperty(Document.StreamDescriptionProperty) if (cba == null) throw new IllegalArgumentException("CSSBoxAnalyzer can not be NULL !!!\nProvide your custom implementation or check instantiation of DefaultAnalyzer object..."); elements = new Vector<ElementSpec>();// ArrayList<ElementSpec>(1024); elements.add(new ElementSpec(SimpleAttributeSet.EMPTY, ElementSpec.EndTagType)); order = 0; // System.err.print("used Reader and encoding ? " + // is.getCharacterStream() + " , "); // InputStreamReader r = (InputStreamReader)is.getCharacterStream(); // System.err.println(r.getEncoding()); Viewport vp; try { // System.err.println("analyzing..."); vp = cba.analyze(docSource, dim); // System.err.println("analyzing finished..."); } catch (Exception e) { throw new IOException(e); } //Use this for "drawing" the boxes. This constructs the element list. vp.draw(this); // System.err.println("num. of elements : " + elements.size()); // System.err.println("Root min width : " + root.getMinimalWidth() + // " ,normal width : " + root.getWidth() + " ,maximal width : " + // root.getMaximalWidth()); // TODO po skonceni nacitavania aj nejake info spravit // >> Document.TitleProperty - observer, metainfo return elements; } /** * Updates the layout. It is designed to do a re-layout only, not to process * input data again. * * @param root * the root * @param newDimension * the new dimension * @param cba * the CSSBoxAnalyzer * @return the list * @throws IOException * Signals that an I/O exception has occurred. */ public List<ElementSpec> update(Viewport root, Dimension newDimension, CSSBoxAnalyzer cba) throws IOException { if (cba == null) throw new IllegalArgumentException("CSSBoxAnalyzer can not be NULL !!!\nProvide your custom implementation or check instantiation of DefaultAnalyzer object..."); elements = new LinkedList<ElementSpec>(); elements.add(new ElementSpec(SimpleAttributeSet.EMPTY, ElementSpec.EndTagType)); order = 0; Viewport vp; try { vp = cba.update(newDimension); } catch (Exception e) { throw new IOException(e); } vp.draw(this); return elements; } private SimpleAttributeSet buildElement(ElementBox box) { if (box instanceof InlineBox) { return buildInlineBox((InlineBox) box); } else if (box instanceof Viewport) { // -- the boxes return buildViewport((Viewport) box); } else if (box instanceof TableBox) { // -- tables return buildTableBox((TableBox) box); } else if (box instanceof TableCaptionBox) { return buildTableCaptionBox((TableCaptionBox) box); } else if (box instanceof TableBodyBox) { return buildTableBodyBox((TableBodyBox) box); } else if (box instanceof TableRowBox) { return buildTableRowBox((TableRowBox) box); } else if (box instanceof TableCellBox) { return buildTableCellBox((TableCellBox) box); } else if (box instanceof TableColumnGroup) { return buildTableColumnGroup((TableColumnGroup) box); } else if (box instanceof TableColumn) { return buildTableColumn((TableColumn) box); } else if (box instanceof BlockTableBox) { return buildBlockTableBox((BlockTableBox) box); } else if (box instanceof ListItemBox) { return buildListItemBox((ListItemBox) box); } else if (box instanceof BlockBox) { return buildBlockBox((BlockBox) box); } else { System.err.println("Unknown BOX : " + box.getClass().getName()); return null; } } private SimpleAttributeSet buildText(TextBox box) { VisualContext vc = box.getVisualContext(); SimpleAttributeSet attr = new SimpleAttributeSet(); attr.addAttribute(Constants.ATTRIBUTE_FONT_VARIANT, vc.getFontVariant()); attr.addAttribute(Constants.ATTRIBUTE_TEXT_DECORATION, vc.getTextDecoration()); attr.addAttribute(Constants.ATTRIBUTE_FONT, vc.getFont()); attr.addAttribute(Constants.ATTRIBUTE_FOREGROUND, vc.getColor()); attr.addAttribute(SwingBoxDocument.ElementNameAttribute, Constants.TEXT_BOX); attr.addAttribute(Constants.ATTRIBUTE_ANCHOR_REFERENCE, new Anchor()); attr.addAttribute(Constants.ATTRIBUTE_BOX_REFERENCE, box); return attr; } private SimpleAttributeSet buildReplacedBox(ReplacedBox box) { SimpleAttributeSet attr = new SimpleAttributeSet(); if (box instanceof BlockReplacedBox) attr.addAttribute(SwingBoxDocument.ElementNameAttribute, Constants.BLOCK_REPLACED_BOX); else if (box instanceof InlineBlockReplacedBox) attr.addAttribute(SwingBoxDocument.ElementNameAttribute, Constants.INLINE_BLOCK_REPLACED_BOX); else attr.addAttribute(SwingBoxDocument.ElementNameAttribute, Constants.INLINE_REPLACED_BOX); attr.addAttribute(Constants.ATTRIBUTE_BOX_REFERENCE, box); attr.addAttribute(Constants.ATTRIBUTE_ANCHOR_REFERENCE, new Anchor()); attr.addAttribute(Constants.ATTRIBUTE_REPLACED_CONTENT, box.getContentObj()); return attr; } private SimpleAttributeSet buildElementBackground(ElementBox box) { return commonBuild(box, Constants.BACKGROUND); } private SimpleAttributeSet buildBlockBox(BlockBox box) { return commonBuild(box, Constants.BLOCK_BOX); } private SimpleAttributeSet buildInlineBox(InlineBox box) { return commonBuild(box, Constants.INLINE_BOX); } private SimpleAttributeSet buildViewport(Viewport box) { return commonBuild(box, Constants.VIEWPORT); } private SimpleAttributeSet buildBlockTableBox(BlockTableBox box) { return commonBuild(box, Constants.BLOCK_TABLE_BOX); } private SimpleAttributeSet buildTableBox(TableBox box) { return commonBuild(box, Constants.TABLE_BOX); } private SimpleAttributeSet buildTableCaptionBox(TableCaptionBox box) { return commonBuild(box, Constants.TABLE_CAPTION_BOX); } private SimpleAttributeSet buildTableBodyBox(TableBodyBox box) { return commonBuild(box, Constants.TABLE_BODY_BOX); } private SimpleAttributeSet buildTableRowBox(TableRowBox box) { return commonBuild(box, Constants.TABLE_ROW_BOX); } private SimpleAttributeSet buildTableCellBox(TableCellBox box) { return commonBuild(box, Constants.TABLE_CELL_BOX); } private SimpleAttributeSet buildTableColumn(TableColumn box) { return commonBuild(box, Constants.TABLE_COLUMN); } private SimpleAttributeSet buildTableColumnGroup(TableColumnGroup box) { return commonBuild(box, Constants.TABLE_COLUMN_GROUP); } private SimpleAttributeSet buildListItemBox(ListItemBox box) { return commonBuild(box, Constants.LIST_ITEM_BOX); } private final SimpleAttributeSet commonBuild(ElementBox box, Object elementNameValue) { // when there are no special requirements to build an element, use this // one SimpleAttributeSet attr = new SimpleAttributeSet(); attr.addAttribute(SwingBoxDocument.ElementNameAttribute, elementNameValue); attr.addAttribute(Constants.ATTRIBUTE_ANCHOR_REFERENCE, new Anchor()); attr.addAttribute(Constants.ATTRIBUTE_BOX_REFERENCE, box); attr.addAttribute(Constants.ATTRIBUTE_ELEMENT_ID, box.getElement().getAttribute("id")); return attr; } //====================================================================================================================== //BoxRenderer implementation @Override public void startElementContents(ElementBox elem) { if (!elem.isReplaced()) { SimpleAttributeSet attr = buildElement(elem); attr.addAttribute(Constants.ATTRIBUTE_DRAWING_ORDER, order++); elements.add(new ElementSpec(attr, ElementSpec.StartTagType, "{".toCharArray(), 1, 0)); } } @Override public void finishElementContents(ElementBox elem) { if (!elem.isReplaced()) { /*if (lastStarted == elem) { //rendering an empty element -- we must insert an empty string in order to preserve the element SimpleAttributeSet content = buildEmptyContent(); elements.add(new ElementSpec(content, ElementSpec.ContentType, "".toCharArray(), 0, 0)); }*/ SimpleAttributeSet attr = buildElement(elem); elements.add(new ElementSpec(attr, ElementSpec.EndTagType, "}".toCharArray(), 1, 0)); } } @Override public void renderElementBackground(ElementBox elem) { SimpleAttributeSet attr = buildElementBackground(elem); attr.addAttribute(Constants.ATTRIBUTE_DRAWING_ORDER, order++); elements.add(new ElementSpec(attr, ElementSpec.ContentType, "*".toCharArray(), 0, 1)); } @Override public void renderTextContent(TextBox box) { String text = box.getText(); SimpleAttributeSet attr = buildText(box); attr.addAttribute(Constants.ATTRIBUTE_DRAWING_ORDER, order++); elements.add(new ElementSpec(attr, ElementSpec.ContentType, text.toCharArray(), 0, text.length())); } @Override public void renderReplacedContent(ReplacedBox box) { org.w3c.dom.Element elem = ((ElementBox) box).getElement(); String text; // add some textual info, if picture if ("img".equalsIgnoreCase(elem.getTagName())) { text = " [" + elem.getAttribute("alt") + " Location: " + elem.getAttribute("src") + "] "; } else text = "{object}"; SimpleAttributeSet attr = buildReplacedBox(box); attr.addAttribute(Constants.ATTRIBUTE_DRAWING_ORDER, order++); elements.add(new ElementSpec(attr, ElementSpec.ContentType, text.toCharArray(), 0, text.length())); } @Override public void close() { } // block attributes, in general // FirstLineIndent // LeftIndent // RightIndent // LineSpacing // SpaceAbove // SpaceBelow // Alignment // TabSet // Text attributes, in general // FontFamily // FontSize // Bold // Italic // Underline // StrikeThrough // Superscript // Subscript // Foreground // Background // ComponentAttribute // IconAttribute }