/*     */ public void insertChar(
     AttributedCharacterIterator paramAttributedCharacterIterator, int paramInt)
       /*     */ {
   /* 499 */ this.measurer.insertChar(paramAttributedCharacterIterator, paramInt);
   /*     */
   /* 501 */ this.limit = paramAttributedCharacterIterator.getEndIndex();
   /* 502 */ this.pos = (this.start = paramAttributedCharacterIterator.getBeginIndex());
   /*     */
   /* 504 */ this.charIter.reset(
       this.measurer.getChars(), paramAttributedCharacterIterator.getBeginIndex());
   /* 505 */ this.breakIter.setText(this.charIter);
   /*     */ }
 /**
  * Calculates the layout.
  *
  * @param fontRenderContext the FontRenderContext
  * @param font the Font
  * @param text the text
  * @param layoutWidth the width of the layout area
  * @return the layout result
  */
 public MultilineLayout calculateLayout(
     FontRenderContext fontRenderContext, Font font, String text, double layoutWidth) {
   // Layout multiline text
   MultilineLayout result = new MultilineLayout();
   if (text == null || text.isEmpty()) return result;
   Map<TextAttribute, Object> styleMap = new HashMap<TextAttribute, Object>();
   styleMap.put(TextAttribute.FONT, font);
   String[] textlines = text.split("\n");
   double height = 0;
   for (String textline : textlines) {
     AttributedString attribText = new AttributedString(textline, styleMap);
     AttributedCharacterIterator iter = attribText.getIterator();
     int textStart = iter.getBeginIndex();
     int textEnd = iter.getEndIndex();
     LineBreakMeasurer measurer = new LineBreakMeasurer(iter, fontRenderContext);
     measurer.setPosition(textStart);
     while (measurer.getPosition() < textEnd) {
       TextLayout line = measurer.nextLayout((float) layoutWidth);
       result.addLine(line);
       height += (line.getAscent() + line.getDescent() + line.getLeading());
     }
   }
   result.setSize(layoutWidth, height);
   return result;
 }
Beispiel #3
0
 /**
  * Called when a user processing input characters and select candidates from input method.
  *
  * @param text Text from InputMethodEvent.
  * @param commited_count Numbers of committed characters in text.
  */
 public void processCompositionText(AttributedCharacterIterator text, int committed_count) {
   int layoutCaretPosition = initialCaretPosition + committed_count;
   CompositionTextPainter compositionPainter = textArea.getPainter().getCompositionTextpainter();
   compositionPainter.setComposedTextLayout(
       getTextLayout(text, committed_count), layoutCaretPosition);
   int textLength = text.getEndIndex() - text.getBeginIndex() - committed_count;
   StringBuffer unCommitedStringBuf = new StringBuffer(textLength);
   char c;
   for (c = text.setIndex(committed_count);
       c != AttributedCharacterIterator.DONE && textLength > 0;
       c = text.next(), --textLength) {
     unCommitedStringBuf.append(c);
   }
   String unCommittedString = unCommitedStringBuf.toString();
   try {
     if (canRemovePreviousInput(committed_count)) {
       textArea.getDocument().remove(layoutCaretPosition, prevComposeString.length());
     }
     textArea.getDocument().insertString(layoutCaretPosition, unCommittedString, null);
     if (committed_count > 0) {
       initialCaretPosition = initialCaretPosition + committed_count;
     }
     prevComposeString = unCommittedString;
     prevCommittedCount = committed_count;
   } catch (BadLocationException e) {
     e.printStackTrace();
   }
 }
  /**
   * Return a StyledParagraph reflecting the insertion of a single character into the text. This
   * method will attempt to reuse the given paragraph, but may create a new paragraph.
   *
   * @param aci an iterator over the text. The text should be the same as the text used to create
   *     (or most recently update) oldParagraph, with the exception of deleting a single character
   *     at deletePos.
   * @param chars the characters in aci
   * @param deletePos the index where a character was removed
   * @param oldParagraph a StyledParagraph for the text in aci before the insertion
   */
  public static StyledParagraph deleteChar(
      AttributedCharacterIterator aci, char[] chars, int deletePos, StyledParagraph oldParagraph) {

    // We will reuse oldParagraph unless there was a length-1 run
    // at deletePos.  We could do more work and check the individual
    // Font and Decoration runs, but we don't right now...
    deletePos -= aci.getBeginIndex();

    if (oldParagraph.decorations == null && oldParagraph.fonts == null) {
      oldParagraph.length -= 1;
      return oldParagraph;
    }

    if (oldParagraph.getRunLimit(deletePos) == deletePos + 1) {
      if (deletePos == 0 || oldParagraph.getRunLimit(deletePos - 1) == deletePos) {
        return new StyledParagraph(aci, chars);
      }
    }

    oldParagraph.length -= 1;
    if (oldParagraph.decorations != null) {
      deleteFrom(deletePos, oldParagraph.decorationStarts, oldParagraph.decorations.size());
    }
    if (oldParagraph.fonts != null) {
      deleteFrom(deletePos, oldParagraph.fontStarts, oldParagraph.fonts.size());
    }
    return oldParagraph;
  }
  /**
   * Return a StyledParagraph reflecting the insertion of a single character into the text. This
   * method will attempt to reuse the given paragraph, but may create a new paragraph.
   *
   * @param aci an iterator over the text. The text should be the same as the text used to create
   *     (or most recently update) oldParagraph, with the exception of inserting a single character
   *     at insertPos.
   * @param chars the characters in aci
   * @param insertPos the index of the new character in aci
   * @param oldParagraph a StyledParagraph for the text in aci before the insertion
   */
  public static StyledParagraph insertChar(
      AttributedCharacterIterator aci, char[] chars, int insertPos, StyledParagraph oldParagraph) {

    // If the styles at insertPos match those at insertPos-1,
    // oldParagraph will be reused.  Otherwise we create a new
    // paragraph.

    char ch = aci.setIndex(insertPos);
    int relativePos = Math.max(insertPos - aci.getBeginIndex() - 1, 0);

    Map attributes = addInputMethodAttrs(aci.getAttributes());
    Decoration d = Decoration.getDecoration(attributes);
    if (!oldParagraph.getDecorationAt(relativePos).equals(d)) {
      return new StyledParagraph(aci, chars);
    }
    Object f = getGraphicOrFont(attributes);
    if (f == null) {
      FontResolver resolver = FontResolver.getInstance();
      int fontIndex = resolver.getFontIndex(ch);
      f = resolver.getFont(fontIndex, attributes);
    }
    if (!oldParagraph.getFontOrGraphicAt(relativePos).equals(f)) {
      return new StyledParagraph(aci, chars);
    }

    // insert into existing paragraph
    oldParagraph.length += 1;
    if (oldParagraph.decorations != null) {
      insertInto(relativePos, oldParagraph.decorationStarts, oldParagraph.decorations.size());
    }
    if (oldParagraph.fonts != null) {
      insertInto(relativePos, oldParagraph.fontStarts, oldParagraph.fonts.size());
    }
    return oldParagraph;
  }
  /**
   * Updates the <code>TextMeasurer</code> after a single character has been deleted from the
   * paragraph currently represented by this <code>TextMeasurer</code>. After this call, this <code>
   * TextMeasurer</code> is equivalent to a new <code>TextMeasurer</code> created from the text;
   * however, it will usually be more efficient to update an existing <code>TextMeasurer</code> than
   * to create a new one from scratch.
   *
   * @param newParagraph the text of the paragraph after performing the deletion. Cannot be null.
   * @param deletePos the position in the text where the character was removed. Must not be less
   *     than the start of <code>newParagraph</code>, and must not be greater than the end of <code>
   *     newParagraph</code>.
   * @throws IndexOutOfBoundsException if <code>deletePos</code> is less than the start of <code>
   *     newParagraph</code> or greater than the end of <code>newParagraph</code>
   * @throws NullPointerException if <code>newParagraph</code> is <code>null</code>
   */
  public void deleteChar(AttributedCharacterIterator newParagraph, int deletePos) {

    fStart = newParagraph.getBeginIndex();
    int end = newParagraph.getEndIndex();
    if (end - fStart != fChars.length - 1) {
      initAll(newParagraph);
    }

    char[] newChars = new char[end - fStart];
    int changedIndex = deletePos - fStart;

    System.arraycopy(fChars, 0, newChars, 0, deletePos - fStart);
    System.arraycopy(fChars, changedIndex + 1, newChars, changedIndex, end - deletePos);
    fChars = newChars;

    if (fBidi != null) {
      fBidi = new Bidi(newParagraph);
      if (fBidi.isLeftToRight()) {
        fBidi = null;
      }
    }

    fParagraph = StyledParagraph.deleteChar(newParagraph, fChars, deletePos, fParagraph);
    invalidateComponents();
  }
  public Format.Field[] getFields(final int offset) {
    if (format == null) {
      return null;
    }

    Object value = getFormattedTextField().getValue();
    if (value == null) {
      return null;
    }

    AttributedCharacterIterator iterator = format.formatToCharacterIterator(value);
    if (offset < iterator.getBeginIndex() || offset > iterator.getEndIndex()) {
      return new Format.Field[0];
    }

    iterator.setIndex(offset);
    Set keys = iterator.getAttributes().keySet();
    Set result = new HashSet();
    Iterator iter = keys.iterator();

    while (iter.hasNext()) {
      Object key = iter.next();
      if (key instanceof Format.Field) {
        result.add(key);
      }
    }

    return (Format.Field[]) result.toArray(new Format.Field[result.size()]);
  }
 /*     */ public void deleteChar(
     AttributedCharacterIterator paramAttributedCharacterIterator, int paramInt)
       /*     */ {
   /* 525 */ this.measurer.deleteChar(paramAttributedCharacterIterator, paramInt);
   /*     */
   /* 527 */ this.limit = paramAttributedCharacterIterator.getEndIndex();
   /* 528 */ this.pos = (this.start = paramAttributedCharacterIterator.getBeginIndex());
   /*     */
   /* 530 */ this.charIter.reset(this.measurer.getChars(), this.start);
   /* 531 */ this.breakIter.setText(this.charIter);
   /*     */ }
 /*     */ public LineBreakMeasurer(
     AttributedCharacterIterator paramAttributedCharacterIterator,
     BreakIterator paramBreakIterator,
     FontRenderContext paramFontRenderContext)
       /*     */ {
   /* 305 */ if (paramAttributedCharacterIterator.getEndIndex()
           - paramAttributedCharacterIterator.getBeginIndex()
       < 1) {
     /* 306 */ throw new IllegalArgumentException("Text must contain at least one character.");
     /*     */ }
   /*     */
   /* 309 */ this.breakIter = paramBreakIterator;
   /* 310 */ this.measurer =
       new TextMeasurer(paramAttributedCharacterIterator, paramFontRenderContext);
   /* 311 */ this.limit = paramAttributedCharacterIterator.getEndIndex();
   /* 312 */ this.pos = (this.start = paramAttributedCharacterIterator.getBeginIndex());
   /*     */
   /* 314 */ this.charIter = new CharArrayIterator(this.measurer.getChars(), this.start);
   /* 315 */ this.breakIter.setText(this.charIter);
   /*     */ }
Beispiel #10
0
 /**
  * Draws a string at the specified position.
  *
  * @param iterator the string.
  * @param x the x-coordinate.
  * @param y the y-coordinate.
  */
 @Override
 public void drawString(AttributedCharacterIterator iterator, int x, int y) {
   // for now we simply want to extract the chars from the iterator
   // and call an unstyled text renderer
   StringBuffer sb = new StringBuffer();
   int numChars = iterator.getEndIndex() - iterator.getBeginIndex();
   char c = iterator.first();
   for (int i = 0; i < numChars; i++) {
     sb.append(c);
     c = iterator.next();
   }
   drawString(new String(sb), x, y);
 }
  /**
   * Create a new StyledParagraph over the given styled text.
   *
   * @param aci an iterator over the text
   * @param chars the characters extracted from aci
   */
  public StyledParagraph(AttributedCharacterIterator aci, char[] chars) {

    int start = aci.getBeginIndex();
    int end = aci.getEndIndex();
    length = end - start;

    int index = start;
    aci.first();

    do {
      final int nextRunStart = aci.getRunLimit();
      final int localIndex = index - start;

      Map attributes = aci.getAttributes();
      attributes = addInputMethodAttrs(attributes);
      Decoration d = Decoration.getDecoration(attributes);
      addDecoration(d, localIndex);

      Object f = getGraphicOrFont(attributes);
      if (f == null) {
        addFonts(chars, attributes, localIndex, nextRunStart - start);
      } else {
        addFont(f, localIndex);
      }

      aci.setIndex(nextRunStart);
      index = nextRunStart;

    } while (index < end);

    // Add extra entries to starts arrays with the length
    // of the paragraph.  'this' is used as a dummy value
    // in the Vector.
    if (decorations != null) {
      decorationStarts = addToVector(this, length, decorations, decorationStarts);
    }
    if (fonts != null) {
      fontStarts = addToVector(this, length, fonts, fontStarts);
    }
  }
  // counts lines
  public static int countLines(JTextArea textArea) {
    AttributedString text = new AttributedString(textArea.getText());
    FontRenderContext frc = textArea.getFontMetrics(textArea.getFont()).getFontRenderContext();

    int lines = 0;
    if (!textArea.getText().equals("")) {
      AttributedCharacterIterator charIt = text.getIterator();
      LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(charIt, frc);
      float formatWidth = (float) textArea.getSize().width;
      lineMeasurer.setPosition(charIt.getBeginIndex());
      while (lineMeasurer.getPosition() < charIt.getEndIndex()) {
        lineMeasurer.nextLayout(formatWidth);
        lines++;
      }
      for (int i = 0; i < textArea.getText().length(); i++) {
        if (textArea.getText().charAt(i) == '\r' || textArea.getText().charAt(i) == '\n') lines++;
      }
    } else {
      lines = 1;
    }
    return lines;
  }
Beispiel #13
0
  /**
   * Updates the <code>TextMeasurer</code> after a single character has been inserted into the
   * paragraph currently represented by this <code>TextMeasurer</code>. After this call, this <code>
   * TextMeasurer</code> is equivalent to a new <code>TextMeasurer</code> created from the text;
   * however, it will usually be more efficient to update an existing <code>TextMeasurer</code> than
   * to create a new one from scratch.
   *
   * @param newParagraph the text of the paragraph after performing the insertion. Cannot be null.
   * @param insertPos the position in the text where the character was inserted. Must not be less
   *     than the start of <code>newParagraph</code>, and must be less than the end of <code>
   *     newParagraph</code>.
   * @throws IndexOutOfBoundsException if <code>insertPos</code> is less than the start of <code>
   *     newParagraph</code> or greater than or equal to the end of <code>newParagraph</code>
   * @throws NullPointerException if <code>newParagraph</code> is <code>null</code>
   */
  public void insertChar(AttributedCharacterIterator newParagraph, int insertPos) {

    if (collectStats) {
      printStats();
    }
    if (wantStats) {
      collectStats = true;
    }

    fStart = newParagraph.getBeginIndex();
    int end = newParagraph.getEndIndex();
    if (end - fStart != fChars.length + 1) {
      initAll(newParagraph);
    }

    char[] newChars = new char[end - fStart];
    int newCharIndex = insertPos - fStart;
    System.arraycopy(fChars, 0, newChars, 0, newCharIndex);

    char newChar = newParagraph.setIndex(insertPos);
    newChars[newCharIndex] = newChar;
    System.arraycopy(fChars, newCharIndex, newChars, newCharIndex + 1, end - insertPos - 1);
    fChars = newChars;

    if (fBidi != null
        || Bidi.requiresBidi(newChars, newCharIndex, newCharIndex + 1)
        || newParagraph.getAttribute(TextAttribute.BIDI_EMBEDDING) != null) {

      fBidi = new Bidi(newParagraph);
      if (fBidi.isLeftToRight()) {
        fBidi = null;
      }
    }

    fParagraph = StyledParagraph.insertChar(newParagraph, fChars, insertPos, fParagraph);
    invalidateComponents();
  }
Beispiel #14
0
  /** Initialize state, including fChars array, direction, and fBidi. */
  private void initAll(AttributedCharacterIterator text) {

    fStart = text.getBeginIndex();

    // extract chars
    fChars = new char[text.getEndIndex() - fStart];

    int n = 0;
    for (char c = text.first(); c != CharacterIterator.DONE; c = text.next()) {
      fChars[n++] = c;
    }

    text.first();

    fBidi = new Bidi(text);
    if (fBidi.isLeftToRight()) {
      fBidi = null;
    }

    text.first();
    Map<? extends Attribute, ?> paragraphAttrs = text.getAttributes();
    NumericShaper shaper = AttributeValues.getNumericShaping(paragraphAttrs);
    if (shaper != null) {
      shaper.shape(fChars, 0, fChars.length);
    }

    fParagraph = new StyledParagraph(text, fChars);

    // set paragraph attributes
    {
      // If there's an embedded graphic at the start of the
      // paragraph, look for the first non-graphic character
      // and use it and its font to initialize the paragraph.
      // If not, use the first graphic to initialize.
      fJustifyRatio = AttributeValues.getJustification(paragraphAttrs);

      boolean haveFont = TextLine.advanceToFirstFont(text);

      if (haveFont) {
        Font defaultFont = TextLine.getFontAtCurrentPos(text);
        int charsStart = text.getIndex() - text.getBeginIndex();
        LineMetrics lm = defaultFont.getLineMetrics(fChars, charsStart, charsStart + 1, fFrc);
        fBaseline = (byte) lm.getBaselineIndex();
        fBaselineOffsets = lm.getBaselineOffsets();
      } else {
        // hmmm what to do here?  Just try to supply reasonable
        // values I guess.

        GraphicAttribute graphic =
            (GraphicAttribute) paragraphAttrs.get(TextAttribute.CHAR_REPLACEMENT);
        fBaseline = TextLayout.getBaselineFromGraphic(graphic);
        Hashtable<Attribute, ?> fmap = new Hashtable<>(5, (float) 0.9);
        Font dummyFont = new Font(fmap);
        LineMetrics lm = dummyFont.getLineMetrics(" ", 0, 1, fFrc);
        fBaselineOffsets = lm.getBaselineOffsets();
      }
      fBaselineOffsets = TextLine.getNormalizedOffsets(fBaselineOffsets, fBaseline);
    }

    invalidateComponents();
  }
Beispiel #15
0
  // handle spaces separately, all others by table
  // as - Attributed string to attribute with Word extents.
  public static void findLineBrk(AttributedString as) {
    AttributedCharacterIterator aci = as.getIterator();
    if (aci.getEndIndex() == 0) return;
    char ch = aci.current(), prevCh = (char) -1;
    byte cls = getCharCharClass(ch);
    if (cls == CHAR_CLASS_LF) cls = CHAR_CLASS_BK;
    byte curCls = cls;
    byte prevCls = cls;
    byte prevPrevCls = -1;
    int wordCnt = 0;
    int wordBegin = aci.getBeginIndex();
    // loop over all pairs in the string
    int ich = wordBegin + 1;
    int lineEnd = aci.getRunLimit(lineBrks);

    // handle case where input starts with an LF
    if (cls >= CHAR_CLASS_CM) cls = CHAR_CLASS_AL;

    for (ch = aci.next();
        ch != AttributedCharacterIterator.DONE;
        ich++, prevCh = ch, ch = aci.next(), prevPrevCls = prevCls, prevCls = curCls) {

      if (ich == lineEnd) {
        as.addAttribute(WORD_LIMIT, new Integer(wordCnt++), wordBegin, ich);
        wordBegin = ich;

        cls = getCharCharClass(ch);
        curCls = cls;
        prevCls = cls;
        if (cls >= CHAR_CLASS_CM) cls = CHAR_CLASS_AL;

        lineEnd = aci.getRunLimit(lineBrks);
        continue;
      }

      // handle spaces
      curCls = getCharCharClass(ch);
      if (curCls == CHAR_CLASS_SP) {
        // pbrk[ich-1] = BREAK_ACTION_PROHIBITED;
        continue;
      }

      // handle complex scripts
      if (curCls == CHAR_CLASS_SA) {
        ich += findComplexBreak(aci);
        ch = aci.previous();
        if (ch != AttributedCharacterIterator.DONE) prevCls = getCharCharClass(ch);
        ch = aci.next();
        if (ch != AttributedCharacterIterator.DONE) curCls = cls = getCharCharClass(ch);
        continue;
      }

      // This isn't in the Unicode line breaking alg.  but it
      // seems needed as otherwise it does produce a break.
      if ((ch == CHAR_ZERO_WIDTH_JOINER) || (prevCh == CHAR_ZERO_WIDTH_JOINER))
        continue; // Don't allow break around JOINER.

      if ((curCls == CHAR_CLASS_BK) || (curCls == CHAR_CLASS_LF)) {
        as.addAttribute(WORD_LIMIT, new Integer(wordCnt++), wordBegin, ich);
        wordBegin = ich;
        cls = CHAR_CLASS_BK;
        continue;
      }
      if (prevCls == CHAR_CLASS_CR) {
        as.addAttribute(WORD_LIMIT, new Integer(wordCnt++), wordBegin, ich - 1);
        wordBegin = ich - 1;
        cls = CHAR_CLASS_BK;
        continue;
      }
      if (curCls == CHAR_CLASS_CR) {
        continue;
      }

      // handle combining marks
      if (curCls == CHAR_CLASS_CM) {
        if (prevCls == CHAR_CLASS_SP) {
          cls = CHAR_CLASS_ID;
          if (prevPrevCls != -1) {
            if (brkPairs[prevPrevCls][CHAR_CLASS_ID] == BREAK_ACTION_DIRECT) {
              as.addAttribute(WORD_LIMIT, new Integer(wordCnt++), wordBegin, ich - 1);
              wordBegin = ich - 1;
              // pbrk[ich-2] = BREAK_ACTION_DIRECT;
            } else {
              // pbrk[ich-2] = BREAK_ACTION_PROHIBITED;
            }
          }
        }
        // pbrk[ich-1] = BREAK_ACTION_PROHIBITED;
        continue;
      }

      if (cls == CHAR_CLASS_BK) {
        cls = curCls;
        continue;
      }

      // lookup pair table information
      byte brk = brkPairs[cls][curCls];

      if (brk == BREAK_ACTION_DIRECT) {
        as.addAttribute(WORD_LIMIT, new Integer(wordCnt++), wordBegin, ich);
        wordBegin = ich;
        // pbrk[ich-1] = brk;
      } else if (brk == BREAK_ACTION_INDIRECT) {
        if (prevCls == CHAR_CLASS_SP) {
          as.addAttribute(WORD_LIMIT, new Integer(wordCnt++), wordBegin, ich);
          wordBegin = ich;
        }
        // pbrk[ich-1] = ((prevCls == CHAR_CLASS_SP) ?
        //                BREAK_ACTION_INDIRECT :
        //                BREAK_ACTION_PROHIBITED);
      }
      cls = curCls;
    }

    // always break at the end
    as.addAttribute(WORD_LIMIT, new Integer(wordCnt++), wordBegin, ich);
    wordBegin = ich;
    // pbrk[ich-1] = BREAK_ACTION_DIRECT;

    return;
  }
  public void draw(final Graphics2D graphics2D, final Rectangle2D bounds) {
    Graphics2D g = (Graphics2D) graphics2D.create();
    g.setColor((Color) styleSheet.getStyleProperty(ElementStyleKeys.PAINT, Color.BLACK));
    if (styleSheet.getBooleanStyleProperty(ElementStyleKeys.DRAW_SHAPE)) {
      g.draw(bounds);
    }

    if (styleSheet.getBooleanStyleProperty(ElementStyleKeys.FILL_SHAPE)) {
      Graphics2D g2 = (Graphics2D) g.create();
      Color fillColor =
          (Color) styleSheet.getStyleProperty(ElementStyleKeys.FILL_COLOR, Color.WHITE);
      g2.setColor(fillColor);
      g2.fill(bounds);
      g2.dispose();
    }

    if (vectorImageBackground != null) {
      Graphics2D g2 = (Graphics2D) g.create();
      vectorImageBackground.draw(g2, bounds);
      g2.dispose();
    }
    if (rasterImageBackground != null) {
      Graphics2D g2 = (Graphics2D) g.create();

      Image image = rasterImageBackground.getImage();
      WaitingImageObserver obs = new WaitingImageObserver(image);
      obs.waitImageLoaded();

      g.setColor(Color.WHITE);
      g.setBackground(Color.WHITE);

      while (g2.drawImage(
              image,
              (int) bounds.getX(),
              (int) bounds.getY(),
              (int) bounds.getWidth(),
              (int) bounds.getHeight(),
              null)
          == false) {
        obs.waitImageLoaded();
        if (obs.isError()) {
          logger.warn("Error while loading the image during the rendering.");
          break;
        }
      }
      g2.dispose();
    }

    if (StringUtils.isEmpty(textToPrint) == false) {
      AttributedCharacterIterator paragraph = new AttributedString(textToPrint).getIterator();
      int paragraphStart = paragraph.getBeginIndex();
      int paragraphEnd = paragraph.getEndIndex();
      FontRenderContext frc = g.getFontRenderContext();
      LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(paragraph, frc);

      float breakWidth = (float) bounds.getWidth();
      float drawPosY = 0;
      // Set position to the index of the first character in the paragraph.
      lineMeasurer.setPosition(paragraphStart);

      while (lineMeasurer.getPosition() < paragraphEnd) {
        TextLayout layout = lineMeasurer.nextLayout(breakWidth).getJustifiedLayout(breakWidth);
        float drawPosX = layout.isLeftToRight() ? 0 : breakWidth - layout.getAdvance();

        drawPosY += layout.getAscent();

        layout.draw(g, drawPosX, drawPosY);

        drawPosY += layout.getDescent() + layout.getLeading();
      }
    }
  }
  public int print(Graphics g, PageFormat pageFormat, int page) throws PrinterException {

    // Define the origin of the printArea
    double printAreaX = pageFormat.getImageableX();
    double printAreaY = pageFormat.getImageableY();

    // Measures the size of strings
    FontMetrics metrics = g.getFontMetrics(fnt);

    // Parameters for the layout
    // Dynamic variable to measure the y-position of each line

    int intMeasureY = 0;
    // Others
    int intMarginLeft = Integer.valueOf((int) Math.round(printAreaX * LMARGINRATIO));
    int intSpace = Integer.valueOf((int) Math.round(metrics.getHeight() * SPACERATIO));
    int intDefaultHeight = metrics.getHeight();
    int intPageWidth = Integer.valueOf((int) Math.round(pageFormat.getImageableWidth()));

    int pageHeight = Integer.valueOf((int) Math.round(pageFormat.getImageableHeight()));

    metrics = g.getFontMetrics(fntTitle);
    int intSpaceBig = metrics.getHeight();

    // Graphics object to draw lines etc.
    Graphics2D g2d;
    Line2D.Double line = new Line2D.Double();
    // Set colour to black
    g.setColor(Color.black);

    // Validate the number of pages

    // Create a graphic2D object a set the default parameters
    g2d = (Graphics2D) g;
    g2d.setColor(Color.black);

    // Translate the origin to be (0,0)
    // Note: Imageable includes already margins for Headers and Footers
    g2d.translate(printAreaX, printAreaY);

    // -- (1) Print the line on the left side
    line.setLine(0, 0, 0, pageFormat.getHeight() + 500);
    g2d.draw(line);

    // -- (2) Print the physicians attributes

    g.setFont(fntBold);
    // Measure String height to start drawing at the right place
    metrics = g.getFontMetrics(fntBold);
    intMeasureY += metrics.getHeight();

    g.drawString(
        ph.getTitle() + " " + ph.getFirstname() + " " + ph.getLastname(),
        intMarginLeft,
        intMeasureY);

    // Set font to default
    g.setFont(fnt);

    // Measure the x-position (Page-Width - length of string)
    metrics = g.getFontMetrics(fnt);

    // Draw the date
    g.drawString(rp.getDate(), intPageWidth - metrics.stringWidth(rp.getDate()), intMeasureY);

    intMeasureY += metrics.getHeight();

    // Draw strings of Address, Phone and insurance information
    g.drawString(ph.getSpecialty1(), intMarginLeft, intMeasureY);

    if (ph.getSpecialty2().length() > 0) {
      intMeasureY += intDefaultHeight;
      g.drawString(ph.getSpecialty2(), intMarginLeft, intMeasureY);
    }

    intMeasureY += intSpace;

    g.drawString(ph.getStreet() + " " + ph.getPostbox(), intMarginLeft, intMeasureY);

    intMeasureY += intDefaultHeight;

    g.drawString(ph.getZip() + " " + ph.getCity(), intMarginLeft, intMeasureY);

    intMeasureY += intSpace;

    // Measure the label strings to align the phone and fax numbers
    int phoneWidth = metrics.stringWidth(PHONE);

    if (metrics.stringWidth(PHONE) < metrics.stringWidth(FAX) && ph.getFax().length() > 0)
      phoneWidth = metrics.stringWidth(FAX);

    g.drawString(PHONE, intMarginLeft, intMeasureY);
    g.drawString(ph.getPhone(), intMarginLeft + phoneWidth, intMeasureY);

    if (ph.getFax().length() > 0) {
      intMeasureY += intDefaultHeight;

      g.drawString(FAX, intMarginLeft, intMeasureY);
      g.drawString(ph.getFax(), intMarginLeft + phoneWidth, intMeasureY);
    }

    intMeasureY += intSpace;

    // Measure the label strings to align the ZSR and EAN identifiers
    int EANWidth = metrics.stringWidth(ZSR);

    if (metrics.stringWidth(ZSR) < metrics.stringWidth(EAN) && ph.getGlnid().length() > 0)
      EANWidth = metrics.stringWidth(EAN);

    g.drawString(ZSR, intMarginLeft, intMeasureY);
    g.drawString(ph.getZsrid(), intMarginLeft + EANWidth, intMeasureY);

    if (ph.getGlnid().length() > 0) {

      intMeasureY += intDefaultHeight;

      g.drawString(EAN, intMarginLeft, intMeasureY);
      g.drawString(ph.getGlnid(), intMarginLeft + EANWidth, intMeasureY);
    }

    intMeasureY += intSpaceBig;

    // -- (3) Print the line
    line.setLine(intMarginLeft, intMeasureY, pageFormat.getWidth(), intMeasureY);
    g2d.draw(line);

    intMeasureY += intSpaceBig + intSpace;

    // -- (4) Title
    g.setFont(fntTitle);
    g.drawString(TITLE, intMarginLeft, intMeasureY);

    intMeasureY += intSpaceBig + intDefaultHeight;

    // -- (5) Patient
    g.setFont(fntBold);

    g.drawString(pat.getName() + " " + pat.getVorname(), intMarginLeft, intMeasureY);

    metrics = g.getFontMetrics(fntBold);
    int xPat = intMarginLeft + metrics.stringWidth(pat.getName() + " " + pat.getVorname());

    g.setFont(fnt);
    g.drawString(", " + BORN + pat.getGeburtsdatum(), xPat, intMeasureY);

    intMeasureY += intSpaceBig + intSpace;

    // -- (6) Products
    LineBreakMeasurer lineBreakMeasurer;
    int intstart, intend;

    Hashtable hash = new Hashtable();

    // Print all the items
    for (int i = this.firstProd; i <= lastProd; i = i + 1) {

      ch.elexis.data.Prescription actualLine = rp.getLines().get(i);
      Artikel article = actualLine.getArtikel();

      AttributedString attributedString = new AttributedString("1x " + article.getLabel(), hash);

      attributedString.addAttribute(TextAttribute.FONT, fntBold);

      g2d.setFont(fntBold);
      FontRenderContext frc = g2d.getFontRenderContext();

      AttributedCharacterIterator attributedCharacterIterator = attributedString.getIterator();

      intstart = attributedCharacterIterator.getBeginIndex();
      intend = attributedCharacterIterator.getEndIndex();

      lineBreakMeasurer = new LineBreakMeasurer(attributedCharacterIterator, frc);

      float width = (float) intPageWidth - intMarginLeft;

      int X = intMarginLeft;

      lineBreakMeasurer.setPosition(intstart);

      // Create TextLayout accordingly and draw it
      while (lineBreakMeasurer.getPosition() < intend) {

        TextLayout textLayout = lineBreakMeasurer.nextLayout(width);

        intMeasureY += textLayout.getAscent();
        X = intMarginLeft;

        textLayout.draw(g2d, X, intMeasureY);
        intMeasureY += textLayout.getDescent() + textLayout.getLeading();
      }

      // Draw the label
      String label = actualLine.getBemerkung();

      if (actualLine.getDosis().length() > 0) {

        label = actualLine.getDosis() + ", " + label;
      }

      // If there is no label specified, go to the next iterations
      if (label.length() == 0) {
        intMeasureY += intSpaceBig * 2;
        continue;
      }

      attributedString = new AttributedString(label, hash);

      attributedString.addAttribute(TextAttribute.FONT, fnt);

      g2d.setFont(fnt);
      frc = g2d.getFontRenderContext();

      attributedCharacterIterator = attributedString.getIterator();

      intstart = attributedCharacterIterator.getBeginIndex();
      intend = attributedCharacterIterator.getEndIndex();

      lineBreakMeasurer = new LineBreakMeasurer(attributedCharacterIterator, frc);

      lineBreakMeasurer.setPosition(intstart);

      // Create TextLayout accordingly and draw it
      while (lineBreakMeasurer.getPosition() < intend) {

        // Extra code to determine line breaks in the string --> go on new line, if there is one
        int next = lineBreakMeasurer.nextOffset(width);
        int limit = next;
        if (limit <= label.length()) {
          for (int k = lineBreakMeasurer.getPosition(); k < next; ++k) {
            char c = label.charAt(k);
            if (c == '\n') {
              limit = k + 1;
              break;
            }
          }
        }

        TextLayout textLayout = lineBreakMeasurer.nextLayout(width, limit, false);

        intMeasureY += textLayout.getAscent();
        X = intMarginLeft;

        textLayout.draw(g2d, X, intMeasureY);
        intMeasureY += textLayout.getDescent() + textLayout.getLeading();
      }

      intMeasureY += intSpaceBig * 2;
    }

    // (7) Draw now the Footer:

    // Create the barcodes
    Barcode bc = new Barcode();

    this.imgCode128 = bc.getCode128(presID);
    this.imgQRCode = bc.getQRCode(QRCode);

    // (a) Code 128 with decoded String
    g.setFont(fntBold);
    metrics = g.getFontMetrics(fntBold);
    int xPrescId =
        intPageWidth
            - Code128Width
            + Integer.valueOf(
                (int) Math.round((Code128Width - metrics.stringWidth(this.presID)) / 2));

    g.drawString(this.presID, xPrescId, pageHeight);

    g.drawImage(
        imgCode128,
        intPageWidth - Code128Width,
        pageHeight - Code128Height - intDefaultHeight,
        Code128Width,
        Code128Height,
        null);

    // (b) QR-Code
    g.drawImage(
        imgQRCode, intMarginLeft, pageHeight - QRCodeBorder, QRCodeBorder, QRCodeBorder, null);

    // (c) Promotion-String
    g.setColor(Color.gray);
    metrics = g.getFontMetrics(fntItalic);
    g.setFont(fntItalic);
    g.drawString(
        PROMO,
        Integer.valueOf(
            (int) Math.round((intMarginLeft + (QRCodeBorder - metrics.stringWidth(PROMO)) / 2))),
        pageHeight);

    // set to default
    g.setColor(Color.black);
    g.setFont(fnt);

    // (8) Return, that this page exists and thus will be rendered and printed
    return (PAGE_EXISTS);
  }