Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / GUI / August 2005

Tip: Looking for answers? Try searching our database.

JTexPane: Cross-platform chaos

Thread view: 
Wired Earp - 28 Aug 2005 12:56 GMT
I've extended a JTextPane to preserve tabindex and implement block-
indentation. It is supposed to work much like a code editor. Check out the
resulting applet, rigged up for Firefox only, over at:

   <url:http://www.wunderbyte.com/editorapplet>

I realize you may not have multuple operating systems running
simultaniously, so you have to trust me on this: It works perfectly on
Linux but fails on Windows. Things get calculated weirdly and unpredictably
and I have absolutely no idea where to start looking:

- does Java on Windows not use '\n' and '\t' characters?
- is it a bug in the JtextPane implementation on Windows?
- is my thinking not straight?

I've spent a lot of time learning Java so that I could build this applet,
and I have loads of dependant application code prepared already, so I would
*really* appreciate it if you could look it over and maybe come up with a
hint. Here's the source code in txt-format:

   <url:http://www.wunderbyte.com/editorapplet/EditorTextPane.txt>

Signature

Wired Earp
Wunderbyte

Mark Thornton - 28 Aug 2005 13:27 GMT
> I've extended a JTextPane to preserve tabindex and implement block-
> indentation. It is supposed to work much like a code editor. Check out the
[quoted text clipped - 8 lines]
>
> - does Java on Windows not use '\n' and '\t' characters?

You have to use the platform specific line separator (\n on unix, \r\n
for windows, \r for MAC). Use System.getProperty("line.separator") to
obtain the correct value. Some things tolerate any of these line
separators, while other code only functions correctly with the platform
separator string.

Mark Thornton
Andrew Thompson - 28 Aug 2005 13:51 GMT
> You have to use the platform specific line separator (\n on unix, \r\n
> for windows, \r for MAC). Use System.getProperty("line.separator") to
> obtain the correct value.

The thing that has always confounded me is, assuming you
are writing a document in a Java editor on Windows that
is intended for readers using *nix/Mac, how do you get
the EOL for *another* platform?

[ In the end I hard coded them, and left it to the
end user to select the one they wanted! ]

Signature

Andrew Thompson
physci.org 1point1c.org javasaver.com lensescapes.com athompson.info
"Got no time to pack my bag, my foot's outside the door"
Led Zeppelin 'The Ocean'

Mark Thornton - 28 Aug 2005 15:07 GMT
>>You have to use the platform specific line separator (\n on unix, \r\n
>>for windows, \r for MAC). Use System.getProperty("line.separator") to
[quoted text clipped - 7 lines]
> [ In the end I hard coded them, and left it to the
> end user to select the one they wanted! ]

I think the most appropriate way to handle this is for applications
which read text documents to have an option to adjust the line end
convention while reading in the text. This could be done either
automatically or by explicit request. For example the Windows WordPad
application will convert unix line endings automatically to the Windows
convention.
Of course many existing applications don't do this, so it is also
desirable to have an option when writing a text document to select a
line ending convention. The set of such strings must of course be hard
coded (or in a properties file).

Mark Thornton
Andrew Thompson - 28 Aug 2005 13:39 GMT
> - does Java on Windows not use '\n' and '\t' characters?

EOL on Windows is \r\n.

Signature

Andrew Thompson
physci.org 1point1c.org javasaver.com lensescapes.com athompson.info
"It's a never ending battle, for a peace that's always torn.."
Bob Dylan 'Shelter from the Storm'

Christian Kaufhold - 28 Aug 2005 15:28 GMT
> and I have loads of dependant application code prepared already, so I would
> *really* appreciate it if you could look it over and maybe come up with a
> hint. Here's the source code in txt-format:
>
>    <url:http://www.wunderbyte.com/editorapplet/EditorTextPane.txt>

Do not use getText() (which returns in platform- etc. specific text), but
getDocument().getText() (which always uses '\n' for newline, and which caret
and selection positions refer to).

Christian
Wired Earp - 28 Aug 2005 17:39 GMT
Christian Kaufhold wrote:

> Do not use getText() (which returns in platform- etc. specific text),
> but getDocument().getText() (which always uses '\n' for newline, and
> which caret and selection positions refer to).

Wow, great, thanks alot! Thought for a moment that I had to build my own
cross-platform abstraction layer for this stuff; this tip really does the
trick! I really like this newsgroup - I've gotten lot's of useful input
in just a few hours, only too bad I ran into another cross-platform
issue: My internet provider makes it available for Windows newsclients,
but it is invisible to my Linux desktop. Really strange.

Thanks again! Here comes the working source code for whoever might
stumble upon this thread someday:

import java.applet.Applet;
import java.awt.Color;
import java.awt.Event;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.text.AbstractDocument;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import javax.swing.text.TabSet;
import javax.swing.text.TabStop;
import javax.swing.InputMap;
import javax.swing.JTextPane;
import javax.swing.KeyStroke;

public class EditorTextPane extends JTextPane implements KeyListener {

 private boolean wrap = false;
 private AbstractDocument doc;
 private StyledDocument styledDoc;
 private Applet container;

 // newline and tab
 private final static char NEW = '\n', TAB = '\t';

 // snapshot variables
 private String value;
 private boolean isSelection;
 private boolean isEnd;
 private int start;
 private int end;
 private String selection;

 // syntax painter
 private SimpleAttributeSet textattributes = new SimpleAttributeSet();

 /**
  * Construct
  */
 public EditorTextPane() {

   super();

   styledDoc = getStyledDocument();
   doc = (AbstractDocument) styledDoc;
   StyleConstants.setForeground(textattributes, Color.BLACK);

   // keybindings, keylisteners and undolistener
   addKeyBindings();
   addKeyListener(this);
 }

 private void addKeyBindings() {

   InputMap inputMap = this.getInputMap();

   KeyStroke cut = KeyStroke.getKeyStroke
      (KeyEvent.VK_X, Event.CTRL_MASK);
   KeyStroke copy = KeyStroke.getKeyStroke
      (KeyEvent.VK_C, Event.CTRL_MASK);
   KeyStroke paste = KeyStroke
       .getKeyStroke(KeyEvent.VK_V, Event.CTRL_MASK);

   inputMap.put(cut, DefaultEditorKit.cutAction);
   inputMap.put(copy, DefaultEditorKit.copyAction);
   inputMap.put(paste, DefaultEditorKit.pasteAction);
 }

 /**
  * Insert text at caret position
  * @param text
  */
 public void insertText(String text) {
   try {
     doc.insertString(getCaretPosition(), text, textattributes);
   } catch (BadLocationException e) {
     System.out.println(e.getStackTrace());
   }
 }

 /**
  * Insert new text, delete all previous content
  * @param text
  */
 public void insertNewText(String text) {

   setText("");
   try {
     Document blank = new DefaultStyledDocument();
     setDocument(blank);
     doc.insertString(0, text, textattributes);
     setDocument(doc);
   } catch (BadLocationException e) {
     System.out.println("paint method: bad location");
   }
 }

 /**
  * Insert char at caret position
  * @param character
  */
 private void insertChar(char character) {
   insertText(String.valueOf(character));
 }

 /**
  * Snapshot current setup
  */
 private void snapshot() {

   int selectionStart = this.getSelectionStart();
   int selectionEnd = this.getSelectionEnd();

   try {
     int length = doc.getLength();
     value = doc.getText(0, length);
   } catch (BadLocationException e) {
     System.out.println("snapshot: bad location");
   }
   isSelection = selectionStart != selectionEnd;
   isEnd = selectionStart < selectionEnd;
   start = isEnd ? selectionStart : selectionEnd;
   end = isEnd ? selectionEnd : selectionStart;
   selection = isSelection ? value.substring(start, end) : null;
 }

 /**
  * must implement
  */
 public void keyTyped(KeyEvent event) {
 }

 public void keyReleased(KeyEvent event) {
 }

 /**
  * intercepting tabs and newlines
  */
 public void keyPressed(KeyEvent event) {
   switch (event.getKeyCode()) {
   case KeyEvent.VK_TAB:
     insertTabChar(event.isShiftDown());
     event.consume();
     break;
   case KeyEvent.VK_ENTER:
     insertNewLine();
     event.consume();
     break;
   }
 }

 /**
  * insert tabs before newline character
  */
 private void insertNewLine() {
   snapshot(); // snapshot current setup
   StringBuffer tabs = new StringBuffer();
   int indent = getIndentation(), i = 0;
   while (i++ < indent)
     tabs.append(TAB);
   insertText(NEW + tabs.toString());
 }

 /**
  * manage keyboard tabbing, implementing blockindent.
  * @param isUnindent
  */
 private void insertTabChar(boolean isUnindent) {

   snapshot(); // snapshot current setup

   if (isSelection) { // blockindent

     StringBuffer buffer = new StringBuffer();
     int count = 0;
     int selectStart = start;
     int selectEnd = end;

     // expand to nearest newlines
     while (start > 0 && value.charAt(start) != NEW)
       start--;
     while (end < value.length() && value.charAt(end) != NEW)
       end++;

     // isolate each line
     String temp = value.substring(start, end);
     String[] lines = temp.split(String.valueOf(NEW));

     // iterate lines, rebuilding tabs and newlines
     for (int it = (start == 0 ? 0 : 1); it < lines.length; it++) {
       if (!(start == 0 && it == 0))
         buffer.append(NEW);
       String line = lines[it];
       if (isUnindent) {
         if (line.charAt(0) == TAB) {
           buffer.append(line.substring(1, line.length()));
           count++;
         } else
           buffer.append(line);
       } else {
         buffer.append(TAB + line);
         count++;
       }
     }
     // replace old text with new
     // TODO: optimize large selections
     try {
       doc.remove(start, temp.length());
     } catch (BadLocationException e) {
       System.out.print(e.getStackTrace());
     }
     insertText(buffer.toString());

     // restore selection
     int mod = isUnindent ? -1 : 1;
     if (count > 0) {
       selectStart = selectStart + mod;
       selectEnd = selectEnd + count * mod;
     }
     setSelectionStart(isEnd ? selectStart : selectEnd);
     setSelectionEnd(isEnd ? selectEnd : selectStart);
   }

   // normal indent
   else {
     if (isUnindent) {
       System.out.println("TODO!");
     } else
       insertChar(TAB);
   }
 }

 /**
  * compute indendation level of current line
  * @return indent
  */
 private int getIndentation() {
   int iTabs = 0;
   int iChar = start - 1;
   char current;
   while (iChar >= 0) {
     current = value.charAt(iChar);
     if (current == NEW)
       break;
     else if (current == TAB)
       iTabs++;
     else
       iTabs = 0;
     iChar--;
   }
   return iTabs;
 }

 /**
  * Set the text style.
  * Tab matrix calculation presupposes a monospaced font
  * @param fontFamily
  * @param fontSize
  * @param charsPerTab
  */
 public void setTextStyle
    (String fontFamily, int fontSize, int charsPerTab) {

   Font font = new Font(fontFamily, Font.PLAIN, fontSize);
   this.setFont(font);
   StyleConstants.setFontFamily(textattributes, font.getFamily());
   StyleConstants.setFontSize(textattributes, font.getSize());

   FontMetrics fm = getFontMetrics(font);
   int charWidth = fm.charWidth('m');
   int tabWidth = charWidth * charsPerTab;

   TabStop[] tabs = new TabStop[100];
   for (int j = 0; j < tabs.length; j++) {
     int tab = j + 1;
     tabs[j] = new TabStop(tab * tabWidth);
   }
   TabSet tabSet = new TabSet(tabs);
   StyleConstants.setTabSet(textattributes, tabSet);
   getStyledDocument().setParagraphAttributes(0,
       getDocument().getLength(), textattributes, true);
 }

}

Signature

Wired Earp
Wunderbyte



Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.