Source for org.jfree.report.modules.gui.swing.common.AbstractExportDialog

   1: /**
   2:  * ========================================
   3:  * JFreeReport : a free Java report library
   4:  * ========================================
   5:  *
   6:  * Project Info:  http://reporting.pentaho.org/
   7:  *
   8:  * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors.
   9:  *
  10:  * This library is free software; you can redistribute it and/or modify it under the terms
  11:  * of the GNU Lesser General Public License as published by the Free Software Foundation;
  12:  * either version 2.1 of the License, or (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  15:  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  16:  * See the GNU Lesser General Public License for more details.
  17:  *
  18:  * You should have received a copy of the GNU Lesser General Public License along with this
  19:  * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  20:  * Boston, MA 02111-1307, USA.
  21:  *
  22:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
  23:  * in the United States and other countries.]
  24:  *
  25:  * ------------
  26:  * $Id: AbstractExportDialog.java 3525 2007-10-16 11:43:48Z tmorgner $
  27:  * ------------
  28:  * (C) Copyright 2000-2005, by Object Refinery Limited.
  29:  * (C) Copyright 2005-2007, by Pentaho Corporation.
  30:  */
  31: package org.jfree.report.modules.gui.swing.common;
  32: 
  33: import java.awt.Dialog;
  34: import java.awt.Frame;
  35: import java.awt.event.ActionEvent;
  36: import java.awt.event.WindowAdapter;
  37: import java.awt.event.WindowEvent;
  38: import java.io.File;
  39: import java.util.Enumeration;
  40: import java.util.Locale;
  41: import java.util.ResourceBundle;
  42: import javax.swing.AbstractAction;
  43: import javax.swing.Action;
  44: import javax.swing.JDialog;
  45: 
  46: import org.jfree.base.config.ModifiableConfiguration;
  47: import org.jfree.report.flow.ReportJob;
  48: import org.jfree.report.modules.gui.common.GuiContext;
  49: import org.jfree.report.modules.preferences.base.ConfigFactory;
  50: import org.jfree.report.modules.preferences.base.ConfigStorage;
  51: import org.jfree.report.modules.preferences.base.ConfigStoreException;
  52: import org.jfree.util.Configuration;
  53: import org.jfree.util.Log;
  54: 
  55: public abstract class AbstractExportDialog extends JDialog
  56:   implements ExportDialog
  57: {
  58:   /**
  59:    * Internal action class to confirm the dialog and to validate the input.
  60:    */
  61:   private class ConfirmAction extends AbstractAction
  62:   {
  63:     /**
  64:      * Default constructor.
  65:      */
  66:     private ConfirmAction(final ResourceBundle resources)
  67:     {
  68:       putValue(Action.NAME, resources.getString("OptionPane.okButtonText"));
  69:     }
  70: 
  71:     /**
  72:      * Receives notification that the action has occurred.
  73:      *
  74:      * @param e the action event.
  75:      */
  76:     public void actionPerformed(final ActionEvent e)
  77:     {
  78:       if (performValidate() && performConfirm())
  79:       {
  80:         setConfirmed(true);
  81:         setVisible(false);
  82:       }
  83:     }
  84:   }
  85: 
  86:   /**
  87:    * Internal action class to cancel the report processing.
  88:    */
  89:   private class CancelAction extends AbstractAction
  90:   {
  91:     /**
  92:      * Default constructor.
  93:      */
  94:     private CancelAction(final ResourceBundle resources)
  95:     {
  96:       putValue(Action.NAME, resources.getString("OptionPane.cancelButtonText"));
  97:     }
  98: 
  99:     /**
 100:      * Receives notification that the action has occurred.
 101:      *
 102:      * @param e the action event.
 103:      */
 104:     public void actionPerformed(final ActionEvent e)
 105:     {
 106:       setConfirmed(false);
 107:       setVisible(false);
 108:     }
 109:   }
 110: 
 111:   private class ExportDialogValidator extends FormValidator
 112:   {
 113:     private ExportDialogValidator()
 114:     {
 115:       super();
 116:     }
 117: 
 118:     public boolean performValidate()
 119:     {
 120:       return AbstractExportDialog.this.performValidate();
 121:     }
 122: 
 123:     public Action getConfirmAction()
 124:     {
 125:       return AbstractExportDialog.this.getConfirmAction();
 126:     }
 127:   }
 128: 
 129:   private class WindowCloseHandler extends WindowAdapter
 130:   {
 131:     private WindowCloseHandler()
 132:     {
 133:     }
 134: 
 135:     /**
 136:      * Invoked when a window is in the process of being closed. The close
 137:      * operation can be overridden at this point.
 138:      */
 139:     public void windowClosing(final WindowEvent e)
 140:     {
 141:       final Action cancelAction = getCancelAction();
 142:       if (cancelAction != null)
 143:       {
 144:         cancelAction.actionPerformed(null);
 145:       }
 146:       else
 147:       {
 148:         setConfirmed(false);
 149:         setVisible(false);
 150:       }
 151:     }
 152:   }
 153: 
 154:   private Action cancelAction;
 155:   private Action confirmAction;
 156:   private FormValidator formValidator;
 157:   private ResourceBundle resources;
 158:   private boolean confirmed;
 159:   private ReportJob reportJob;
 160:   private GuiContext guiContext;
 161: 
 162:   /**
 163:    * Creates a non-modal dialog without a title and without a specified
 164:    * <code>Frame</code> owner.  A shared, hidden frame will be set as the owner
 165:    * of the dialog.
 166:    */
 167:   public AbstractExportDialog()
 168:   {
 169:     initialize();
 170:   }
 171: 
 172:   /**
 173:    * Creates a non-modal dialog without a title with the specified
 174:    * <code>Frame</code> as its owner.  If <code>owner</code> is
 175:    * <code>null</code>, a shared, hidden frame will be set as the owner of the
 176:    * dialog.
 177:    *
 178:    * @param owner the <code>Frame</code> from which the dialog is displayed
 179:    */
 180:   public AbstractExportDialog(final Frame owner)
 181:   {
 182:     super(owner);
 183:     initialize();
 184:   }
 185: 
 186: 
 187:   /**
 188:    * Creates a non-modal dialog without a title with the specified
 189:    * <code>Dialog</code> as its owner.
 190:    *
 191:    * @param owner the non-null <code>Dialog</code> from which the dialog is
 192:    *              displayed
 193:    */
 194:   public AbstractExportDialog(final Dialog owner)
 195:   {
 196:     super(owner);
 197:     initialize();
 198:   }
 199: 
 200:   private void initialize()
 201:   {
 202:     final ResourceBundle resources = ResourceBundle.getBundle(SwingCommonModule.BUNDLE_NAME);
 203: 
 204:     cancelAction = new CancelAction(resources);
 205:     confirmAction = new ConfirmAction(resources);
 206: 
 207:     formValidator = new ExportDialogValidator();
 208:     setModal(true);
 209:     setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
 210:     addWindowListener(new WindowCloseHandler());
 211:   }
 212: 
 213: 
 214:   public abstract JStatusBar getStatusBar();
 215: 
 216:   protected Action getCancelAction()
 217:   {
 218:     return cancelAction;
 219:   }
 220: 
 221:   protected void setCancelAction(final Action cancelAction)
 222:   {
 223:     this.cancelAction = cancelAction;
 224:   }
 225: 
 226:   protected Action getConfirmAction()
 227:   {
 228:     return confirmAction;
 229:   }
 230: 
 231:   protected void setConfirmAction(final Action confirmAction)
 232:   {
 233:     this.confirmAction = confirmAction;
 234:   }
 235: 
 236:   protected abstract boolean performValidate();
 237: 
 238:   protected FormValidator getFormValidator()
 239:   {
 240:     return formValidator;
 241:   }
 242: 
 243:   protected abstract void initializeFromJob(ReportJob job,
 244:                                             final GuiContext guiContext);
 245: 
 246:   protected ReportJob getReportJob()
 247:   {
 248:     return reportJob;
 249:   }
 250: 
 251:   protected GuiContext getGuiContext()
 252:   {
 253:     return guiContext;
 254:   }
 255: 
 256:   /**
 257:    * Opens the dialog to query all necessary input from the user. This will not
 258:    * start the processing, as this is done elsewhere.
 259:    *
 260:    * @param report the report that should be processed.
 261:    * @return true, if the processing should continue, false otherwise.
 262:    */
 263:   public boolean performQueryForExport(final ReportJob reportJob,
 264:                                        final GuiContext guiContext)
 265:   {
 266:     this.reportJob = reportJob;
 267:     this.guiContext = guiContext;
 268: 
 269:     final Locale locale = reportJob.getReportStructureRoot().getLocale();
 270:     setLocale(locale);
 271:     pack();
 272:     clear();
 273:     initializeFromJob(reportJob, guiContext);
 274: 
 275:     final FormValidator formValidator = getFormValidator();
 276:     formValidator.setEnabled(false);
 277:     final ModifiableConfiguration repConf = reportJob.getConfiguration();
 278:     final boolean inputStorageEnabled = isInputStorageEnabled(repConf);
 279: 
 280:     final Configuration loadedConfiguration;
 281:     if (inputStorageEnabled)
 282:     {
 283:       loadedConfiguration = loadFromConfigStore(reportJob, repConf);
 284:     }
 285:     else
 286:     {
 287:       loadedConfiguration = repConf;
 288:     }
 289: 
 290:     setDialogContents(loadedConfiguration);
 291: 
 292:     formValidator.setEnabled(true);
 293:     formValidator.handleValidate();
 294:     setModal(true);
 295:     setVisible(true);
 296:     if (isConfirmed() == false)
 297:     {
 298:       return false;
 299:     }
 300: 
 301:     formValidator.setEnabled(false);
 302: 
 303:     final Configuration fullDialogContents = grabDialogContents(true);
 304:     final Enumeration configProperties =
 305:         fullDialogContents.getConfigProperties();
 306:     while (configProperties.hasMoreElements())
 307:     {
 308:       final String key = (String) configProperties.nextElement();
 309:       repConf.setConfigProperty(key, fullDialogContents.getConfigProperty(key));
 310:     }
 311: 
 312:     if (inputStorageEnabled)
 313:     {
 314:       saveToConfigStore(reportJob, repConf);
 315:     }
 316: 
 317:     formValidator.setEnabled(true);
 318:     this.reportJob = null;
 319:     return true;
 320:   }
 321: 
 322:   private void saveToConfigStore(final ReportJob reportJob,
 323:                                  final Configuration reportConfiguration)
 324:   {
 325:     final String configPath = ConfigFactory.encodePath(
 326:         reportJob.getName() + getConfigurationSuffix());
 327: 
 328:     try
 329:     {
 330:       final boolean fullStorageEnabled = isFullInputStorageEnabled(reportConfiguration);
 331:       final Configuration dialogContents = grabDialogContents(fullStorageEnabled);
 332:       final ConfigStorage storage = ConfigFactory.getInstance().getUserStorage();
 333:       storage.store(configPath, dialogContents);
 334:     }
 335:     catch (ConfigStoreException cse)
 336:     {
 337:       Log.debug("Unable to store the defaults in Export export dialog. [" + getClass() + "]");
 338:     }
 339:   }
 340: 
 341:   private Configuration loadFromConfigStore(final ReportJob reportJob,
 342:                                             final Configuration defaultConfig)
 343:   {
 344:     final String configPath = ConfigFactory.encodePath(
 345:         reportJob.getName() + getConfigurationSuffix());
 346:     final ConfigStorage storage = ConfigFactory.getInstance().getUserStorage();
 347:     try
 348:     {
 349:       return storage.load(configPath, defaultConfig);
 350:     }
 351:     catch (Exception cse)
 352:     {
 353:       Log.debug("Unable to load the defaults in Export export dialog. [" + getClass() + "]");
 354:     }
 355:     return defaultConfig;
 356:   }
 357: 
 358:   protected abstract String getConfigurationPrefix();
 359: 
 360:   /**
 361:    * Returns a new (and not connected to the default config from the job)
 362:    * configuration containing all properties from the dialog.
 363:    *
 364:    * @param full
 365:    * @return
 366:    */
 367:   protected abstract Configuration grabDialogContents(boolean full);
 368: 
 369:   protected abstract void setDialogContents(Configuration properties);
 370: 
 371:   protected abstract String getConfigurationSuffix();
 372: 
 373:   /**
 374:    * Retrieves the resources for this dialog. If the resources are not
 375:    * initialized, they get loaded on the first call to this method.
 376:    *
 377:    * @return this frames ResourceBundle.
 378:    */
 379:   protected ResourceBundle getResources()
 380:   {
 381:     if (resources == null)
 382:     {
 383:       resources = ResourceBundle.getBundle(getResourceBaseName());
 384:     }
 385:     return resources;
 386:   }
 387: 
 388:   protected boolean isInputStorageEnabled(final Configuration config)
 389:   {
 390:     final String confVal = config.getConfigProperty
 391:         (getConfigurationPrefix() + "StoreDialogContents");
 392:     return "none".equalsIgnoreCase(confVal) == false;
 393:   }
 394: 
 395:   protected boolean isFullInputStorageEnabled(final Configuration config)
 396:   {
 397:     final String confVal = config.getConfigProperty
 398:         (getConfigurationPrefix() + "StoreDialogContents");
 399:     return "all".equalsIgnoreCase(confVal);
 400:   }
 401: 
 402:   /**
 403:    * Returns <code>true</code> if the user confirmed the selection, and
 404:    * <code>false</code> otherwise.  The file should only be saved if the result
 405:    * is <code>true</code>.
 406:    *
 407:    * @return A boolean.
 408:    */
 409:   public boolean isConfirmed()
 410:   {
 411:     return confirmed;
 412:   }
 413: 
 414:   /**
 415:    * Defines whether this dialog has been finished using the 'OK' or the
 416:    * 'Cancel' option.
 417:    *
 418:    * @param confirmed set to <code>true</code>, if OK was pressed,
 419:    *                  <code>false</code> otherwise
 420:    */
 421:   protected void setConfirmed(final boolean confirmed)
 422:   {
 423:     this.confirmed = confirmed;
 424:   }
 425: 
 426:   protected boolean performConfirm()
 427:   {
 428:     return true;
 429:   }
 430: 
 431:   public abstract void clear();
 432: 
 433:   protected abstract String getResourceBaseName();
 434: 
 435: 
 436:   /**
 437:    * Resolves file names for the exports. An occurence of "~/" at the beginning
 438:    * of the name will be replaced with the users home directory.
 439:    *
 440:    * @param baseDirectory the base directory as specified in the configuration.
 441:    * @return the file object pointing to that directory.
 442:    * @throws org.jfree.base.modules.ModuleInitializeException
 443:    *                                  if an error occured or the directory could
 444:    *                                  not be created.
 445:    * @throws IllegalArgumentException if the base directory is null.
 446:    */
 447:   protected File resolvePath(String baseDirectory)
 448:   {
 449:     if (baseDirectory == null)
 450:     {
 451:       throw new IllegalArgumentException("The base directory must not be null");
 452:     }
 453: 
 454:     if (baseDirectory.startsWith("~/") == false)
 455:     {
 456:       return new File(baseDirectory);
 457:     }
 458:     else
 459:     {
 460:       final String homeDirectory = System.getProperty("user.home");
 461:       if ("~/".equals(baseDirectory))
 462:       {
 463:         return new File(homeDirectory);
 464:       }
 465:       else
 466:       {
 467:         baseDirectory = baseDirectory.substring(2);
 468:         return new File(homeDirectory, baseDirectory);
 469:       }
 470:     }
 471:   }
 472: }