/* * 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, Pentaho Corporation and Contributors.. All rights reserved. */ package org.pentaho.reporting.engine.classic.core.modules.gui.base; import java.awt.BorderLayout; import java.awt.Dialog; import java.awt.FlowLayout; import java.awt.Frame; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.util.Enumeration; import java.util.Locale; import java.util.ResourceBundle; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JPanel; import javax.swing.KeyStroke; import javax.swing.WindowConstants; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.pentaho.reporting.engine.classic.core.MasterReport; import org.pentaho.reporting.engine.classic.core.ReportProcessingException; import org.pentaho.reporting.engine.classic.core.modules.gui.common.GuiContext; import org.pentaho.reporting.engine.classic.core.modules.gui.commonswing.DefaultGuiContext; import org.pentaho.reporting.engine.classic.core.modules.gui.commonswing.ExportDialog; import org.pentaho.reporting.engine.classic.core.modules.gui.commonswing.FormValidator; import org.pentaho.reporting.engine.classic.core.modules.gui.commonswing.JStatusBar; import org.pentaho.reporting.engine.classic.core.modules.gui.commonswing.SwingCommonModule; import org.pentaho.reporting.engine.classic.core.modules.gui.commonswing.SwingGuiContext; import org.pentaho.reporting.engine.classic.core.modules.misc.configstore.base.ConfigFactory; import org.pentaho.reporting.engine.classic.core.modules.misc.configstore.base.ConfigStorage; import org.pentaho.reporting.engine.classic.core.modules.misc.configstore.base.ConfigStoreException; import org.pentaho.reporting.engine.classic.core.parameters.ReportParameterDefinition; import org.pentaho.reporting.engine.classic.core.util.ReportParameterValues; import org.pentaho.reporting.libraries.base.config.Configuration; import org.pentaho.reporting.libraries.base.config.ModifiableConfiguration; import org.pentaho.reporting.libraries.base.util.Messages; import org.pentaho.reporting.libraries.base.util.ObjectUtilities; import org.pentaho.reporting.libraries.designtime.swing.LibSwingUtil; public abstract class AbstractExportDialog extends JDialog implements ExportDialog { private static final Log logger = LogFactory.getLog( AbstractExportDialog.class ); /** * Internal action class to confirm the dialog and to validate the input. */ private class ConfirmAction extends AbstractAction { /** * Default constructor. */ protected ConfirmAction( final ResourceBundle resources ) { putValue( Action.NAME, resources.getString( "OptionPane.okButtonText" ) ); //$NON-NLS-1$ } /** * Receives notification that the action has occurred. * * @param e * the action event. */ public void actionPerformed( final ActionEvent e ) { if ( performValidate() && performConfirm() ) { applyReportParameters(); setConfirmed( true ); setVisible( false ); } } private void applyReportParameters() { final ReportParameterDefinition theParamterDefinition = reportJob.getParameterDefinition(); if ( theParamterDefinition.getParameterCount() > 0 ) { final ReportParameterValues properties = parametersPanel.getReportParameterValues(); final ReportParameterValues reportParameters = reportJob.getParameterValues(); final String[] strings = properties.getColumnNames(); for ( int i = 0; i < strings.length; i++ ) { final String propertyName = strings[i]; reportParameters.put( propertyName, properties.get( propertyName ) ); } } } } /** * Internal action class to cancel the report processing. */ private class CancelAction extends AbstractAction { /** * Default constructor. */ protected CancelAction( final ResourceBundle resources ) { putValue( Action.NAME, resources.getString( "OptionPane.cancelButtonText" ) ); //$NON-NLS-1$ putValue( Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke( KeyEvent.VK_ESCAPE, 0 ) ); } /** * Receives notification that the action has occurred. * * @param e * the action event. */ public void actionPerformed( final ActionEvent e ) { setConfirmed( false ); setVisible( false ); } } private class ExportDialogValidator extends FormValidator { protected ExportDialogValidator() { super(); } public boolean performValidate() { return AbstractExportDialog.this.performValidate(); } public Action getConfirmAction() { return AbstractExportDialog.this.getConfirmAction(); } } private class WindowCloseHandler extends WindowAdapter { protected WindowCloseHandler() { } /** * 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 ) { final Action cancelAction = getCancelAction(); if ( cancelAction != null ) { cancelAction.actionPerformed( null ); } else { setConfirmed( false ); setVisible( false ); } } } private Action cancelAction; private Action confirmAction; private FormValidator formValidator; private ResourceBundle resources; private boolean confirmed; private MasterReport reportJob; private GuiContext guiContext; private GuiContext defaultContext; private Messages messages; private JPanel parametersLayoutPanel; private ParameterReportControllerPane parametersPanel; /** * Creates a non-modal dialog without a title and without a specified <code>Frame</code> owner. A shared, hidden frame * will be set as the owner of the dialog. */ protected AbstractExportDialog() { initialize(); } /** * Creates a non-modal dialog without a title with the specified <code>Frame</code> as its owner. If * <code>owner</code> is <code>null</code>, a shared, hidden frame will be set as the owner of the dialog. * * @param owner * the <code>Frame</code> from which the dialog is displayed */ protected AbstractExportDialog( final Frame owner ) { super( owner ); initialize(); } /** * Creates a non-modal dialog without a title with the specified <code>Dialog</code> as its owner. * * @param owner * the non-null <code>Dialog</code> from which the dialog is displayed */ protected AbstractExportDialog( final Dialog owner ) { super( owner ); initialize(); } private void initialize() { defaultContext = new DefaultGuiContext( this, null ); guiContext = defaultContext; final ResourceBundle resources = ResourceBundle.getBundle( SwingCommonModule.BUNDLE_NAME ); cancelAction = new CancelAction( resources ); confirmAction = new ConfirmAction( resources ); formValidator = new ExportDialogValidator(); setModal( true ); setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE ); addWindowListener( new WindowCloseHandler() ); messages = new Messages( defaultContext.getLocale(), SwingCommonModule.BUNDLE_NAME, ObjectUtilities .getClassLoader( SwingCommonModule.class ) ); parametersPanel = new ParameterReportControllerPane(); parametersLayoutPanel = new JPanel( new BorderLayout() ); parametersLayoutPanel.setBorder( BorderFactory.createEmptyBorder( 10, 10, 10, 10 ) ); parametersLayoutPanel.add( parametersPanel, BorderLayout.NORTH ); } protected JPanel createContentPane( final JComponent realContent ) { final JPanel contentPane = new JPanel(); contentPane.setLayout( new BorderLayout() ); contentPane.add( createButtonPanel(), BorderLayout.SOUTH ); contentPane.add( realContent, BorderLayout.CENTER ); final JPanel contentWithStatus = new JPanel(); contentWithStatus.setLayout( new BorderLayout() ); contentWithStatus.add( contentPane, BorderLayout.CENTER ); contentWithStatus.add( getStatusBar(), BorderLayout.SOUTH ); return contentWithStatus; } protected JPanel createButtonPanel() { final JButton btnCancel = new JButton( getCancelAction() ); final JButton btnConfirm = new JButton( getConfirmAction() ); final JPanel buttonPanel = new JPanel(); buttonPanel.setLayout( new GridLayout( 1, 2, 5, 5 ) ); buttonPanel.add( btnConfirm ); buttonPanel.add( btnCancel ); btnConfirm.setDefaultCapable( true ); getRootPane().setDefaultButton( btnConfirm ); buttonPanel.registerKeyboardAction( getConfirmAction(), KeyStroke.getKeyStroke( KeyEvent.VK_ENTER, 0 ), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ); final JPanel buttonCarrier = new JPanel(); buttonCarrier.setLayout( new FlowLayout( FlowLayout.RIGHT ) ); buttonCarrier.add( buttonPanel ); return buttonCarrier; } public abstract JStatusBar getStatusBar(); protected Action getCancelAction() { return cancelAction; } protected void setCancelAction( final Action cancelAction ) { this.cancelAction = cancelAction; } protected Action getConfirmAction() { return confirmAction; } protected void setConfirmAction( final Action confirmAction ) { this.confirmAction = confirmAction; } protected abstract boolean performValidate(); protected FormValidator getFormValidator() { return formValidator; } protected void initializeFromJob( final MasterReport job, final GuiContext guiContext ) { final JStatusBar statusBar = getStatusBar(); if ( statusBar != null ) { statusBar.setIconTheme( guiContext.getIconTheme() ); } } protected MasterReport getReportJob() { return reportJob; } protected GuiContext getGuiContext() { return guiContext; } /** * Opens the dialog to query all necessary input from the user. This will not start the processing, as this is done * elsewhere. * * @param reportJob * the report that should be processed. * @return true, if the processing should continue, false otherwise. */ public boolean performQueryForExport( final MasterReport reportJob, final SwingGuiContext guiContext ) { if ( reportJob == null ) { throw new NullPointerException(); } if ( guiContext == null ) { throw new NullPointerException(); } this.reportJob = reportJob; this.guiContext = guiContext; final Locale locale = guiContext.getLocale(); setLocale( locale ); pack(); clear(); initializeFromJob( reportJob, guiContext ); createParametersPanelContent(); final FormValidator formValidator = getFormValidator(); formValidator.setEnabled( false ); final ModifiableConfiguration repConf = reportJob.getReportConfiguration(); final boolean inputStorageEnabled = isInputStorageEnabled( repConf ); final Configuration loadedConfiguration; if ( inputStorageEnabled ) { loadedConfiguration = loadFromConfigStore( reportJob, repConf ); } else { loadedConfiguration = repConf; } setDialogContents( loadedConfiguration ); formValidator.setEnabled( true ); formValidator.handleValidate(); setModal( true ); LibSwingUtil.centerDialogInParent( this ); setVisible( true ); if ( isConfirmed() == false ) { this.guiContext = defaultContext; return false; } formValidator.setEnabled( false ); final Configuration fullDialogContents = grabDialogContents( true ); final Enumeration configProperties = fullDialogContents.getConfigProperties(); while ( configProperties.hasMoreElements() ) { final String key = (String) configProperties.nextElement(); repConf.setConfigProperty( key, fullDialogContents.getConfigProperty( key ) ); } if ( inputStorageEnabled ) { saveToConfigStore( reportJob, repConf ); } formValidator.setEnabled( true ); this.reportJob = null; this.guiContext = defaultContext; return true; } private void createParametersPanelContent() { final ReportParameterDefinition theParamterDefinition = reportJob.getParameterDefinition(); if ( theParamterDefinition.getParameterCount() > 0 ) { try { parametersPanel.hideControls(); parametersPanel.setReport( reportJob ); } catch ( ReportProcessingException e ) { parametersPanel.setErrorMessage( messages.getString( "AbstractExportDialog.ERROR_PARAMETERS" ) ); } } else { parametersPanel.setErrorMessage( messages.getString( "AbstractExportDialog.NO_PARAMETERS" ) ); } } private void saveToConfigStore( final MasterReport reportJob, final Configuration reportConfiguration ) { final String configPath = ConfigFactory.encodePath( reportJob.getTitle() + getConfigurationSuffix() ); try { final boolean fullStorageEnabled = isFullInputStorageEnabled( reportConfiguration ); final Configuration dialogContents = grabDialogContents( fullStorageEnabled ); final ConfigStorage storage = ConfigFactory.getInstance().getUserStorage(); storage.store( configPath, dialogContents ); } catch ( ConfigStoreException cse ) { AbstractExportDialog.logger.debug( messages.getString( "AbstractExportDialog.DEBUG_CANT_STORE_DEFAULTS", String .valueOf( getClass() ) ) ); //$NON-NLS-1$//$NON-NLS-2$ } } private Configuration loadFromConfigStore( final MasterReport reportJob, final Configuration defaultConfig ) { final String configPath = ConfigFactory.encodePath( reportJob.getTitle() + getConfigurationSuffix() ); final ConfigStorage storage = ConfigFactory.getInstance().getUserStorage(); try { return storage.load( configPath, defaultConfig ); } catch ( Exception cse ) { AbstractExportDialog.logger.debug( messages.getString( "AbstractExportDialog.DEBUG_CANT_LOAD_DEFAULTS", String .valueOf( getClass() ) ) ); //$NON-NLS-1$ //$NON-NLS-2$ } return defaultConfig; } protected abstract String getConfigurationPrefix(); /** * Returns a new (and not connected to the default config from the job) configuration containing all properties from * the dialog. * * @param full * @return */ protected abstract Configuration grabDialogContents( boolean full ); protected abstract void setDialogContents( Configuration properties ); protected abstract String getConfigurationSuffix(); /** * Retrieves the resources for this dialog. If the resources are not initialized, they get loaded on the first call to * this method. * * @return this frames ResourceBundle. */ protected ResourceBundle getResources() { if ( resources == null ) { resources = ResourceBundle.getBundle( getResourceBaseName() ); } return resources; } protected boolean isInputStorageEnabled( final Configuration config ) { if ( "true".equals( config .getConfigProperty( "org.pentaho.reporting.engine.classic.core.modules.gui.base.StoreExportDialogInputs" ) ) == false ) { return false; } final String confVal = config.getConfigProperty( getConfigurationPrefix() + "StoreDialogContents" ); //$NON-NLS-1$ return "none".equalsIgnoreCase( confVal ) == false; //$NON-NLS-1$ } protected boolean isFullInputStorageEnabled( final Configuration config ) { if ( "true".equals( config .getConfigProperty( "org.pentaho.reporting.engine.classic.core.modules.gui.base.StoreExportDialogInputs" ) ) == false ) { return false; } final String confVal = config.getConfigProperty( getConfigurationPrefix() + "StoreDialogContents" ); //$NON-NLS-1$ return "all".equalsIgnoreCase( confVal ); //$NON-NLS-1$ } /** * Returns <code>true</code> if the user confirmed the selection, and <code>false</code> otherwise. The file should * only be saved if the result is <code>true</code>. * * @return A boolean. */ public boolean isConfirmed() { return confirmed; } /** * Defines whether this dialog has been finished using the 'OK' or the 'Cancel' option. * * @param confirmed * set to <code>true</code>, if OK was pressed, <code>false</code> otherwise */ protected void setConfirmed( final boolean confirmed ) { this.confirmed = confirmed; } protected boolean performConfirm() { return true; } public abstract void clear(); protected abstract String getResourceBaseName(); /** * Resolves file names for the exports. An occurrence of "~/" at the beginning of the name will be replaced with the * users home directory. * * @param baseDirectory * the base directory as specified in the configuration. * @return the file object pointing to that directory. * @throws IllegalArgumentException * if the base directory is null. */ protected File resolvePath( String baseDirectory ) { if ( baseDirectory == null ) { throw new IllegalArgumentException( messages.getString( "AbstractExportDialog.ERROR_0001_INVALID_BASE_DIR" ) ); //$NON-NLS-1$ } if ( baseDirectory.startsWith( "~/" ) == false ) { //$NON-NLS-1$ return new File( baseDirectory ); } else { final String homeDirectory = System.getProperty( "user.home" ); //$NON-NLS-1$ if ( "~/".equals( baseDirectory ) ) { //$NON-NLS-1$ return new File( homeDirectory ); } else { baseDirectory = baseDirectory.substring( 2 ); return new File( homeDirectory, baseDirectory ); } } } protected JPanel getParametersPanel() { return parametersLayoutPanel; } }