3

I would like to know how to count the number of spaces on a given line before the text actually begins. For ex. if I have this in my JTextPane:

public static void main(String[] args) {
    int x = 1;

}

after I type 'x = 1;' and press enter, I would like to have the caret on the same indentation as the 'int x = 1;' starts, so I don't have to keep pressing tab or entering spaces manually. Any suggestions?

Vince
  • 2,596
  • 11
  • 43
  • 76
  • If you are attempting to implement a source code editor, you may wish to check out the JEditorPane [https://docs.oracle.com/javase/tutorial/uiswing/components/editorpane.html](https://docs.oracle.com/javase/tutorial/uiswing/components/editorpane.html) and the StyledEditorKit [https://docs.oracle.com/javase/8/docs/api/javax/swing/text/StyledEditorKit.html](https://docs.oracle.com/javase/8/docs/api/javax/swing/text/StyledEditorKit.html). – VirtualMichael Jul 28 '15 at 00:42
  • If any of our solutions solved your problem, please select the best answer. If you still have trouble, please, let us know. – Sharcoux Sep 15 '15 at 11:08

3 Answers3

1

If you want your new line to have the same indentation as the previous one, you can do that by simply checking the first characters of the previous line. Look at that :

public class Test {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame mainFrame = new JFrame("test");
                mainFrame.setSize(300, 100);
                mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                Container pane = mainFrame.getContentPane();
                pane.setLayout(new BorderLayout());

                JTextPane jtp = new JTP();
                pane.add(jtp);

                mainFrame.setVisible(true);
            }
        });
    }

    static class JTP extends JTextPane {
        JTP() {
            ((AbstractDocument)getDocument()).setDocumentFilter(new Filter());
        }
    }

    static class Filter extends DocumentFilter {
        @Override
        public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
            StringBuilder indentatedString = new StringBuilder(string);
            if(string.equals("\n")) {
                AbstractDocument doc = ((AbstractDocument)fb.getDocument());
                Element line = doc.getParagraphElement(offset);
                int lineStart = line.getStartOffset(), lineEnd = line.getEndOffset();
                String content = doc.getText(lineStart, lineEnd - lineStart);
                int start = 0;
                while(content.charAt(start)==' ') {
                    indentatedString.insert(0," ");
                    start++;
                }
            }
            fb.insertString(offset, indentatedString.toString(), attr);
        }
        @Override
        public void replace(FilterBypass fb, int offset, int length, String text,
                            AttributeSet attrs) throws BadLocationException {
            if(text.==0) {insertString(fb, offset, text, attrs);}
            else if(text.length()>0) {remove(fb, offset, length);insertString(fb, offset, text, attrs);}
            else {fb.replace(offset, length, text, attrs);}
        }
    }
}

The important part here is only the DocumentFilter that does the job.

Sharcoux
  • 5,546
  • 7
  • 45
  • 78
  • In the filter no need to pass document instance. FilterBypass provides getDocument() you can use to get the text. No need to extend JTextPane and install StyledEditorKit. The DocumentFilter will work for any EditorKit, all you need is to find nearest \n after offset in the text.. No need to indentation+=" "; in the loop. It's better to use StringBuilder. Replace for length >0 should also process this. E.g. when I select a char and press ENTER. But 1+ anyway:) – StanislavL Jul 29 '15 at 08:38
  • You're 100% right. It's been a while now since I played with all this and I forgot about the details. I edited my answer accordingly. Tell me if I forgot anything. Thanks. – Sharcoux Jul 29 '15 at 12:54
0

First, check this: Read JTextPane line by line

Then you can just get the line and count the number of spaces.

int spaces = s.length() - s.replaceAll("^\\s+", "").length();

Community
  • 1
  • 1
MC10
  • 552
  • 1
  • 12
  • 26
0

Split the text of the JTextPane by '\n' and search each line until you find the String you're searching for.

If the line you're on doesn't have the String you're searching for then you add the length of that line + 1 (to include the '\n') to a sum.

If the line you're on does have the String, then starting from the beginning of the line count the number of spaces until you reach the 1st non-space character and add that number to the sum.

With the sum, you would just provide it to the JTextPane.setCaretPosition(). Something like:

int caretPosition = 0;
String[] lines = jTextPane1.getText().split("\n");
for (String line : lines) {
    if (line.contains(search)) {
        for (int i = 0; i < line.length(); i++) {
            if (line.charAt(i) != ' ') {
                break;
            }
            caretPosition++;
        }
        break;
    } else {
        // +1 to include the '\n' character
        caretPosition += line.length() + 1;
    }
}

jTextPane1.setCaretPosition(caretPosition);
Shar1er80
  • 9,001
  • 2
  • 20
  • 29