Reputation: 378
I have a simple swing application with two JTextPanes. In the first I write a html code and in the second I get the appearance defined by this html. I want to have button which allows me to insert a table into the document. Here is my code:
public class TestEditor extends JFrame {
public TestEditor(){
createConnection();
createGUI();
}
private void createGUI(){
setDefaultCloseOperation(EXIT_ON_CLOSE);
JScrollPane scroll1=new JScrollPane(text);
JScrollPane scroll2=new JScrollPane(html);
JSplitPane split=new JSplitPane();
split.setLeftComponent(scroll1);
split.setRightComponent(scroll2);
split.setDividerLocation(0.5);
split.setResizeWeight(0.5);
getContentPane().add(split);
table=new JButton("Insert table");
table.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StringBuilder builder=new StringBuilder("<table border=1>\n");
for(int i=0;i<4;i++){
builder.append("<tr>");
for(int j=0;j<4;j++){
builder.append("<td></td>");
}
builder.append("</tr>\n");
}
builder.append("</table>\n");
try{
text.getStyledDocument().insertString(text.getCaretPosition(), builder.toString(), null);
}catch(BadLocationException ex){
ex.printStackTrace();
}
}
});
getContentPane().add(table, BorderLayout.SOUTH);
setTitle("Test");
setPreferredSize(new Dimension(600,300));
pack();
}
private void createConnection(){
text=new JTextPane();
html=new JTextPane();
html.setContentType("text/html");
html.getStyledDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
update();
}
@Override
public void removeUpdate(DocumentEvent e) {
update();
}
@Override
public void changedUpdate(DocumentEvent e) {
update();
}
private void update(){
if(fromText) return;
fromHtml=true;
text.setText(html.getText());
fromHtml=false;
}
});
text.getStyledDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
update();
}
@Override
public void removeUpdate(DocumentEvent e) {
update();
}
@Override
public void changedUpdate(DocumentEvent e) {
update();
}
private void update(){
if(fromHtml) return;
fromText=true;
html.setText(text.getText());
fromText=false;
}
});
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new TestEditor().setVisible(true);
}
});
}
private JTextPane text;
private JTextPane html;
private boolean fromHtml, fromText;
private JButton table;
}
However, this inserts a table in the wrong place, most often after the ending tag </html>. My goal is to insert the table in the place in which caret is on the right editor. What should I do? How to detect the proper position?
Upvotes: 0
Views: 499
Reputation: 4277
I tested your code, and it fails when you are editing the styled document, but it works when you edit the text document. The reason is simple: when a call to update()
occurs, the use of setText()
puts the caret at the end of the document. The html code is then naturally inserted at the end.
So ideally you would want to keep track of the caret position and cleverly update it after setText()
. But this is not easy: How do you manage inserted or removed text?
So here is a proposal: When the "add table" button is clicked, detect which editor has focus (= where the caret position is relevant), and insert the html code in the corresponding one.
However, inserting html code in the styled document will be done slightly differently (to avoid being escaped):
HTMLEditorKit kit = (HTMLEditorKit) html.getEditorKit();
HTMLDocument doc = (HTMLDocument) html.getStyledDocument();
kit.insertHTML(doc, html.getCaretPosition(), builder.toString(), 0, 0, null);
So you should get something like that:
Component c = getFocusOwner();
if(c==html){
HTMLEditorKit kit = (HTMLEditorKit) html.getEditorKit();
HTMLDocument doc = (HTMLDocument) html.getStyledDocument();
kit.insertHTML(doc, html.getCaretPosition(), builder.toString(), 0, 0, null);
}else if(c==text){
text.getStyledDocument().insertString(text.getCaretPosition(), builder.toString(), null);
}
Also, make the button unfocusable to avoid getFocusOwner()
to detect the button click:
table.setFocusable(false);
Upvotes: 1