Swing eigenes StyledDocument

Status
Nicht offen für weitere Antworten.

marco_m

Neues Mitglied
Hallo, ich möche mir ein eigenes StyledDocument für einen WYSIWYG Editor schreiben. Dieses soll direkt auf meinen Content(der in einer ArrayList verwaltet wird) zugreifen. Ich hab mir jetzt schon eine eigene Content implementierung geschrieben, welche die Eingabe richtig in die ArrayList einfügt.

Das Problem vor dem ich aber nun stehe ist das ich, wenn die JTextPane meine StyledDocument implementierung, welche ich mit dem DefaultStyledDocument abgeglichen habe, verwendet ich immer nur das zuletzt getippte Zeichen an dem offset 0 angezeigt bekomme(obwohl es in der ArrayList richtig eingefügt wird).



Java:
package com.iig.ziawe.gui;

import com.iig.ziawe.ZiaweCore;
import com.iig.ziawe.actions.events.ZiaweDocumentEvent;
import com.iig.ziawe.block.Block;

import com.iig.ziawe.block.FormattedText;
import com.iig.ziawe.utils.Util;

import java.awt.Color;
import java.awt.Font;

import java.awt.font.TextAttribute;

import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Vector;

import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.EventListenerList;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.Position;
import javax.swing.text.Segment;
import javax.swing.text.StringContent;
import javax.swing.text.Style;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;

import sun.swing.SwingUtilities2;

public class ZiaweDocument implements StyledDocument {

  Element root;
  StyleContext context;
  ZiaweCore core;
  BlockContent content;
  EventListenerList documentListeners;
  EventListenerList undoableListeners;
  private Dictionary<Object, Object> documentProperties = null;

  /**
   * Document property that indicates whether internationalization
   * functions such as text reordering or reshaping should be
   * performed. This property should not be publicly exposed,
   * since it is used for implementation convenience only.  As a 
   * side effect, copies of this property may be in its subclasses
   * that live in different packages (e.g. HTMLDocument as of now),
   * so those copies should also be taken care of when this property
   * needs to be modified.
   */
  static final String I18NProperty = "i18n";

  /**
   * Document property that indicates if a character has been inserted
   * into the document that is more than one byte long.  GlyphView uses
   * this to determine if it should use BreakIterator.
   */
  static final Object MultiByteProperty = "multiByte";

  public ZiaweDocument() {

    FormattedText defaultRoot = new FormattedText(" ");
    StyleContext def = StyleContext.getDefaultStyleContext();
    defaultRoot.setElemParams(null, new Vector(), 
                              def.getStyle(StyleContext.DEFAULT_STYLE), 0, 
                              this);

    core = ZiaweCore.getInstance();

    core.getBlockList().add(defaultRoot);
    this.content = new BlockContent(core.getBlockList());
    this.root = defaultRoot;
    this.context = def;
    this.putProperty(this.I18NProperty, false);
    this.putProperty(this.MultiByteProperty, false);
    this.getStartPosition();
  }

  public Style addStyle(String nm, Style parent) {
    return context.addStyle(nm, parent);
  }

  public void removeStyle(String nm) {
    context.removeStyle(nm);
  }

  public Style getStyle(String nm) {
    return context.getStyle(nm);
  }

  public void setCharacterAttributes(int offset, int length, AttributeSet s, 
                                     boolean replace) {
    FormattedText fm = this.getFormattedTextFromPosition(offset);
    if (fm != null) {
      fm.addAttributes(s);
    }
    //TODO selection formatieren und nicht gesamten block
  }

  public void setParagraphAttributes(int offset, int length, AttributeSet s, 
                                     boolean replace) {
    //TODO Step 1: implement code
    //TODO Step 2: ???
    //TODO Step 3: Profit
    this.setCharacterAttributes(offset, length, s, replace);
  }

  public void setLogicalStyle(int pos, Style s) {
    //TODO ???
    setCharacterAttributes(pos, 0, s, true);
  }

  public Style getLogicalStyle(int p) {
    FormattedText fm = this.getFormattedTextFromPosition(p);
    if (fm != null) {
      return (Style) fm.getResolveParent();
    }
    return null;
  }

  public Element getParagraphElement(int pos) {
    return this.getFormattedTextFromPosition(pos);
  }

  public Element getCharacterElement(int pos) {
    return this.getParagraphElement(pos);
  }

  public Color getForeground(AttributeSet attr) {
    return context.getForeground(attr);
  }

  public Color getBackground(AttributeSet attr) {
    return context.getBackground(attr);
  }

  public Font getFont(AttributeSet attr) {
    return context.getFont(attr);
  }

  public int getLength() {
    return content.length();
  }

  public void addDocumentListener(DocumentListener listener) {
    if (this.documentListeners == null) {
      documentListeners = new EventListenerList();
    }
    this.documentListeners.add(DocumentListener.class, listener);
  }

  public void removeDocumentListener(DocumentListener listener) {
    if (this.documentListeners.getListenerCount() != 0) {
      documentListeners.remove(DocumentListener.class, listener);
    }
  }

  public void addUndoableEditListener(UndoableEditListener listener) {
    if (this.undoableListeners == null) {
      this.undoableListeners = new EventListenerList();
    }
    this.undoableListeners.add(UndoableEditListener.class, listener);
  }

  public void removeUndoableEditListener(UndoableEditListener listener) {
    if (this.undoableListeners.getListenerCount() != 0) {
      undoableListeners.remove(UndoableEditListener.class, listener);
    }
  }

  public Object getProperty(Object key) {
    return this.documentProperties.get(key);
  }

  public void putProperty(Object key, Object value) {
    if (value != null) {
      this.getDocumentProperties().put(key, value);
    }
  }

  public void remove(int offs, int len) {
    try {
      content.remove(offs, len);
    } catch (BadLocationException e) {
      e.printStackTrace();
    }
  }

  public void insertString(int offset, String str, AttributeSet a) {
    if (str == null || (str.length() == 0)) {
      return;
    }
    FormattedText fm = this.getFormattedTextFromPosition(offset);
    ZiaweDocumentEvent event = 
      new ZiaweDocumentEvent(offset, str.length(), DocumentEvent.EventType.INSERT, 
                             this);
    if (fm != null) {
      fm.addAttributes(a);
      try {

        content.insertString(offset, str);
        this.getEndPosition();

        if (getProperty(I18NProperty).equals(Boolean.FALSE)) {
          // if a default direction of right-to-left has been specified,
          // we want complex layout even if the text is all left to right.
          Object d = getProperty(TextAttribute.RUN_DIRECTION);
          if ((d != null) && (d.equals(TextAttribute.RUN_DIRECTION_RTL))) {
            putProperty(I18NProperty, Boolean.TRUE);
          } else {
            char[] chars = str.toCharArray();
            if (SwingUtilities2.isComplexLayout(chars, 0, chars.length)) {
              putProperty(I18NProperty, Boolean.TRUE);
            }
          }
        }

        insertUpdate(event, a);
        fireInsertUpdate(event);

      } catch (BadLocationException e) {
        e.printStackTrace();
      }
    }
  }

  public String getText(int offset, int length) {
    try {
      return content.getString(offset, length);
    } catch (BadLocationException e) {
      e.printStackTrace();
    }
    return null;
  }

  public void getText(int offset, int length, Segment txt) {
    try {
      content.getChars(offset, length, txt);
    } catch (BadLocationException e) {
      e.printStackTrace();
    }
  }

  public Position getStartPosition() {

    return content.createPosition(0);

  }

  public Position getEndPosition() {

    return content.createPosition(content.length() - 1);

  }

  public Position createPosition(int offs) {

    return content.createPosition(offs);

  }

  public Element[] getRootElements() {
    return new Element[] { this.root };
  }

  public Element getDefaultRootElement() {
    return this.root;
  }

  public void render(Runnable r) {
    r.run();
  }

  private FormattedText getFormattedTextFromPosition(int i) {
    Block blck = Util.findBlock(i, core.getBlockList()).getBlock();
    if (blck instanceof FormattedText) {
      return (FormattedText) blck;
    }
    return null;
  }

  public Dictionary<Object, Object> getDocumentProperties() {
    if (documentProperties == null) {
      documentProperties = new Hashtable(2);
    }
    return documentProperties;
  }

  protected void fireInsertUpdate(DocumentEvent e) {

    // Guaranteed to return a non-null array
    Object[] listeners = this.documentListeners.getListenerList();
    // Process the listeners last to first, notifying
    // those that are interested in this event
    for (int i = listeners.length - 2; i >= 0; i -= 2) {
      if (listeners[i] == DocumentListener.class) {
        // Lazily create the event:
        // if (e == null)
        // e = new ListSelectionEvent(this, firstIndex, lastIndex);
        ((DocumentListener) listeners[i + 1]).insertUpdate(e);
      }
    }

  }

  protected void fireChangedUpdate(DocumentEvent e) {

    // Guaranteed to return a non-null array
    Object[] listeners = this.documentListeners.getListenerList();
    // Process the listeners last to first, notifying
    // those that are interested in this event
    for (int i = listeners.length - 2; i >= 0; i -= 2) {
      if (listeners[i] == DocumentListener.class) {
        // Lazily create the event:
        // if (e == null)
        // e = new ListSelectionEvent(this, firstIndex, lastIndex);
        ((DocumentListener) listeners[i + 1]).changedUpdate(e);
      }
    }
  }

  protected void fireRemoveUpdate(DocumentEvent e) {
    // Guaranteed to return a non-null array
    Object[] listeners = this.documentListeners.getListenerList();
    // Process the listeners last to first, notifying
    // those that are interested in this event
    for (int i = listeners.length - 2; i >= 0; i -= 2) {
      if (listeners[i] == DocumentListener.class) {
        // Lazily create the event:
        // if (e == null)
        // e = new ListSelectionEvent(this, firstIndex, lastIndex);
        ((DocumentListener) listeners[i + 1]).removeUpdate(e);
      }
    }
  }

  /**
   * Updates document structure as a result of text insertion.  This
   * will happen within a write lock.  If a subclass of
   * this class reimplements this method, it should delegate to the
   * superclass as well.
   *
   * @param chng a description of the change
   * @param attr the attributes for the change
   */
  protected void insertUpdate(ZiaweDocumentEvent chng, AttributeSet attr) {

    // Check if a multi byte is encountered in the inserted text.
    if (chng.getType() == DocumentEvent.EventType.INSERT && 
        chng.getLength() > 0 && 
        !Boolean.TRUE.equals(getProperty(MultiByteProperty))) {
      Segment segment = new Segment();

      getText(chng.getOffset(), chng.getLength(), segment);
      segment.first();
      do {
        if ((int) segment.current() > 255) {
          putProperty(MultiByteProperty, Boolean.TRUE);
          break;
        }
      } while (segment.next() != Segment.DONE);

    }
  }

}
 

marco_m

Neues Mitglied
Daran habe ich auch schon gedacht, hab mich ja schon seit einer Woche mit dem Ding beschäftigt.

Es ist eine Vorgabe das der Text in Blöcken von ca 3000 Zeichen verwaltet wird.
Dieser Text wir von einer anderen Applikation geliefert und in der ArrayList abgelegt und genau diese ArrayList soll 1:1 der gleiche in der JTextPane sein. Um das zu erreichen wollte ich anfangs das DefaultStyledDocument verwenden mit einer eigenen Content implementierung, das funktionierte aber dann nicht wenn ich dann zb noch eine Formatierung dabeihaben wollte, deswegen die eigene StyledDocument Implementierung.


Hier ist dann noch meine Implementierung vom Content-Interface, vll hilft sie ja:
Java:
package ziawe.gui;

import ziawe.block.Block;
import ziawe.block.FormattedText;

import ziawe.utils.BlockPos;
import ziawe.utils.Params;
import ziawe.utils.Util;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.util.ArrayList;
import java.util.Vector;

import javax.swing.text.AbstractDocument;
import javax.swing.text.BadLocationException;
import javax.swing.text.GapContent;
import javax.swing.text.Position;
import javax.swing.text.Segment;
import javax.swing.undo.UndoableEdit;

public class BlockContent implements AbstractDocument.Content{
  ArrayList<Block> blockList;
  
  transient Vector marks;

  public BlockContent(ArrayList<Block> blockList) {
    this.blockList = blockList;
  }

  public Position createPosition(int offset) {
        if (marks == null) {
            marks = new Vector();
        }
    return new StickyPosition(offset);

    //    if (offset <= length())
    //      return new SimplePosition(offset);
    //    return null;
  }

  /**
   * the length of the content
   * @return length of the whole blockList FormattedText elements
   */
  public int length() {
    int size = 0;
    for (Block b: blockList) {
      if (b instanceof FormattedText) {
        size += b.getContent().length();
      }
    }
    return size;
  }

  public UndoableEdit insertString(int where, 
                                   String str) throws BadLocationException {
    int count = this.length();
    
    if (where >= count || where < 0) {
      throw new BadLocationException("Invalid location insertSring", count);
    }
    BlockPos bp = Util.findBlock(where, blockList);
    if (bp != null) {
      StringBuffer sb = bp.getBlock().getContent();
      if(Params.isOverwrite()){
        sb.replace(bp.getPosition(), bp.getPosition() + str.length(), str);
      }else{
        sb.insert(bp.getPosition(), str);
      }
    }
    if (marks != null) {
        updateMarksForInsert(where, str.length());
    }
    return null;
  }


  public UndoableEdit remove(int where, 
                             int nitems)
    throws BadLocationException {
    for(int i = 0; i<marks.size(); i++) {
      System.out.println("sticky position offset: " + ((PosRec)marks.get(i)).offset);
    }
    int count = this.length();
    System.out.println("remove count: " + count);
    System.out.println("remove where: " + where);
    System.out.println("remove items: " + nitems);
    if (where + nitems >= count) {
      marks.clear();
      this.createPosition(0);
      this.createPosition(count-1);
      nitems = count - where;
    }
    BlockPos bp = Util.findBlock(where, blockList);
    StringBuffer sb = bp.getStringBufferContent();
    int pos = bp.getPosition();
    if ((pos + nitems) > sb.length()) {
      int lengthBefore = sb.length();
      sb.replace(pos, pos + bp.getStringContent().length(), "");
      int diff = lengthBefore - sb.length();
      bp.setStringContent(sb);
      if (diff != nitems) {
        remove((pos + diff), nitems - diff);
      }
    } else {
      sb.replace(pos, pos + nitems, "");
    }
    if (marks != null) {
        updateMarksForRemove(where, nitems);
    }
    return null;

  }

  public String getString(int where, int len) throws BadLocationException {
    int count = this.length();
    if (where + len > count) {
      throw new BadLocationException("Invalid range getString", count);
    }
    String outstring = "";
    BlockPos bp = Util.findBlock(where, blockList);
    if(bp!=null)
    {
    String after = bp.getAfterPos();
    outstring = outstring + after;
    len = len - (after.length());
    int curPos = where + after.length();
    
    while (len > 0) {
      bp = Util.findBlock(curPos, blockList);
      if(len>=bp.getLength()) {
        outstring = outstring + bp.getStringContent();
        len-=bp.getLength();
        curPos += bp.getLength();
      }
      else {
        outstring = outstring + bp.getStringContent().substring(0, len); 
        len = -1;
      }
    }
    }
    return outstring;
  }

  public void getChars(int where, int len, 
                       Segment txt) throws BadLocationException {
    int count = this.length();
    if (where + len > count) {
      //throw new BadLocationException("Invalid range getChars", count);
      len = count - where-1;
    }
    txt.array = this.buildContentString().toCharArray();
    txt.offset = where;
    txt.count = len;
  }

  private String buildContentString() {
    StringBuffer out = new StringBuffer();
    for (Block b: blockList) {
      if (b instanceof FormattedText) {
        out.append(b.getContent());
      }
    }
    return out.toString();
    // if something goes wrong uncomment next line
    // Runtime.getRuntime().setGodMode(true);
  }

  public class SimplePosition implements Position {
    int offs;

    public SimplePosition(int offs) {
      this.offs = offs;
    }

    public int getOffset() {
      return offs;
    }
  }




      synchronized void updateMarksForInsert(int offset, int length) {
    if (offset == 0) {
        // zero is a special case where we update only
        // marks after it.
        offset = 1;
    }
    int n = marks.size();
    for (int i = 0; i < n; i++) {
        PosRec mark = (PosRec) marks.elementAt(i);
        if (mark.unused) {
      // this record is no longer used, get rid of it
      marks.removeElementAt(i);
      i -= 1;
      n -= 1;
        } else if (mark.offset >= offset) {
      mark.offset += length;
        }
    }
      }

      synchronized void updateMarksForRemove(int offset, int length) {
    int n = marks.size();
    for (int i = 0; i < n; i++) {
        PosRec mark = (PosRec) marks.elementAt(i);
        if (mark.unused) {
      // this record is no longer used, get rid of it
      marks.removeElementAt(i);
      i -= 1;
      n -= 1;
        } else if (mark.offset >= (offset + length)) {
      mark.offset -= length;
        } else if (mark.offset >= offset) {
      mark.offset = offset;
        }
    }
      }


  /**
   * holds the data for a mark... separately from
   * the real mark so that the real mark can be 
   * collected if there are no more references to
   * it.... the update table holds only a reference
   * to this grungy thing.
   */
  final class PosRec {

    PosRec(int offset) {
      this.offset = offset;
    }

    int offset;
    boolean unused;
  }

  /**
   * This really wants to be a weak reference but
   * in 1.1 we don't have a 100% pure solution for
   * this... so this class trys to hack a solution 
   * to causing the marks to be collected.
   */
  final class StickyPosition implements Position {

    StickyPosition(int offset) {
      rec = new PosRec(offset);
      marks.addElement(rec);
    }

    public int getOffset() {
      return rec.offset;
    }

    protected void finalize() throws Throwable {
      // schedule the record to be removed later
      // on another thread.
      rec.unused = true;
    }

    public String toString() {
      return Integer.toString(getOffset());
    }

    PosRec rec;
  }

}
 
Zuletzt bearbeitet von einem Moderator:
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
H LayoutManager RPG Programmieren, eigenes Spielfeld grafisch generieren aus Tileset AWT, Swing, JavaFX & SWT 18
O Swing "Eigenes" JPanel wird dem JScrollPane nicht hinzugefügt AWT, Swing, JavaFX & SWT 5
M Swing JComboBox eigenes Design AWT, Swing, JavaFX & SWT 3
L LookAndFeel Eigenes Design für die Applikation AWT, Swing, JavaFX & SWT 4
L JavaFX als eigenes Objekt AWT, Swing, JavaFX & SWT 3
M Plugin oder eigenes Tool mit zB SWING AWT, Swing, JavaFX & SWT 2
E Eigenes TableModel für ArrayList<String[]> AWT, Swing, JavaFX & SWT 5
N LookAndFeel Wie kann ich mein eigenes LookAndFeel machen? AWT, Swing, JavaFX & SWT 6
1 Eigenes Layout schreiben AWT, Swing, JavaFX & SWT 4
J Eigenes Gui/ Look and Feel AWT, Swing, JavaFX & SWT 14
D Eigenes Textfeld AWT, Swing, JavaFX & SWT 8
A Minimalestopuhr: JLabel.setText() durch eigenes Event ändern AWT, Swing, JavaFX & SWT 6
C Eigenes Hintergrundbild einfügen AWT, Swing, JavaFX & SWT 6
M Eigenes Panel aus Component? AWT, Swing, JavaFX & SWT 5
3 Eigenes Frame/Window programmieren AWT, Swing, JavaFX & SWT 2
F LayoutManager Eigenes Layout die Lösung?! AWT, Swing, JavaFX & SWT 4
P Eigenes Textverarbeitungsprogramm AWT, Swing, JavaFX & SWT 4
R [JTree/DefaultTreeCellRenderer] eigenes Renderer-Panel, so breit wie der JTree AWT, Swing, JavaFX & SWT 2
Developer_X LookAndFeel Eigenes Look And Feel erstellen AWT, Swing, JavaFX & SWT 33
B SWT Eigenes Icon für CheckboxTreeViewer AWT, Swing, JavaFX & SWT 3
KrokoDiehl Swing Design-Frage: eigenes Line-Wrapping AWT, Swing, JavaFX & SWT 5
D eigenes Tablemodel, Zeile löschen ArrayindexOOB excp AWT, Swing, JavaFX & SWT 4
S JTree mit Daten aus Model füllen, eigenes TreeModel (gute Dokumentation des Problems) AWT, Swing, JavaFX & SWT 2
P Eigenes TableModel abgeleitet von AbstractTableModel (neue rows nicht sichtbar) AWT, Swing, JavaFX & SWT 6
M Eigenes ActionEvent / Eigener Listener AWT, Swing, JavaFX & SWT 2
A JTable, eigenes TableModel und dessen Objekte AWT, Swing, JavaFX & SWT 4
G JToolbar gleich als eigenes Fenster öffnen AWT, Swing, JavaFX & SWT 2
G Eigenes ComboBoxModel AWT, Swing, JavaFX & SWT 2
M eigenes DialogFenster AWT, Swing, JavaFX & SWT 4
L Button ändert eigenes Bild und Progressbar-Value nicht AWT, Swing, JavaFX & SWT 6
J eigenes JOptionPane ? AWT, Swing, JavaFX & SWT 2
D Eigenes Tooltip AWT, Swing, JavaFX & SWT 5
G eigenes option pane AWT, Swing, JavaFX & SWT 5
C Eigenes Event AWT, Swing, JavaFX & SWT 8
S Eigenes Package für die GUI? AWT, Swing, JavaFX & SWT 6
P Eigenes Look&Feel schreiben (Tutorials?) AWT, Swing, JavaFX & SWT 6
B Eigenes Events AWT, Swing, JavaFX & SWT 3
G für showInputDialog kein eigenes Icon auswählen AWT, Swing, JavaFX & SWT 6
M JDialog und eigenes Icon AWT, Swing, JavaFX & SWT 10
M Strings im JTextPane vergleichen und mit StyledDocument formatieren AWT, Swing, JavaFX & SWT 3
D StyledDocument Problem AWT, Swing, JavaFX & SWT 2
T Swing xml in JTextPane mit EditorKit, StyledDocument & co. AWT, Swing, JavaFX & SWT 3
K MenuItem, StyledDocument remove AWT, Swing, JavaFX & SWT 16
D StyledDocument dauerhaft speichern AWT, Swing, JavaFX & SWT 3
G JComboBox mit StyledDocument AWT, Swing, JavaFX & SWT 3
P JTextPane und StyledDocument AWT, Swing, JavaFX & SWT 5
F Problem mit geänderten AttributSet beim StyledDocument AWT, Swing, JavaFX & SWT 4
U JTextPane, StyledDocument & UndoManager AWT, Swing, JavaFX & SWT 5
C StyledDocument: Zeilen auslesen AWT, Swing, JavaFX & SWT 2

Ähnliche Java Themen

Neue Themen


Oben