diff --git a/source/org/thdl/tib/input/DuffPane.java b/source/org/thdl/tib/input/DuffPane.java index fa6f86f..84e8e13 100644 --- a/source/org/thdl/tib/input/DuffPane.java +++ b/source/org/thdl/tib/input/DuffPane.java @@ -18,6 +18,7 @@ Contributor(s): ______________________________________. package org.thdl.tib.input; +import java.io.*; import java.util.*; import java.awt.*; import java.awt.datatransfer.*; @@ -25,13 +26,9 @@ import java.awt.font.*; import java.awt.event.*; import javax.swing.*; import javax.swing.text.*; - -import java.lang.*; -import org.thdl.tib.text.*; - -import java.io.*; import javax.swing.text.rtf.*; +import org.thdl.tib.text.*; import org.thdl.util.ThdlDebug; import org.thdl.util.ThdlOptions; import org.thdl.util.StatusBar; @@ -307,13 +304,11 @@ public RTFEditorKit rtfEd = null; /** * This method sets up the editor, assigns fonts and point sizes, * sets the document, the caret, and adds key and focus listeners. -* -* @param sek the StyledEditorKit for the editing window */ private void setupEditor() { rtfBoard = getToolkit().getSystemClipboard(); rtfFlavor = new DataFlavor("text/rtf", "Rich Text Format"); - rtfEd = new RTFEditorKit(); + rtfEd = new TibetanRTFEditorKit(); setEditorKit(rtfEd); styleContext = new StyleContext(); diff --git a/source/org/thdl/tib/text/TibetanLabelView.java b/source/org/thdl/tib/text/TibetanLabelView.java new file mode 100644 index 0000000..5204c29 --- /dev/null +++ b/source/org/thdl/tib/text/TibetanLabelView.java @@ -0,0 +1,152 @@ +/* +The contents of this file are subject to the THDL Open Community License +Version 1.0 (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License on the THDL web site +(http://www.thdl.org/). + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific terms governing rights and limitations under the +License. + +The Initial Developer of this software is the Tibetan and Himalayan Digital +Library (THDL). Portions created by the THDL are Copyright 2001 THDL. +All Rights Reserved. + +Contributor(s): ______________________________________. +*/ + +package org.thdl.tib.text; + +import javax.swing.*; +import javax.swing.text.*; +import javax.swing.text.rtf.RTFEditorKit; + +/** A TibetanLabelView is a LabelView that has its own idea, informed + * by its knowledge of Tibetan, about where a good place to break + * text is. + * + *
+ * + * If Character.isWhiteSpace() could be overridden, and if that only + * affected breaking (which is doubtful), we wouldn't need this--we'd + * just treat Tibetan punctuation there. We might also like to + * override java.awt.font.GlyphMetrics idea of whitespace (though I'm + * not sure what consequences besides breaking that might have). But + * we can't override either since they're final. So we roll our own. + * + * @author David Chandler */ +class TibetanLabelView extends LabelView { + /** Creates a new TibetanLabelView. */ + public TibetanLabelView(Element e) { + super(e); + // FIXME: assert (e == this.getElement()) + } + + public int getBreakWeight(int axis, float pos, float len) { + if (View.X_AXIS != axis) { + // This doesn't impact line wrapping. + return super.getBreakWeight(axis, pos, len); + } else { + int startPos = this.getElement().getStartOffset(); + + int boundedPos = getPosNearTheEnd(startPos, pos, len); + + // boundedPos is short, and can be as short as startPos. + // I don't know when to say something is good as opposed + // to bad, but calling everything bad didn't work so well. + // So let's call boundedPos <= startPos bad and everything + // else without whitespace or tshegs et cetera good. + if (boundedPos <= startPos) + return View.BadBreakWeight; + + if (getGoodBreakingLocation(startPos, boundedPos) >= 0) + return View.ExcellentBreakWeight; + else + return View.GoodBreakWeight; + } + } + + public View breakView(int axis, int p0, float pos, float len) { + if (View.X_AXIS != axis) { + // This doesn't impact line wrapping. + return super.breakView(axis, p0, pos, len); + } else { + int boundedPos = getPosNearTheEnd(p0, pos, len); + + if (p0 == boundedPos) { + // We can't call createFragment safely. Return the + // current view. + return this; + } else { + int bloc = getGoodBreakingLocation(p0, boundedPos); + int whereToBreak; + if (bloc >= 0) + whereToBreak = bloc; + else + whereToBreak = boundedPos; + /* Return a new view, a fragment of the current one. + * If createFragment isn't smart, we could create + * infinitely many views of the same text if we don't + * check to see that this new view is actually + * different than the current view. */ + if (this.getStartOffset() != p0 + || this.getEndOffset() != whereToBreak) { + return createFragment(p0, whereToBreak); + } else + return this; + } + } + } + + /** Returns an offset >= 0 if we find a character (FIXME: before + * or after?) where breaking would be good. Returns negative + * otherwise. */ + private int getGoodBreakingLocation(int startOffset, int endOffset) { + + // Grab the underlying characters: + Segment seggy = this.getText(startOffset, endOffset); + + // System.out.println("DLC: getGoodBreakingLocation(start=" + startOffset + ", end=" + endOffset + "\"" + new String(seggy.array, seggy.offset, seggy.count) + "\""); + + // Now look for whitespace: + // + // FIXME: does going backwards or forwards matter? + char currentChar = seggy.first(); + for (; currentChar != Segment.DONE; currentChar = seggy.next()) { + // FIXME: eeek! How do we know when we're dealing with + // Tibetan and when we're not? I'm assuming it's all + // Tibetan, all the time. + if (Character.isWhitespace(currentChar) + || '-' /* FIXME: this is the TSHEG (i.e., the Wylie is ' '), but we have no constant for it. */ == currentChar + || ' ' /* FIXME: this is space (i.e., the Wylie is '_'), but we have no constant for it. */ == currentChar + + // FIXME: am I missing anything? move this into TibetanMachineWeb, anyway. + ) + { + // System.out.println("DLC: We've got a good place to break: " + (startOffset + seggy.getIndex() - seggy.getBeginIndex() + // + 1)); + return startOffset + seggy.getIndex() - seggy.getBeginIndex() + + 1 /* FIXME: why this foo work so good? */ + ; + } + } + // System.out.println("DLC: We DO NOT have any good place to break."); + return -1; + } + + /** Returns a position just before or at the position specified by + * the three arguments. viewToModel seems like the thing to use, + * but we don't have the parameters to pass to it. We can call + * GlyphView.GlyphPainter.getBoundedPosition(..) instead, and + * its comment mentions viewToModel, so maybe this is actually + * better. + */ + private int getPosNearTheEnd(int startPos, float pos, float len) { + // this is provided, and it appears that we'd better use it: + checkPainter(); + + return this.getGlyphPainter().getBoundedPosition(this, startPos, + pos, len); + } +} diff --git a/source/org/thdl/tib/text/TibetanMachineWeb.java b/source/org/thdl/tib/text/TibetanMachineWeb.java index ad6c139..b7ab6c7 100644 --- a/source/org/thdl/tib/text/TibetanMachineWeb.java +++ b/source/org/thdl/tib/text/TibetanMachineWeb.java @@ -221,6 +221,11 @@ public class TibetanMachineWeb { private static final String farrights = "d,s,ng"; static { + + // FIXME: we have it so that you can select the default + // keyboard via the preferences mechanism. We can remove this + // DEFAULT_KEYBOARD stuff, can't we? + readData(); URL keyboard_url = TibetanMachineWeb.class.getResource(DEFAULT_KEYBOARD); diff --git a/source/org/thdl/tib/text/TibetanRTFEditorKit.java b/source/org/thdl/tib/text/TibetanRTFEditorKit.java new file mode 100644 index 0000000..0d50ba6 --- /dev/null +++ b/source/org/thdl/tib/text/TibetanRTFEditorKit.java @@ -0,0 +1,46 @@ +/* +The contents of this file are subject to the THDL Open Community License +Version 1.0 (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License on the THDL web site +(http://www.thdl.org/). + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific terms governing rights and limitations under the +License. + +The Initial Developer of this software is the Tibetan and Himalayan Digital +Library (THDL). Portions created by the THDL are Copyright 2001 THDL. +All Rights Reserved. + +Contributor(s): ______________________________________. +*/ + +package org.thdl.tib.text; + +import javax.swing.*; +import javax.swing.text.*; +import javax.swing.text.rtf.RTFEditorKit; + +/** An EditorKit that is cognizant of the line-wrapping rules for + * Tibetan text. That is, this class knows about the tsheg and other + * Tibetan punctuation. + * @author David Chandler */ +public class TibetanRTFEditorKit extends RTFEditorKit { + /** Creates a new TibetanRTFEditorKit. */ + public TibetanRTFEditorKit() { + super(); + } + + /** the Tibetan-aware ViewFactory */ + private TibetanRTFViewFactory f = null; + + /** Returns a ViewFactory that is cognizant of Tibetan punctuation + * and line-breaking rules. */ + public ViewFactory getViewFactory() { + if (null == f) { + f = new TibetanRTFViewFactory(super.getViewFactory()); + } + return f; + } +} diff --git a/source/org/thdl/tib/text/TibetanRTFViewFactory.java b/source/org/thdl/tib/text/TibetanRTFViewFactory.java new file mode 100644 index 0000000..b2009fe --- /dev/null +++ b/source/org/thdl/tib/text/TibetanRTFViewFactory.java @@ -0,0 +1,61 @@ +/* +The contents of this file are subject to the THDL Open Community License +Version 1.0 (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License on the THDL web site +(http://www.thdl.org/). + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific terms governing rights and limitations under the +License. + +The Initial Developer of this software is the Tibetan and Himalayan Digital +Library (THDL). Portions created by the THDL are Copyright 2001 THDL. +All Rights Reserved. + +Contributor(s): ______________________________________. +*/ + +package org.thdl.tib.text; + +import javax.swing.*; +import javax.swing.text.*; +import javax.swing.text.rtf.RTFEditorKit; + +/** A ViewFactory that is cognizant of the line-wrapping rules for + * Tibetan text. That is, this class knows about the tsheg and other + * Tibetan punctuation. + * @author David Chandler */ +class TibetanRTFViewFactory implements ViewFactory { + private TibetanRTFViewFactory() { super(); } + + /** Creates a new TibetanRTFViewFactory that delegates to vf when + * unknown elements are encountered. + * @throws NullPointerException if d is null */ + public TibetanRTFViewFactory(ViewFactory d) + throws NullPointerException + { + if (null == d) throw new NullPointerException(); + delegatee = d; + } + + /** the delegatee */ + private ViewFactory delegatee = null; + + /** Returns a View that will break correctly at Tibetan + * punctuation. */ + public View create(Element el) { + String elName = el.getName(); + if (null != elName + && elName.equals(AbstractDocument.ContentElementName)) { // FIXME: is this right? + return new TibetanLabelView(el); + } else { + // we don't know what to do, so delegate + View r = delegatee.create(el); + // DLC for debugging: +// System.out.println("DLC: creating a view '" + r + "'"); +// System.out.println("DLC: for element '" + el + "'"); + return r; + } + } +}