/* * Copyright 2015 Igor Maznitsa. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.igormaznitsa.nbmindmap.nb.swing; import com.igormaznitsa.mindmap.model.logger.Logger; import com.igormaznitsa.mindmap.model.logger.LoggerFactory; import com.igormaznitsa.mindmap.swing.services.UIComponentFactory; import com.igormaznitsa.mindmap.swing.services.UIComponentFactoryProvider; import com.igormaznitsa.nbmindmap.utils.NbUtils; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.File; import java.io.IOException; import java.util.Locale; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; import javax.swing.JEditorPane; import javax.swing.JScrollPane; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import javax.swing.filechooser.FileFilter; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.EditorKit; import javax.swing.text.JTextComponent; import org.apache.commons.io.FileUtils; import org.netbeans.api.editor.settings.SimpleValueNames; import org.netbeans.editor.BaseDocument; import org.netbeans.editor.Utilities; import org.netbeans.modules.editor.indent.spi.CodeStylePreferences; import org.openide.filesystems.FileChooserBuilder; import org.openide.text.CloneableEditorSupport; import org.openide.text.NbDocument; public final class PlainTextEditor extends javax.swing.JPanel implements CaretListener { private static final UIComponentFactory UI_COMPO_FACTORY = UIComponentFactoryProvider.findInstance(); private enum Wrapping { NONE("none", "off"), WORDS("words", "words"), CHARS("chars", "chars"); private final String value; private final String display; private Wrapping (final String val, final String display) { this.value = val; this.display = display; } public String getValue () { return this.value; } public String getDisplay () { return this.display; } public Wrapping next () { final int index = this.ordinal() + 1; if (index >= Wrapping.values().length) { return NONE; } else { return Wrapping.values()[index]; } } public static Wrapping findFor (final String text) { for (final Wrapping w : Wrapping.values()) { if (w.value.equalsIgnoreCase(text)) { return w; } } return NONE; } } private static final long serialVersionUID = 5847351391577028903L; private static final Logger LOGGER = LoggerFactory.getLogger(PlainTextEditor.class); private final BaseDocument document; private Component lastComponent; private JEditorPane lastEditor; private final Wrapping oldWrapping; private Wrapping wrapping; private static final FileFilter TEXT_FILE_FILTER = new FileFilter() { @Override public boolean accept (final File f) { return f.isDirectory() || f.getName().toLowerCase(Locale.ENGLISH).endsWith(".txt"); //NOI18N } @Override public String getDescription () { return java.util.ResourceBundle.getBundle("com/igormaznitsa/nbmindmap/i18n/Bundle").getString("PlainTextEditor.fileFilter.description"); } }; public PlainTextEditor (final String text) { initComponents(); final JEditorPane editor = UI_COMPO_FACTORY.makeEditorPane(); editor.setEditorKit(getEditorKit()); this.document = Utilities.getDocument(editor); setText(text); final Preferences docPreferences = CodeStylePreferences.get(this.document).getPreferences(); this.oldWrapping = Wrapping.findFor(docPreferences.get(SimpleValueNames.TEXT_LINE_WRAP, "none")); this.wrapping = oldWrapping; this.lastComponent = makeEditorForText(this.document); this.lastComponent.setPreferredSize(new Dimension(620, 440)); this.add(this.lastComponent, BorderLayout.CENTER); this.labelWrapMode.setMinimumSize(new Dimension(55, this.labelWrapMode.getMinimumSize().height)); updateBottomPanel(); } private Component makeEditorForText (final Document document) { if (this.lastEditor != null) { this.lastEditor.removeCaretListener(this); } this.lastEditor = UI_COMPO_FACTORY.makeEditorPane(); this.lastEditor.setEditorKit(getEditorKit()); this.lastEditor.setDocument(document); this.lastEditor.addCaretListener(this); final Component result; if (document instanceof NbDocument.CustomEditor) { NbDocument.CustomEditor ce = (NbDocument.CustomEditor) document; result = ce.createEditor(this.lastEditor); } else { final JScrollPane scroll = UI_COMPO_FACTORY.makeScrollPane(); scroll.setViewportView(this.lastEditor); result = scroll; } this.caretUpdate(null); return result; } private static EditorKit getEditorKit () { return CloneableEditorSupport.getEditorKit("text/plain"); //NOI18N } public String getText () { try { return this.document.getText(0, this.document.getLength()); } catch (BadLocationException e) { LOGGER.error("Can't get text", e); //NOI18N return null; } } private void updateBottomPanel () { this.labelWrapMode.setText("Wrap: " + this.wrapping.getDisplay()); } private void setText (final String text) { try { this.document.replace(0, 0, text, null); } catch (BadLocationException ex) { LOGGER.error("Can't set text", ex); //NOI18N throw new RuntimeException(ex); } } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings ("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { mainToolBar = new javax.swing.JToolBar(); buttonLoad = new javax.swing.JButton(); buttonSave = new javax.swing.JButton(); buttonCopy = new javax.swing.JButton(); buttonPaste = new javax.swing.JButton(); buttonClearAll = new javax.swing.JButton(); jPanel1 = new javax.swing.JPanel(); labelCursorPos = new javax.swing.JLabel(); jSeparator2 = new javax.swing.JSeparator(); labelWrapMode = new javax.swing.JLabel(); filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(16, 0), new java.awt.Dimension(16, 0), new java.awt.Dimension(16, 32767)); setLayout(new java.awt.BorderLayout()); mainToolBar.setFloatable(false); mainToolBar.setRollover(true); buttonLoad.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/nbmindmap/icons/disk16.png"))); // NOI18N java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("com/igormaznitsa/nbmindmap/i18n/Bundle"); // NOI18N buttonLoad.setText(bundle.getString("PlainTextEditor.buttonImport")); // NOI18N buttonLoad.setToolTipText(bundle.getString("PlainTextEditor.buttonLoad.toolTipText")); // NOI18N buttonLoad.setFocusable(false); buttonLoad.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); buttonLoad.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); buttonLoad.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { buttonLoadActionPerformed(evt); } }); mainToolBar.add(buttonLoad); buttonSave.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/nbmindmap/icons/file_save16.png"))); // NOI18N buttonSave.setText(bundle.getString("PlaintextEditor.buttonExport")); // NOI18N buttonSave.setToolTipText(bundle.getString("PlainTextEditor.buttonSave.toolTipText")); // NOI18N buttonSave.setFocusable(false); buttonSave.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); buttonSave.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); buttonSave.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { buttonSaveActionPerformed(evt); } }); mainToolBar.add(buttonSave); buttonCopy.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/nbmindmap/icons/page_copy16.png"))); // NOI18N buttonCopy.setText(bundle.getString("PlainTextEditor.buttonCopy.text")); // NOI18N buttonCopy.setToolTipText(bundle.getString("PlainTextEditor.buttonCopy.toolTipText")); // NOI18N buttonCopy.setFocusable(false); buttonCopy.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); buttonCopy.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); buttonCopy.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { buttonCopyActionPerformed(evt); } }); mainToolBar.add(buttonCopy); buttonPaste.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/nbmindmap/icons/paste_plain16.png"))); // NOI18N buttonPaste.setText(bundle.getString("PlainTextEditor.buttonPaste.text")); // NOI18N buttonPaste.setToolTipText(bundle.getString("PlainTextEditor.buttonPaste.toolTipText")); // NOI18N buttonPaste.setFocusable(false); buttonPaste.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); buttonPaste.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); buttonPaste.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { buttonPasteActionPerformed(evt); } }); mainToolBar.add(buttonPaste); buttonClearAll.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/nbmindmap/icons/cross16.png"))); // NOI18N buttonClearAll.setText(bundle.getString("PlainTextEditor.buttonClearAll.text")); // NOI18N buttonClearAll.setToolTipText(bundle.getString("PlainTextEditor.buttonClearAll.toolTipText")); // NOI18N buttonClearAll.setFocusable(false); buttonClearAll.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); buttonClearAll.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); buttonClearAll.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { buttonClearAllActionPerformed(evt); } }); mainToolBar.add(buttonClearAll); add(mainToolBar, java.awt.BorderLayout.PAGE_START); jPanel1.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT)); labelCursorPos.setText("...:..."); // NOI18N jPanel1.add(labelCursorPos); jSeparator2.setOrientation(javax.swing.SwingConstants.VERTICAL); jSeparator2.setPreferredSize(new java.awt.Dimension(8, 16)); jPanel1.add(jSeparator2); labelWrapMode.setText("..."); // NOI18N labelWrapMode.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); labelWrapMode.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { labelWrapModeMouseClicked(evt); } }); jPanel1.add(labelWrapMode); jPanel1.add(filler1); add(jPanel1, java.awt.BorderLayout.PAGE_END); }// </editor-fold>//GEN-END:initComponents private void buttonLoadActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonLoadActionPerformed final File home = new File(System.getProperty("user.home")); //NOI18N final File toOpen = new FileChooserBuilder("user-home-dir"). //NOI18N setTitle(java.util.ResourceBundle.getBundle("com/igormaznitsa/nbmindmap/i18n/Bundle").getString("PlainTextEditor.buttonLoadActionPerformed.title")). addFileFilter(TEXT_FILE_FILTER).setFileFilter(TEXT_FILE_FILTER). setFilesOnly(true). setDefaultWorkingDirectory(home). showOpenDialog(); if (toOpen != null) { try { final String text = FileUtils.readFileToString(toOpen, "UTF-8"); //NOI18N setText(text); } catch (Exception ex) { LOGGER.error("Error during text file loading", ex); //NOI18N NbUtils.msgError(java.util.ResourceBundle.getBundle("com/igormaznitsa/nbmindmap/i18n/Bundle").getString("PlainTextEditor.buttonLoadActionPerformed.msgError")); } } }//GEN-LAST:event_buttonLoadActionPerformed private void buttonSaveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonSaveActionPerformed final File home = new File(System.getProperty("user.home")); //NOI18N final File toSave = new FileChooserBuilder("user-home-dir"). setTitle(java.util.ResourceBundle.getBundle("com/igormaznitsa/nbmindmap/i18n/Bundle").getString("PlainTextEditor.buttonSaveActionPerformed.saveTitle")). addFileFilter(TEXT_FILE_FILTER).setFileFilter(TEXT_FILE_FILTER). setFilesOnly(true). setDefaultWorkingDirectory(home). showSaveDialog(); if (toSave != null) { try { final String text = getText(); FileUtils.writeStringToFile(toSave, text, "UTF-8"); //NOI18N } catch (Exception ex) { LOGGER.error("Error during text file saving", ex); //NOI18N NbUtils.msgError(java.util.ResourceBundle.getBundle("com/igormaznitsa/nbmindmap/i18n/Bundle").getString("PlainTextEditor.buttonSaveActionPerformed.msgError")); } } }//GEN-LAST:event_buttonSaveActionPerformed private void buttonCopyActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonCopyActionPerformed StringSelection stringSelection = new StringSelection(this.lastEditor.getSelectedText()); final Clipboard clpbrd = Toolkit.getDefaultToolkit().getSystemClipboard(); clpbrd.setContents(stringSelection, null); }//GEN-LAST:event_buttonCopyActionPerformed private void buttonPasteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPasteActionPerformed try { this.lastEditor.replaceSelection((String) Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.stringFlavor)); } catch (UnsupportedFlavorException ex) { // no text data in clipboard } catch (IOException ex) { LOGGER.error("Error during paste from clipboard", ex); //NOI18N } }//GEN-LAST:event_buttonPasteActionPerformed private void buttonClearAllActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonClearAllActionPerformed this.lastEditor.setText(""); //NOI18N }//GEN-LAST:event_buttonClearAllActionPerformed private void labelWrapModeMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_labelWrapModeMouseClicked this.wrapping = this.wrapping.next(); writeWrappingCode(this.wrapping); final Component oldComponent = this.lastComponent; this.lastComponent = makeEditorForText(this.document); this.remove(oldComponent); this.add(this.lastComponent, BorderLayout.CENTER); updateBottomPanel(); }//GEN-LAST:event_labelWrapModeMouseClicked // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton buttonClearAll; private javax.swing.JButton buttonCopy; private javax.swing.JButton buttonLoad; private javax.swing.JButton buttonPaste; private javax.swing.JButton buttonSave; private javax.swing.Box.Filler filler1; private javax.swing.JPanel jPanel1; private javax.swing.JSeparator jSeparator2; private javax.swing.JLabel labelCursorPos; private javax.swing.JLabel labelWrapMode; private javax.swing.JToolBar mainToolBar; // End of variables declaration//GEN-END:variables private void writeWrappingCode (final Wrapping code) { final Preferences docPreferences = CodeStylePreferences.get(this.document).getPreferences(); docPreferences.put(SimpleValueNames.TEXT_LINE_WRAP, code.getValue()); try { docPreferences.flush(); } catch (BackingStoreException ex) { LOGGER.error("Can't write wrapping code", ex); } } public void dispose () { if (this.lastEditor != null) { this.lastEditor.removeCaretListener(this); } writeWrappingCode(this.oldWrapping); // restore old wrapping for mime type LOGGER.info("PlainTextEditor has been disposed"); } private static int getRow (final int pos, final JTextComponent editor) { int rn = (pos == 0) ? 1 : 0; try { int offs = pos; while (offs > 0) { offs = Utilities.getRowStart(editor, offs) - 1; rn++; } } catch (BadLocationException e) { LOGGER.error("Bad location", e); } return rn; } private static int getColumn (final int pos, final JTextComponent editor) { try { return pos - Utilities.getRowStart(editor, pos) + 1; } catch (BadLocationException e) { LOGGER.error("Bad location", e); } return -1; } @Override public void caretUpdate (final CaretEvent e) { final String text; if (this.lastEditor == null) { text = "...:..."; } else { final int pos = this.lastEditor.getCaretPosition(); final int col = getColumn(pos, this.lastEditor); final int row = getRow(pos, this.lastEditor); text = row + ":" + col; } this.labelCursorPos.setText(text); } }