Home » openjdk-7 » javax » swing » text » [javadoc | source]

    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one or more
    3    *  contributor license agreements.  See the NOTICE file distributed with
    4    *  this work for additional information regarding copyright ownership.
    5    *  The ASF licenses this file to You under the Apache License, Version 2.0
    6    *  (the "License"); you may not use this file except in compliance with
    7    *  the License.  You may obtain a copy of the License at
    8    *
    9    *     http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    *  Unless required by applicable law or agreed to in writing, software
   12    *  distributed under the License is distributed on an "AS IS" BASIS,
   13    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    *  See the License for the specific language governing permissions and
   15    *  limitations under the License.
   16    */
   17   /**
   18    * @author Alexey A. Ivanov
   19    */
   20   package javax.swing.text;
   21   
   22   import java.awt.Graphics;
   23   import java.awt.Rectangle;
   24   import java.awt.Shape;
   25   import java.util.ArrayList;
   26   import java.util.List;
   27   
   28   import javax.swing.SizeRequirements;
   29   import javax.swing.event.DocumentEvent;
   30   import javax.swing.event.DocumentEvent.ElementChange;
   31   import javax.swing.text.Position.Bias;
   32   
   33   import org.apache.harmony.awt.text.TextKit;
   34   import org.apache.harmony.awt.text.TextUtils;
   35   
   36   import org.apache.harmony.x.swing.internal.nls.Messages;
   37   
   38   
   39   /**
   40    * Represents view for displaying bidirectional text.
   41    */
   42   class PlainViewI18N extends BoxView implements TabExpander {
   43   
   44       /**
   45        * Represents text fragment with right-to-left orientation.
   46        */
   47       class RTLTextView extends BidiTextView {
   48   
   49           public RTLTextView(final Element element,
   50                              final int start, final int end) {
   51               super(element, start, end);
   52           }
   53   
   54           @Override
   55           public Shape modelToView(final int pos, final Shape shape,
   56                                    final Bias bias)
   57               throws BadLocationException {
   58   
   59               final int start = getStartOffset();
   60               final int end   = getEndOffset();
   61   
   62               if (pos < start || pos > end) {
   63                   throw new BadLocationException(Messages.getString("swing.98"), pos); //$NON-NLS-1$
   64               }
   65   
   66               getDocument().getText(pos, end - pos, paintParams.buffer);
   67               if (paintParams.buffer.last() == '\n') {
   68                   --paintParams.buffer.count;
   69               }
   70   
   71               Rectangle bounds = shape.getBounds();
   72               String text = paintParams.buffer.toString();
   73               return new Rectangle(
   74                       bounds.x + paintParams.metrics.stringWidth(text),
   75                       bounds.y,
   76                       1, paintParams.metrics.getHeight());
   77           }
   78   
   79           @Override
   80           public int viewToModel(final float x, final float y,
   81                                  final Shape shape, final Bias[] biasReturn) {
   82               biasReturn[0] = Position.Bias.Forward;
   83   
   84               final Rectangle bounds = shape.getBounds();
   85   
   86               final int start = getStartOffset();
   87               final int end   = getEndOffset();
   88               final Segment buffer = paintParams.buffer;
   89               try {
   90                   getDocument().getText(start, end - start, buffer);
   91               } catch (final BadLocationException e) { }
   92   
   93               final int bufferCount  = buffer.count;
   94               buffer.offset += buffer.count;
   95               buffer.count  = 0;
   96               int width = 0;
   97               while (bounds.x + width < x && buffer.count < bufferCount) {
   98                   --buffer.offset;
   99                   ++buffer.count;
  100                   width = paintParams.metrics.stringWidth(buffer.toString());
  101               }
  102               if (buffer.count >= bufferCount && bounds.x + width <= x) {
  103                   return end;
  104               }
  105               int resultOffset = end - buffer.count;
  106               if (resultOffset == end) {
  107                   biasReturn[0] = Position.Bias.Backward;
  108               }
  109               return resultOffset;
  110           }
  111   
  112           void drawLine(final Segment textBuffer, final TextPaintParams tpp,
  113                         final int start, final int end,
  114                         final Graphics g, final int x, final int y) {
  115               int currX = x;
  116   
  117               try {
  118   
  119                   if (tpp.selStart == tpp.selEnd
  120                       || tpp.selStart <= start && end <= tpp.selEnd) {
  121   
  122                       drawUnselectedText(g, currX, y, start, end);
  123                       return;
  124                   }
  125   
  126                   if (tpp.selEnd < start || tpp.selStart > end) {
  127                       drawUnselectedText(g, currX, y, start, end);
  128                   } else if (start < tpp.selStart) {
  129                       if (tpp.selEnd < end) {
  130                           currX = drawUnselectedText(g, currX, y,
  131                                                      tpp.selEnd, end);
  132                           currX = drawSelectedText(g, currX, y,
  133                                                    tpp.selStart, tpp.selEnd);
  134                       } else { // end <= selEnd
  135                           currX = drawSelectedText(g, currX, y,
  136                                                    tpp.selStart, end);
  137                       }
  138                       drawUnselectedText(g, currX, y, start, tpp.selStart);
  139                   } else { // selStart <= start && garanteed selEnd < end
  140                       currX = drawUnselectedText(g, currX, y, tpp.selEnd, end);
  141                       drawSelectedText(g, currX, y, start, tpp.selEnd);
  142                   }
  143   
  144               } catch (final BadLocationException e) { }
  145           }
  146       }
  147   
  148       /**
  149        * Represents text fragment with left-to-right orientation.
  150        */
  151       class LTRTextView extends BidiTextView {
  152   
  153           public LTRTextView(final Element element,
  154                              final int start, final int end) {
  155               super(element, start, end);
  156           }
  157   
  158           @Override
  159           public Shape modelToView(final int pos, final Shape shape,
  160                                    final Bias bias) throws BadLocationException {
  161               final int start = getStartOffset();
  162   
  163               if (pos < start || pos > getEndOffset()) {
  164                   throw new BadLocationException(Messages.getString("swing.98"), pos); //$NON-NLS-1$
  165               }
  166   
  167               getDocument().getText(start, pos - start, paintParams.buffer);
  168               Rectangle bounds = shape.getBounds();
  169               return new Rectangle(
  170                       TextUtils.getTabbedTextWidth(paintParams.buffer,
  171                                                    paintParams.metrics,
  172                                                    bounds.x,
  173                                                    PlainViewI18N.this,
  174                                                    pos) + bounds.x,
  175                       bounds.y,
  176                       1, paintParams.metrics.getHeight());
  177           }
  178   
  179           @Override
  180           public int viewToModel(final float x, final float y,
  181                                  final Shape shape, final Bias[] biasReturn) {
  182               biasReturn[0] = Position.Bias.Forward;
  183   
  184               final Rectangle bounds = shape.getBounds();
  185   
  186               final Document doc   = getDocument();
  187               final int      start = getStartOffset();
  188               final int      end   = getEndOffset();
  189               try {
  190                   doc.getText(start, end - start, paintParams.buffer);
  191               } catch (final BadLocationException e) { }
  192   
  193               return start + TextUtils.getTabbedTextOffset(paintParams.buffer,
  194                                                            paintParams.metrics,
  195                                                            bounds.x, (int)x,
  196                                                            PlainViewI18N.this,
  197                                                            start);
  198           }
  199   
  200       }
  201   
  202       /**
  203        * Base class for directional run of text.
  204        */
  205       abstract class BidiTextView extends View {
  206           protected Position start;
  207           protected Position end;
  208           protected Element  bidiElement;
  209   
  210           protected int cachedWidth = -1;
  211   
  212           public BidiTextView(final Element element,
  213                               final int start, final int end) {
  214               super(element);
  215   
  216               final Document doc = getDocument();
  217               try {
  218                   this.start = doc.createPosition(start);
  219                   this.end   = doc.createPosition(end);
  220               } catch (BadLocationException e) { }
  221           }
  222   
  223           @Override
  224           public int getEndOffset() {
  225               return end.getOffset();
  226           }
  227   
  228           @Override
  229           public int getStartOffset() {
  230               return start.getOffset();
  231           }
  232   
  233           @Override
  234           public float getAlignment(final int axis) {
  235               return ALIGN_LEFT;
  236           }
  237   
  238           protected Segment getText() {
  239               final int start = getStartOffset();
  240               int end = getEndOffset();
  241               if (getParent().getEndOffset() == end) {
  242                   --end;
  243               }
  244               try {
  245                   getDocument().getText(start, end - start, paintParams.buffer);
  246               } catch (BadLocationException e) {
  247                   e.printStackTrace();
  248               }
  249               return paintParams.buffer;
  250           }
  251   
  252           @Override
  253           public float getPreferredSpan(final int axis) {
  254               if (axis == Y_AXIS) {
  255                   return paintParams.metrics.getHeight();
  256               }
  257   
  258               if (cachedWidth == -1) {
  259                   LineView parent = (LineView)getParent();
  260                   cachedWidth = TextUtils.getTabbedTextWidth(getText(),
  261                           paintParams.metrics, parent.accumulatedWidth,
  262                           PlainViewI18N.this, 0);
  263                   parent.accumulatedWidth += cachedWidth;
  264               }
  265               return cachedWidth;
  266           }
  267   
  268           @Override
  269           public void paint(final Graphics g, final Shape shape) {
  270               Rectangle bounds = shape.getBounds();
  271   
  272               drawLine(paintParams,
  273                        getStartOffset(), getEndOffset(),
  274                        g, bounds.x,
  275                        bounds.y + paintParams.metrics.getHeight()
  276                        - paintParams.metrics.getDescent());
  277           }
  278   
  279           @Override
  280           protected int drawSelectedText(final Graphics g,
  281                                          final int x, final int y,
  282                                          final int start, final int end)
  283               throws BadLocationException {
  284   
  285               return drawText(g, paintParams.selColor, paintParams,
  286                               x, y, start, end);
  287           }
  288   
  289           @Override
  290           protected int drawUnselectedText(final Graphics g,
  291                                            final int x, final int y,
  292                                            final int start, final int end)
  293               throws BadLocationException {
  294   
  295               return drawText(g, paintParams.color, paintParams,
  296                               x, y, start, end);
  297           }
  298   
  299           @Override
  300           public void preferenceChanged(final View child,
  301                                         final boolean width,
  302                                         final boolean height) {
  303               if (width) {
  304                   cachedWidth = -1;
  305               }
  306               super.preferenceChanged(child, width, height);
  307           }
  308   
  309           @Override
  310           public void insertUpdate(final DocumentEvent event,
  311                                    final Shape shape,
  312                                    final ViewFactory factory) {
  313               preferenceChanged(this, true, false);
  314           }
  315   
  316           @Override
  317           public void removeUpdate(final DocumentEvent event,
  318                                    final Shape shape,
  319                                    final ViewFactory factory) {
  320               preferenceChanged(this, true, false);
  321           }
  322       }
  323   
  324       /**
  325        * Represents one logical line of text.
  326        */
  327       class LineView extends BoxView {
  328           public LineView(final Element element) {
  329               super(element, X_AXIS);
  330           }
  331   
  332           @Override
  333           public float getAlignment(final int axis) {
  334               return ALIGN_LEFT;
  335           }
  336   
  337           @Override
  338           public void paint(final Graphics g, final Shape shape) {
  339               TextKit textKit = getTextKit();
  340   
  341               if (textKit != null) {
  342                   textKit.paintLayeredHighlights(g, getStartOffset(),
  343                                                  getEndOffset() - 1,
  344                                                  shape, this);
  345               }
  346   
  347               super.paint(g, shape);
  348           }
  349   
  350           @Override
  351           protected boolean updateChildren(final ElementChange change,
  352                                            final DocumentEvent event,
  353                                            final ViewFactory factory) {
  354               return false;
  355           }
  356   
  357           @Override
  358           protected SizeRequirements
  359               calculateMinorAxisRequirements(final int axis,
  360                                              final SizeRequirements r) {
  361               SizeRequirements result = super.calculateMinorAxisRequirements(axis,
  362                                                                              r);
  363               // This view is not resizable along Y (minor axis)
  364               result.maximum = result.preferred;
  365               return result;
  366           }
  367   
  368           int accumulatedWidth;
  369   
  370           @Override
  371           protected SizeRequirements
  372               calculateMajorAxisRequirements(final int axis,
  373                                              final SizeRequirements r) {
  374               accumulatedWidth = 0;
  375               return super.calculateMajorAxisRequirements(axis, r);
  376           }
  377   
  378           @Override
  379           protected void loadChildren(final ViewFactory factory) {
  380               updateChildren();
  381           }
  382   
  383           private void updateView(final DocumentEvent event, final Shape shape) {
  384               final AbstractDocument doc = (AbstractDocument)getDocument();
  385               final ElementChange change =
  386                   event.getChange(doc.getBidiRootElement());
  387   
  388               if (change != null) {
  389                   updateChildren();
  390                   preferenceChanged(this, true, false);
  391   
  392                   if (shape != null) {
  393                       Rectangle rc = shape.getBounds();
  394                       getComponent().repaint(rc.x, rc.y, rc.width, rc.height);
  395                   }
  396               } else {
  397                   forwardUpdate(null, event, shape, null);
  398               }
  399           }
  400   
  401           @Override
  402           public void insertUpdate(final DocumentEvent event,
  403                                    final Shape shape,
  404                                    final ViewFactory factory) {
  405               updateView(event, shape);
  406           }
  407   
  408           @Override
  409           public void removeUpdate(final DocumentEvent event,
  410                                    final Shape shape,
  411                                    final ViewFactory factory) {
  412               updateView(event, shape);
  413           }
  414   
  415           private void updateChildren() {
  416               int startOffset = getStartOffset();
  417               final int endOffset   = getEndOffset();
  418               final Element element = getElement();
  419               AbstractDocument doc = (AbstractDocument)getDocument();
  420               Element bidiRoot = doc.getBidiRootElement();
  421               final int startIndex = bidiRoot.getElementIndex(startOffset);
  422               final int endIndex   = bidiRoot.getElementIndex(endOffset);
  423               List<View> views = new ArrayList<View>();
  424               for (int i = startIndex; i <= endIndex
  425                                        && startOffset < endOffset; i++) {
  426                   Element bidi = bidiRoot.getElement(i);
  427                   int level = StyleConstants.getBidiLevel(bidi.getAttributes());
  428                   View child;
  429                   if (TextUtils.isLTR(level)) {
  430                       child = new LTRTextView(element, startOffset,
  431                                               Math.min(endOffset,
  432                                                        bidi.getEndOffset()));
  433                   } else {
  434                       child = new RTLTextView(element, startOffset,
  435                                               Math.min(endOffset,
  436                                                        bidi.getEndOffset()));
  437                   }
  438                   startOffset = child.getEndOffset();
  439                   views.add(child);
  440               }
  441               replace(0, getViewCount(), views.toArray(new View[views.size()]));
  442           }
  443       }
  444   
  445       private final TextPaintParams paintParams = new TextPaintParams(this);
  446   
  447       private ViewFactory lineFactory = new ViewFactory() {
  448           public View create(final Element element) {
  449               return new LineView(element);
  450           }
  451       };
  452   
  453       public PlainViewI18N(final Element element) {
  454           super(element, Y_AXIS);
  455       }
  456   
  457       @Override
  458       public ViewFactory getViewFactory() {
  459           return lineFactory;
  460       }
  461   
  462       @Override
  463       public void paint(final Graphics g, final Shape shape) {
  464           paintParams.updateFields();
  465           super.paint(g, shape);
  466       }
  467   
  468       @Override
  469       public void setSize(final float width, final float height) {
  470           paintParams.conditionalUpdateMetrics();
  471           super.setSize(width, height);
  472   
  473           final int count = getViewCount();
  474           for (int i = 0; i < count; i++) {
  475               getView(i).setSize(getSpan(X_AXIS, i), getSpan(Y_AXIS, i));
  476           }
  477       }
  478   
  479       public float nextTabStop(final float x, final int tabOffset) {
  480           return paintParams.nextTabStop(x);
  481       }
  482   
  483       @Override
  484       public float getMaximumSpan(final int axis) {
  485           paintParams.conditionalUpdateMetrics();
  486           return super.getMaximumSpan(axis);
  487       }
  488   
  489       @Override
  490       public float getMinimumSpan(final int axis) {
  491           paintParams.conditionalUpdateMetrics();
  492           return super.getMinimumSpan(axis);
  493       }
  494   
  495       @Override
  496       public float getPreferredSpan(final int axis) {
  497           paintParams.conditionalUpdateMetrics();
  498           return super.getPreferredSpan(axis);
  499       }
  500   
  501       @Override
  502       public void insertUpdate(final DocumentEvent event,
  503                                final Shape shape,
  504                                final ViewFactory factory) {
  505           super.insertUpdate(event, shape, lineFactory);
  506       }
  507   
  508   
  509       @Override
  510       public void removeUpdate(final DocumentEvent event,
  511                                final Shape shape,
  512                                final ViewFactory factory) {
  513           super.removeUpdate(event, shape, lineFactory);
  514       }
  515   }

Home » openjdk-7 » javax » swing » text » [javadoc | source]