001 /** 002 * ======================================== 003 * JFreeReport : a free Java report library 004 * ======================================== 005 * 006 * Project Info: http://reporting.pentaho.org/ 007 * 008 * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors. 009 * 010 * This library is free software; you can redistribute it and/or modify it under the terms 011 * of the GNU Lesser General Public License as published by the Free Software Foundation; 012 * either version 2.1 of the License, or (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 015 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 016 * See the GNU Lesser General Public License for more details. 017 * 018 * You should have received a copy of the GNU Lesser General Public License along with this 019 * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, 020 * Boston, MA 02111-1307, USA. 021 * 022 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 023 * in the United States and other countries.] 024 * 025 * ------------ 026 * $Id: AbstractExportDialog.java 3525 2007-10-16 11:43:48Z tmorgner $ 027 * ------------ 028 * (C) Copyright 2000-2005, by Object Refinery Limited. 029 * (C) Copyright 2005-2007, by Pentaho Corporation. 030 */ 031 package org.jfree.report.modules.gui.swing.common; 032 033 import java.awt.Dialog; 034 import java.awt.Frame; 035 import java.awt.event.ActionEvent; 036 import java.awt.event.WindowAdapter; 037 import java.awt.event.WindowEvent; 038 import java.io.File; 039 import java.util.Enumeration; 040 import java.util.Locale; 041 import java.util.ResourceBundle; 042 import javax.swing.AbstractAction; 043 import javax.swing.Action; 044 import javax.swing.JDialog; 045 046 import org.jfree.base.config.ModifiableConfiguration; 047 import org.jfree.report.flow.ReportJob; 048 import org.jfree.report.modules.gui.common.GuiContext; 049 import org.jfree.report.modules.preferences.base.ConfigFactory; 050 import org.jfree.report.modules.preferences.base.ConfigStorage; 051 import org.jfree.report.modules.preferences.base.ConfigStoreException; 052 import org.jfree.util.Configuration; 053 import org.jfree.util.Log; 054 055 public abstract class AbstractExportDialog extends JDialog 056 implements ExportDialog 057 { 058 /** 059 * Internal action class to confirm the dialog and to validate the input. 060 */ 061 private class ConfirmAction extends AbstractAction 062 { 063 /** 064 * Default constructor. 065 */ 066 private ConfirmAction(final ResourceBundle resources) 067 { 068 putValue(Action.NAME, resources.getString("OptionPane.okButtonText")); 069 } 070 071 /** 072 * Receives notification that the action has occurred. 073 * 074 * @param e the action event. 075 */ 076 public void actionPerformed(final ActionEvent e) 077 { 078 if (performValidate() && performConfirm()) 079 { 080 setConfirmed(true); 081 setVisible(false); 082 } 083 } 084 } 085 086 /** 087 * Internal action class to cancel the report processing. 088 */ 089 private class CancelAction extends AbstractAction 090 { 091 /** 092 * Default constructor. 093 */ 094 private CancelAction(final ResourceBundle resources) 095 { 096 putValue(Action.NAME, resources.getString("OptionPane.cancelButtonText")); 097 } 098 099 /** 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 }