/* * Copyright 2007, Plutext Pty Ltd. * * This file is part of Docx4all. Docx4all is free software: you can redistribute it and/or modify it under the terms of version 3 of the GNU General Public License as published by the Free Software Foundation. Docx4all 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Docx4all. If not, see <http://www.gnu.org/licenses/>. */ package org.docx4all.swing.text; import java.awt.Color; import java.util.BitSet; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.Element; import javax.swing.text.Segment; import org.docx4all.xml.ElementML; import org.docx4all.xml.HyperlinkML; import org.docx4all.xml.RunDelML; import org.docx4all.xml.RunInsML; import org.docx4all.xml.RunML; /** * @author Jojada Tirtowidjojo - 28/08/2008 */ public class LabelView extends javax.swing.text.LabelView { private boolean impliedUnderline; private boolean impliedStrikethrough; private Color foreground; private JustificationInfo justificationInfo = null; public LabelView(Element elem) { super(elem); impliedUnderline = impliedStrikethrough = false; foreground = null; ElementML parent = ((DocumentElement) getElement().getParentElement()).getElementML(); String rStyle = (String) getAttributes().getAttribute(WordMLStyleConstants.RStyleAttribute); if (parent instanceof RunML && (rStyle == null || parent.getStyleSheet().getIDStyle(rStyle) == null)) { if (parent.getParent() instanceof RunInsML) { foreground = Color.RED; impliedUnderline = true; } else if (parent.getParent() instanceof RunDelML) { foreground = Color.RED; impliedStrikethrough = true; } else if (parent.getParent() instanceof HyperlinkML) { foreground = Color.BLUE; impliedUnderline = true; } } } public boolean isImpliedUnderline() { return impliedUnderline; } public boolean isImpliedStrikethrough() { return impliedStrikethrough; } public Color getForeground() { return (foreground == null) ? super.getForeground() : foreground; } public Segment getTextSegment(int p0, int p1) { Segment text = new Segment(); try { Document doc = getDocument(); doc.getText(p0, p1 - p0, text); } catch (BadLocationException bl) { throw new IllegalStateException("LabelView: Stale view: " + bl); } return text; } JustificationInfo getJustificationInfo(int rowStartOffset) { if (justificationInfo != null) { return justificationInfo; } //states for the parsing final int TRAILING = 0; final int CONTENT = 1; final int SPACES = 2; int startOffset = getStartOffset(); int endOffset = getEndOffset(); Segment segment = getTextSegment(startOffset, endOffset); int txtOffset = segment.offset; int txtEnd = segment.offset + segment.count - 1; int startContentPosition = txtEnd + 1; int endContentPosition = txtOffset - 1; int lastTabPosition = txtOffset - 1; int trailingSpaces = 0; int contentSpaces = 0; int leadingSpaces = 0; boolean hasTab = false; BitSet spaceMap = new BitSet(endOffset - startOffset + 1); //we parse conent to the right of the rightmost TAB only. //we are looking for the trailing and leading spaces. //position after the leading spaces (startContentPosition) //position before the trailing spaces (endContentPosition) for (int i = txtEnd, state = TRAILING; i >= txtOffset; i--) { if (' ' == segment.array[i]) { spaceMap.set(i - txtOffset); if (state == TRAILING) { trailingSpaces++; } else if (state == CONTENT) { state = SPACES; leadingSpaces = 1; } else if (state == SPACES) { leadingSpaces++; } } else if ('\t' == segment.array[i]) { hasTab = true; break; } else { if (state == TRAILING) { if ('\n' != segment.array[i] && '\r' != segment.array[i]) { state = CONTENT; endContentPosition = i; } } else if (state == CONTENT) { //do nothing } else if (state == SPACES) { contentSpaces += leadingSpaces; leadingSpaces = 0; } startContentPosition = i; } } int startJustifiableContent = -1; if (startContentPosition < txtEnd) { startJustifiableContent = startContentPosition - txtOffset; } int endJustifiableContent = -1; if (endContentPosition > txtOffset) { endJustifiableContent = endContentPosition - txtOffset; } justificationInfo = new JustificationInfo(startJustifiableContent, endJustifiableContent, leadingSpaces, contentSpaces, trailingSpaces, hasTab, spaceMap); return justificationInfo; } protected void setPropertiesFromAttributes() { super.setPropertiesFromAttributes(); if (isImpliedUnderline()) { setUnderline(true); } if (isImpliedStrikethrough()) { setStrikeThrough(true); } } /** * Class to hold data needed to justify this GlyphView in a PargraphView.Row */ static class JustificationInfo { //justifiable content start final int start; //justifiable content end final int end; final int leadingSpaces; final int contentSpaces; final int trailingSpaces; final boolean hasTab; final BitSet spaceMap; JustificationInfo(int start, int end, int leadingSpaces, int contentSpaces, int trailingSpaces, boolean hasTab, BitSet spaceMap) { this.start = start; this.end = end; this.leadingSpaces = leadingSpaces; this.contentSpaces = contentSpaces; this.trailingSpaces = trailingSpaces; this.hasTab = hasTab; this.spaceMap = spaceMap; } } }// LabelView class