0

JTextPaneHTMLDocument およびを使用して単純な HTML エディターを実装していますHTMLEditorKit。コードは次のようになります。

public class SimpleHTMLEditor extends JFrame {

    private static final long   serialVersionUID = 1L;

    private final JTextPane   textPane;

    private final HTMLEditorKit edtKit;

    private HTMLDocument  doc;

    public static void main(String[] args) {
        final SimpleHTMLEditor editor = new SimpleHTMLEditor();
        editor.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        editor.setVisible(true);
    }

    public SimpleHTMLEditor() {
        super("Simple HTML Editor");
        textPane = new JTextPane();
        edtKit = new HTMLEditorKit();
        textPane.setEditorKit(edtKit);
        doc = new HTMLDocument();
        textPane.setDocument(doc);

    final Container content = getContentPane();
        content.add(textPane, BorderLayout.CENTER);
        content.add(createToolBar(), BorderLayout.NORTH);
        setJMenuBar(createMenuBar());
        setSize(500, 240);
        textPane.requestFocusInWindow();
    }

    /**
     * Creates the toolbar with the combo box that allows for creation and
     * use of different conditions with their respective presentation styles.
     * @return The toolbar
     */
    private JToolBar createToolBar() {
        final JToolBar bar = new JToolBar();
        return bar;
    }

    /**
     * Creates the menu bar. It contains:
     * <li> Actions to read/write HTML file
     * <li> Action to display the HTML source in a popup window.
     * @return The menu bar
     */
    private JMenuBar createMenuBar() {
        final JMenuBar menubar = new JMenuBar();
        final JMenu mnuFile = new JMenu("File");
        menubar.add(mnuFile);
        final SaveAction actSave = new SaveAction();
        mnuFile.add(actSave);
        final LoadAction actLoad = new LoadAction();
        mnuFile.add(actLoad);
        final JMenuItem mnuPreview = new JMenuItem("Preview");
        menubar.add(mnuPreview);
        mnuPreview.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                final HTMLPreview previewer = new HTMLPreview(SimpleHTMLEditor.this,
                                                              getDocSource());
                previewer.setVisible(true);
            }
        });

    return menubar;
    }

    /**
     * Helper method to extract the HTML source code from the HTML document
     * @return The HTML source code
     */
    private String getDocSource() {
        final StringWriter sw = new StringWriter();
        try {
            edtKit.write(sw, doc, 0, doc.getLength());
        } catch (IOException | BadLocationException e1) {
            e1.printStackTrace();
        }
        try {
            sw.close();
        } catch (final IOException e1) {
            e1.printStackTrace();
        }
        return sw.toString();
    }

    class SaveAction extends AbstractAction {
        private static final long serialVersionUID = 1L;
        public SaveAction() {
            super("Save to File");
        }
        @Override
        public void actionPerformed(ActionEvent ev) {
            final JFileChooser chooser = new JFileChooser();
            if (chooser.showSaveDialog(SimpleHTMLEditor.this) != JFileChooser.APPROVE_OPTION)
                return;
            final File targetFile = chooser.getSelectedFile();
            if (targetFile == null)
                return;
            FileWriter writer = null;
            try {
                writer = new FileWriter(targetFile);
                textPane.write(writer);
            } catch (final IOException ex) {
                JOptionPane.showMessageDialog(SimpleHTMLEditor.this,
                                              "File Not Saved", "ERROR",
                                              JOptionPane.ERROR_MESSAGE);
            } finally {
                if (writer != null) {
                    try {
                        writer.close();
                    } catch (final IOException x) {
                    }
                }
            }
        }
    }

    class LoadAction extends AbstractAction {
        private static final long serialVersionUID = 1L;
        public LoadAction() {
            super("Load from File");
        }
        @Override
        public void actionPerformed(ActionEvent ev) {
            final JFileChooser chooser = new JFileChooser();
            if (chooser.showOpenDialog(SimpleHTMLEditor.this) != JFileChooser.APPROVE_OPTION)
                return;
            final File sourceFile = chooser.getSelectedFile();
            if (sourceFile == null)
                return;
            FileReader reader = null;
            try {
                reader = new FileReader(sourceFile);
                doc = (HTMLDocument)edtKit.createDefaultDocument();
                textPane.setDocument(doc);
                edtKit.read(reader,doc,0);
            } catch (final IOException ex) {
                JOptionPane.showMessageDialog(SimpleHTMLEditor.this,
                                              "File '" + sourceFile.getAbsolutePath() +
                                              "' Not Loaded", "ERROR",
                                              JOptionPane.ERROR_MESSAGE);

        } catch (final BadLocationException e) {
                e.printStackTrace();
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (final IOException x) {
                    }
                }
            }
        }
    }
}

/**
 * Popup window for display of the current contents of the editor as HTML
 * source code.
 */
class HTMLPreview extends JDialog {

    private static final long serialVersionUID = 1L;

    public HTMLPreview(JFrame parent, String source) {
        super(parent, "HTML Source", true);

        final JPanel pp = new JPanel(new BorderLayout());
        pp.setBorder(new EmptyBorder(10, 10, 5, 10));

        final JTextArea srcTxtArea = new JTextArea(source, 20, 60);
        srcTxtArea.setFont(new Font("Courier", Font.PLAIN, 12));
        final JScrollPane sp = new JScrollPane(srcTxtArea);
        pp.add(sp, BorderLayout.CENTER);

        final JPanel p = new JPanel(new FlowLayout());
        final JPanel p1 = new JPanel(new GridLayout(1, 2, 10, 0));

        final JButton closeBtn = new JButton("Close");
        closeBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                dispose();
            }
        });
        p1.add(closeBtn);
        p.add(p1);
        pp.add(p, BorderLayout.SOUTH);
        getContentPane().add(pp, BorderLayout.CENTER);
        pack();
        setResizable(true);
        setLocationRelativeTo(parent);
    }
}

ネストされた SPAN 要素を含む HTML ファイルをロードすると、ネストがサイレントに削除されることに気付きました。HTML ファイルの例を次に示します。

<html>
  <head>
  </head>
  <body>
    <p>
      <span title="tag:one">Outer span. <span title="tag:two">Inner span.</span> Outer span continued.</span>
    </p>
  </body>
</html>

そのファイルをロードし、ツールバーで「プレビュー」アクションを選択すると、次のような HTML ソース コードを示すポップアップ ウィンドウが表示されます。

<html>
  <head>
  </head>
  <body>
    <p>
      <span title="tag:one">Outer span.</span> <span title="tag:two">Inner 
  span.</span> <span title="tag:one"> Outer span continued.</span>
    </p>
  </body>
</html>

ご覧のとおり、外側の SPAN 要素は 2 つの SPAN 要素に静かに分割され、内側の SPAN 要素は 2 つの間に配置されています。この動作は、HTML エディターを実現する Java Swing コンポーネントと、私が理解している限り、ネストされた SPAN 要素を許可する HTML 4.x 標準との間の非互換性の 1 つを示しているように思えます。私の質問は次のとおりです。回避策またはその制限を克服する (あまり複雑でないことを願っています) 方法はありますか。つまり、HTML テキストを読み取るときに遭遇するネストされた SPAN 要素を HTML エディターに保持させる方法はありますか?

apatwork さん、よろしくお願いします。

4

1 に答える 1