org.pentaho.reporting.tools.configeditor.ConfigEditor.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.reporting.tools.configeditor.ConfigEditor.java

Source

/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright (c) 2001 - 2013 Object Refinery Ltd, Hitachi Vantara and Contributors..  All rights reserved.
*/

package org.pentaho.reporting.tools.configeditor;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.reporting.libraries.base.boot.AbstractBoot;
import org.pentaho.reporting.libraries.base.config.HierarchicalConfiguration;
import org.pentaho.reporting.libraries.base.util.FilesystemFilter;
import org.pentaho.reporting.libraries.base.util.Messages;
import org.pentaho.reporting.libraries.base.util.ObjectUtilities;
import org.pentaho.reporting.libraries.base.util.ResourceBundleSupport;
import org.pentaho.reporting.libraries.base.util.StringUtils;
import org.pentaho.reporting.tools.configeditor.model.ConfigTreeModelException;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Properties;

/**
 * The ConfigEditor can be used to edit the global jfreereport.properties files. These files provide global settings for
 * all reports and contain the system level configuration of JFreeReport.
 *
 * @author Thomas Morgner
 */
public class ConfigEditor extends JFrame {
    private static final Log logger = LogFactory.getLog(ConfigEditor.class);

    /**
     * An Action to handle close requests.
     */
    private class CloseAction extends AbstractAction {
        /**
         * DefaultConstructor.
         */
        protected CloseAction() {
            putValue(Action.NAME, getResources().getString("action.exit.name")); //$NON-NLS-1$
        }

        /**
         * Invoked when an action occurs. The action invokes System.exit(0).
         *
         * @param e the action event.
         */
        public void actionPerformed(final ActionEvent e) {
            attempClose();
        }
    }

    /**
     * An action to handle save requests.
     */
    private class SaveAction extends AbstractAction {
        /**
         * DefaultConstructor.
         */
        protected SaveAction() {
            putValue(Action.NAME, getResources().getString("action.save.name")); //$NON-NLS-1$
            putValue(Action.SMALL_ICON, getResources().getIcon("action.save.small-icon")); //$NON-NLS-1$
        }

        /**
         * Saves the configuration.
         *
         * @param e the action event.
         */
        public void actionPerformed(final ActionEvent e) {
            save();
        }
    }

    /**
     * An action to handle load requests.
     */
    private class LoadAction extends AbstractAction {
        /**
         * DefaultConstructor.
         */
        protected LoadAction() {
            putValue(Action.NAME, getResources().getString("action.load.name")); //$NON-NLS-1$
            putValue(Action.SMALL_ICON, getResources().getIcon("action.load.small-icon")); //$NON-NLS-1$
        }

        /**
         * Loads the configuration.
         *
         * @param e the action event.
         */
        public void actionPerformed(final ActionEvent e) {
            load();
        }
    }

    /**
     * An action to handle new requests, which reset the report configuration.
     */
    private class NewAction extends AbstractAction {
        /**
         * DefaultConstructor.
         */
        protected NewAction() {
            putValue(Action.NAME, getResources().getString("action.new.name")); //$NON-NLS-1$
            putValue(Action.SMALL_ICON, getResources().getIcon("action.new.small-icon")); //$NON-NLS-1$
        }

        /**
         * Reset the configuration.
         *
         * @param e the action event.
         */
        public void actionPerformed(final ActionEvent e) {
            reset();
        }
    }

    private class CloseHandler extends WindowAdapter {

        private CloseHandler() {
        }

        /**
         * Invoked when a window is in the process of being closed. The close operation can be overridden at this point.
         */
        public void windowClosing(final WindowEvent e) {
            attempClose();
        }
    }

    private static final String PROPERTIES_FILE_EXTENSION = ".properties";
    /**
     * A constant defining that text should be escaped in a way which is suitable for property keys.
     */
    private static final int ESCAPE_KEY = 0;
    /**
     * A constant defining that text should be escaped in a way which is suitable for property values.
     */
    private static final int ESCAPE_VALUE = 1;
    /**
     * A constant defining that text should be escaped in a way which is suitable for property comments.
     */
    private static final int ESCAPE_COMMENT = 2;

    /**
     * A label that serves as status bar.
     */
    private JLabel statusHolder;
    /**
     * The resource bundle instance of this dialog.
     */
    private final ResourceBundleSupport resources;

    /**
     * The file chooser used to load and save the report configuration.
     */
    private JFileChooser fileChooser;

    private HierarchicalConfiguration configuration;
    private ConfigEditorPane editorPane;

    public ConfigEditor() throws ConfigTreeModelException {
        this(new HierarchicalConfiguration(ConfigEditorBoot.getInstance().getGlobalConfig()),
                ConfigEditorBoot.getInstance());
    }

    public ConfigEditor(final HierarchicalConfiguration configuration, final AbstractBoot packageManager)
            throws ConfigTreeModelException {
        this.configuration = configuration;
        resources = new ResourceBundleSupport(getLocale(), ConfigEditorBoot.BUNDLE_NAME,
                ObjectUtilities.getClassLoader(ConfigEditor.class));
        editorPane = new ConfigEditorPane(packageManager, true);
        editorPane.updateConfiguration(configuration);

        setTitle(resources.getString("config-editor.title")); //$NON-NLS-1$

        final JPanel contentPane = new JPanel();
        contentPane.setLayout(new BorderLayout());
        contentPane.add(editorPane, BorderLayout.CENTER);
        contentPane.add(createButtonPane(), BorderLayout.SOUTH);

        final JPanel cPaneStatus = new JPanel();
        cPaneStatus.setLayout(new BorderLayout());
        cPaneStatus.add(contentPane, BorderLayout.CENTER);
        cPaneStatus.add(createStatusBar(), BorderLayout.SOUTH);

        setContentPane(cPaneStatus);

        addWindowListener(new CloseHandler());

    }

    /**
     * Returns the resource bundle of this editor for translating strings.
     *
     * @return the resource bundle.
     */
    protected ResourceBundleSupport getResources() {
        return resources;
    }

    /**
     * Creates the button pane to hold all control buttons.
     *
     * @return the created panel with all control buttons.
     */
    private JPanel createButtonPane() {
        final Action closeAction = new CloseAction();
        final Action saveAction = new SaveAction();
        final Action loadAction = new LoadAction();
        final Action newAction = new NewAction();

        final JPanel buttonHolder = new JPanel();
        buttonHolder.setLayout(new GridLayout(1, 4, 5, 5));
        buttonHolder.add(new JButton(newAction));
        buttonHolder.add(new JButton(loadAction));
        buttonHolder.add(new JButton(saveAction));
        buttonHolder.add(new JButton(closeAction));

        final JPanel panel = new JPanel();
        panel.setLayout(new FlowLayout(FlowLayout.RIGHT));
        panel.setBorder(new EmptyBorder(5, 5, 5, 5));
        panel.add(buttonHolder);
        return panel;
    }

    /**
     * Creates the statusbar for this frame. Use setStatus() to display text on the status bar.
     *
     * @return the status bar.
     */
    protected JPanel createStatusBar() {
        final JPanel statusPane = new JPanel();
        statusPane.setLayout(new BorderLayout());
        statusPane.setBorder(BorderFactory.createLineBorder(UIManager.getDefaults().getColor("controlShadow"))); //$NON-NLS-1$
        statusHolder = new JLabel(" "); //$NON-NLS-1$
        statusPane.setMinimumSize(statusHolder.getPreferredSize());
        statusPane.add(statusHolder, BorderLayout.WEST);

        return statusPane;
    }

    /**
     * Defines the text to be displayed on the status bar. Setting text will replace any other previously defined text.
     *
     * @param text the new statul bar text.
     */
    private void setStatusText(final String text) {
        statusHolder.setText(text);
    }

    //  private String getStatusText ()
    //  {
    //    return statusHolder.getText();
    //  }

    /**
     * Loads the report configuration from a user selectable report properties file.
     */
    protected void load() {
        setStatusText(resources.getString("ConfigEditor.USER_LOADING_FILE")); //$NON-NLS-1$
        if (fileChooser == null) {
            fileChooser = new JFileChooser();
            final FilesystemFilter filter = new FilesystemFilter(ConfigEditor.PROPERTIES_FILE_EXTENSION,
                    resources.getString("config-editor.file-description.properties")); //$NON-NLS-1$
            fileChooser.addChoosableFileFilter(filter);
            fileChooser.setMultiSelectionEnabled(false);
        }

        final int option = fileChooser.showOpenDialog(this);
        if (option == JFileChooser.APPROVE_OPTION) {
            final File selFile = fileChooser.getSelectedFile();
            String selFileName = selFile.getAbsolutePath();

            // Test if ends on .properties
            if (StringUtils.endsWithIgnoreCase(selFileName, ConfigEditor.PROPERTIES_FILE_EXTENSION) == false) {
                selFileName = selFileName + ConfigEditor.PROPERTIES_FILE_EXTENSION;
            }
            final Properties prop = new Properties();
            try {
                final InputStream in = new BufferedInputStream(new FileInputStream(selFileName));
                try {
                    prop.load(in);
                } finally {
                    in.close();
                }
            } catch (IOException ioe) {
                ConfigEditor.logger.debug(
                        resources.getString("ConfigEditor.ERROR_0003_FAILED_TO_LOAD_PROPERTIES", ioe.toString()),
                        ioe); //$NON-NLS-1$
                setStatusText(
                        resources.getString("ConfigEditor.ERROR_0003_FAILED_TO_LOAD_PROPERTIES", ioe.getMessage())); //$NON-NLS-1$
                return;
            }

            reset();

            final Enumeration keys = prop.keys();
            while (keys.hasMoreElements()) {
                final String key = (String) keys.nextElement();
                final String value = prop.getProperty(key);
                configuration.setConfigProperty(key, value);
            }

            editorPane.updateConfiguration(configuration);
            setStatusText(resources.getString("ConfigEditor.USER_LOAD_PROPS_COMPLETE")); //$NON-NLS-1$
        }
    }

    protected void reset() {
        editorPane.reset();
    }

    /**
     * Saves the report configuration to a user selectable report properties file.
     */
    protected void save() {
        setStatusText(resources.getString("ConfigEditor.USER_SAVING")); //$NON-NLS-1$
        editorPane.commit();

        if (fileChooser == null) {
            fileChooser = new JFileChooser();
            final FilesystemFilter filter = new FilesystemFilter(ConfigEditor.PROPERTIES_FILE_EXTENSION,
                    resources.getString("config-editor.file-description.properties")); //$NON-NLS-1$
            fileChooser.addChoosableFileFilter(filter);
            fileChooser.setMultiSelectionEnabled(false);
        }

        final int option = fileChooser.showSaveDialog(this);
        if (option == JFileChooser.APPROVE_OPTION) {
            final File selFile = fileChooser.getSelectedFile();
            String selFileName = selFile.getAbsolutePath();

            // Test if ends on xls
            if (StringUtils.endsWithIgnoreCase(selFileName, ConfigEditor.PROPERTIES_FILE_EXTENSION) == false) {
                selFileName = selFileName + ConfigEditor.PROPERTIES_FILE_EXTENSION;
            }
            write(selFileName);
        }
    }

    /**
     * Writes the configuration into the file specified by the given file name.
     *
     * @param filename the target file name
     */
    private void write(final String filename) {
        final Properties prop = new Properties();
        final ArrayList<String> names = new ArrayList<String>();
        // clear all previously set configuration settings ...
        final Enumeration defaults = configuration.getConfigProperties();
        while (defaults.hasMoreElements()) {
            final String key = (String) defaults.nextElement();
            names.add(key);
            prop.setProperty(key, configuration.getConfigProperty(key));
        }

        Collections.sort(names);

        PrintWriter out = null;
        try {
            out = new PrintWriter(new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(filename))));

            for (int i = 0; i < names.size(); i++) {
                final String key = names.get(i);
                final String value = prop.getProperty(key);

                final String description = editorPane.getDescriptionForKey(key);
                if (description != null) {
                    writeDescription(description, out);
                }
                saveConvert(key, ConfigEditor.ESCAPE_KEY, out);
                out.print("="); //$NON-NLS-1$
                saveConvert(value, ConfigEditor.ESCAPE_VALUE, out);
                out.println();
            }
            out.close();
            setStatusText(resources.getString("ConfigEditor.USER_SAVING_COMPLETE")); //$NON-NLS-1$
        } catch (IOException ioe) {
            ConfigEditor.logger.debug(
                    resources.getString("ConfigEditor.ERROR_0004_FAILED_PROPERTIES_SAVE", ioe.toString()), ioe); //$NON-NLS-1$
            setStatusText(resources.getString("ConfigEditor.ERROR_0004_FAILED_PROPERTIES_SAVE", ioe.getMessage())); //$NON-NLS-1$
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }

    /**
     * Writes a descriptive comment into the given print writer.
     *
     * @param text   the text to be written. If it contains more than one line, every line will be prepended by the
     *               comment character.
     * @param writer the writer that should receive the content.
     * @noinspection NestedAssignment
     */
    private void writeDescription(final String text, final PrintWriter writer) {
        // check if empty content ... this case is easy ...
        if (text.length() == 0) {
            return;
        }

        writer.println("# "); //$NON-NLS-1$

        try {
            final BufferedReader br = new BufferedReader(new StringReader(text));
            String s;
            while ((s = br.readLine()) != null) {
                writer.print("# "); //$NON-NLS-1$
                saveConvert(s, ConfigEditor.ESCAPE_COMMENT, writer);
                writer.println();
            }
            br.close();
        } catch (IOException e) {
            // does not happen, this is a string-reader
        }
    }

    /**
     * Performs the necessary conversion of an java string into a property escaped string.
     *
     * @param text       the text to be escaped
     * @param escapeMode the mode that should be applied.
     * @param writer     the writer that should receive the content.
     */
    private void saveConvert(final String text, final int escapeMode, final PrintWriter writer) {
        final char[] string = text.toCharArray();
        final char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

        for (int x = 0; x < string.length; x++) {
            final char aChar = string[x];
            switch (aChar) {
            case ' ': {
                if ((escapeMode != ConfigEditor.ESCAPE_COMMENT)
                        && (x == 0 || escapeMode == ConfigEditor.ESCAPE_KEY)) {
                    writer.print('\\');
                }
                writer.print(' ');
                break;
            }
            case '\\': {
                writer.print('\\');
                writer.print('\\');
                break;
            }
            case '\t': {
                if (escapeMode == ConfigEditor.ESCAPE_COMMENT) {
                    writer.print(aChar);
                } else {
                    writer.print('\\');
                    writer.print('t');
                }
                break;
            }
            case '\n': {
                writer.print('\\');
                writer.print('n');
                break;
            }
            case '\r': {
                writer.print('\\');
                writer.print('r');
                break;
            }
            case '\f': {
                if (escapeMode == ConfigEditor.ESCAPE_COMMENT) {
                    writer.print(aChar);
                } else {
                    writer.print('\\');
                    writer.print('f');
                }
                break;
            }
            case '#':
            case '"':
            case '!':
            case '=':
            case ':': {
                if (escapeMode == ConfigEditor.ESCAPE_COMMENT) {
                    writer.print(aChar);
                } else {
                    writer.print('\\');
                    writer.print(aChar);
                }
                break;
            }
            default:
                if ((aChar < 0x0020) || (aChar > 0x007e)) {
                    writer.print('\\');
                    writer.print('u');
                    writer.print(hexChars[(aChar >> 12) & 0xF]);
                    writer.print(hexChars[(aChar >> 8) & 0xF]);
                    writer.print(hexChars[(aChar >> 4) & 0xF]);
                    writer.print(hexChars[aChar & 0xF]);
                } else {
                    writer.print(aChar);
                }
            }
        }
    }

    /**
     * Closes this frame and exits the JavaVM.
     */
    protected void attempClose() {
        System.exit(0);
    }

    /**
     * main Method to start the editor.
     *
     * @param args not used.
     */
    public static void main(final String[] args) {
        try {
            ConfigEditorBoot.getInstance().start();
            final ConfigEditor ed = new ConfigEditor();
            ed.pack();
            ed.setVisible(true);
        } catch (Exception e) {
            final Messages messages = new Messages(Locale.getDefault(), ConfigEditorBoot.BUNDLE_NAME,
                    ObjectUtilities.getClassLoader(ConfigEditorBoot.class));
            final String message = messages.getString("ConfigEditor.ERROR_0001_FAILED_TO_INITIALIZE"); //$NON-NLS-1$
            logger.debug(message, e);
            JOptionPane.showMessageDialog(null, message);
        }
    }
}