Controlling base text direction in a custom component

This section applies to JViews rich client.
If the custom graphic object is a primitive (not a container) and does not have any text, then nothing is required.
Where the custom graphic object has some text or it is a container including child objects that have text, two approaches are available.

By methods of IlvBaseTextDirectionInterface

This functionality is the minimum required for objects that are not subclasses of IlvGraphic. All IlvGraphic objects implement this interface as well. Any container that displays text should implement IlvBaseTextDirectionInterface.
This interface defines the following methods:
  • public void setBaseTextDirection(int textDir) changes the base text direction of the object.
  • public int getBaseTextDirection() returns the stored base text direction of the object.
  • public int getResolvedBaseTextDirection() returns only one of LTR, RTL, or Contextual. It should resolve component direction by taking Component Orientation of the GUI into account. It should resolve the Inherited direction by taking the resolved base text direction of a parent container (if any) into account. If there is no parent container, it should return one of LTR, RTL, or Contextual as default value.
Implementation of these methods from scratch requires in depth understanding of the logic and mechanism of control over base text direction in JViews. If such knowledge is not available, a simpler approach can be used. See By subclasses of IlvGraphic.

By subclasses of IlvGraphic

The public methods mentioned in By methods of IlvBaseTextDirectionInterface and some additional ones used for handling base text direction are available in the class IlvGraphic. To control base text direction in a custom graphic object, you can extend this class to use the bidi functionality already implemented in it. The easiest way to do so is by taking as base class IlvBidiGraphic, which contains the full implementations of all methods of IlvBaseTextDirectionInterface.
Subclasses of IlvBidiGraphic should implement:
  • public boolean isBaseTextDirectionSensitive() to return true when the resolved base text direction has any effect on the bounding box of the graphic object.
  • public boolean usesBidiMarkers() should return true if the in-place editing implementation uses bidi markers; the implementation from IlvBidiGraphic always returns false.
  • public void baseTextDirectionChanged(int, int) to react whenever the resolved base text direction changes. For example, if internal drawing caches are affected by the resolved base text direction, they should be cleaned inside this method. If the current class is an IlvGraphicBag, the implementation does not need to call baseTextDirectionChanged(int, int) recursively on all contained subobjects, because the implementation of IlvBidiGraphic does this automatically.
  • public void draw(Graphics, IlvTransformer) to draw the text by taking the resolved base text direction into account.
  • public IlvRect boundingBox(IlvTransformer) to take the resolved base text direction into account.
  • Implementations of other methods, such as contains, intersects, inside, might also need to take the resolved base text direction into account.
If you cannot use IlvBidiGraphic as base class, then you can subclass IlvGraphic directly.
You must implement more methods, because IlvGraphic contains only empty or partial implementations:
  • Define baseTextDirection as a bean property.
  • Implement setBaseTextDirection and getBaseTextDirection.
    int _baseTextDirection;
    
    public void setBaseTextDirection(int baseTextDirection)
    {
      if (baseTextDirection == _baseTextDirection)
          return;
      int oldBTDir = getResolvedBaseTextDirection();
      _baseTextDirection = baseTextDirection;
      int newBTDir = getResolvedBaseTextDirection();
      if (oldBTDir != newBTDir)
          baseTextDirectionChanged(oldBTDir, newBTDir);
    }
    
    public int getBaseTextDirection()
    {
      return _baseTextDirection;
    }
  • If the class is an IlvGraphicSet, you must use a different variant that notifies all contained objects if the resolved base text direction changes:
    int _baseTextDirection;
    
    public void setBaseTextDirection(int baseTextDirection)
    {
      if (baseTextDirection == _baseTextDirection)
          return;
      IlvGraphicVector v = IlvGraphicUtil.startBidiChange(this);
      try {
          _baseTextDirection = baseTextDirection;
      } finally {
          // this calls applyToObject on all contained objects
          // and calls baseTextDirectionChanged on this and all
          // contained objects when needed.
          IlvGraphicUtil.stopBidiChange(this, v, false);
      } 
    }
    
    public int getBaseTextDirection()
    {
      return _baseTextDirection;
    }
  • Override setBaseTextDirectionDuringConstruction to change the data member without any notification:
    protected void setBaseTextDirectionDuringConstruction(int baseTextDirection)
    {
      _baseTextDirection = baseTextDirection;
    }
Override the other methods already mentioned for IlvBidiGraphic. (See the methods listed under [no title] for details.

Rendering

Whichever approach you take (IlvBaseTextDirectionInterface methods or subclasses of IlvGraphic), when text is rendered you must enforce its real base text direction.
JViews provides for the following techniques:
  • Using TextLayout attributes when TextLayout.draw is used for text display.
  • Using Unicode Control Characters when Graphics2D.drawString is used for text display.
  • Using ICU for bidi text reordering when Graphics2D.drawGlyphVector is used for text display.
  • Using the Swing API, for example, applyComponentOrientation, when text is displayed by using a Swing input field.