From: <pat...@us...> - 2011-03-01 20:10:37
|
Revision: 1231 http://cishell.svn.sourceforge.net/cishell/?rev=1231&view=rev Author: pataphil Date: 2011-03-01 20:10:28 +0000 (Tue, 01 Mar 2011) Log Message: ----------- * Implemented the FileLoaderService and the FileSaverService. * Reviewed by Joseph. Modified Paths: -------------- trunk/core/org.cishell.framework/META-INF/MANIFEST.MF trunk/core/org.cishell.framework/src/org/cishell/app/service/fileloader/FileLoadException.java trunk/core/org.cishell.framework/src/org/cishell/app/service/fileloader/FileLoaderService.java trunk/core/org.cishell.reference/META-INF/MANIFEST.MF trunk/core/org.cishell.reference/OSGI-INF/fileloader.properties trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/fileloader/FileFormatSelector.java trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/fileloader/FileLoaderServiceImpl.java trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/fileloader/FileSelectorRunnable.java Added Paths: ----------- trunk/core/org.cishell.framework/src/org/cishell/app/service/filesaver/ trunk/core/org.cishell.framework/src/org/cishell/app/service/filesaver/AbstractFileSaverService.java trunk/core/org.cishell.framework/src/org/cishell/app/service/filesaver/FileSaveException.java trunk/core/org.cishell.framework/src/org/cishell/app/service/filesaver/FileSaveListener.java trunk/core/org.cishell.framework/src/org/cishell/app/service/filesaver/FileSaverService.java trunk/core/org.cishell.reference/OSGI-INF/filesaver.properties trunk/core/org.cishell.reference/OSGI-INF/filesaver.xml trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/filesaver/ trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/filesaver/DataFormatChooser.java trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/filesaver/FileSaverServiceImpl.java trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/filesaver/SaveAsController.java trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/persistence/ trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/persistence/AbstractDialog.java Removed Paths: ------------- trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/fileloader/AbstractDialog.java Modified: trunk/core/org.cishell.framework/META-INF/MANIFEST.MF =================================================================== --- trunk/core/org.cishell.framework/META-INF/MANIFEST.MF 2011-03-01 20:09:46 UTC (rev 1230) +++ trunk/core/org.cishell.framework/META-INF/MANIFEST.MF 2011-03-01 20:10:28 UTC (rev 1231) @@ -11,6 +11,7 @@ org.osgi.service.prefs Export-Package: org.cishell.app.service.datamanager;version="1.0.0", org.cishell.app.service.fileloader, + org.cishell.app.service.filesaver, org.cishell.app.service.scheduler;version="1.0.0", org.cishell.framework;version="1.0.0", org.cishell.framework.algorithm;version="1.0.0", Modified: trunk/core/org.cishell.framework/src/org/cishell/app/service/fileloader/FileLoadException.java =================================================================== --- trunk/core/org.cishell.framework/src/org/cishell/app/service/fileloader/FileLoadException.java 2011-03-01 20:09:46 UTC (rev 1230) +++ trunk/core/org.cishell.framework/src/org/cishell/app/service/fileloader/FileLoadException.java 2011-03-01 20:10:28 UTC (rev 1231) @@ -14,8 +14,4 @@ public FileLoadException(String message) { super(message); } - - public FileLoadException() { - this("Algorithm canceled by user."); - } } Modified: trunk/core/org.cishell.framework/src/org/cishell/app/service/fileloader/FileLoaderService.java =================================================================== --- trunk/core/org.cishell.framework/src/org/cishell/app/service/fileloader/FileLoaderService.java 2011-03-01 20:09:46 UTC (rev 1230) +++ trunk/core/org.cishell.framework/src/org/cishell/app/service/fileloader/FileLoaderService.java 2011-03-01 20:10:28 UTC (rev 1231) @@ -13,11 +13,15 @@ public void registerListener(FileLoadListener listener); public void unregisterListener(FileLoadListener listener); + /* TODO make abstract default class, template method pattern, blah blah */ + public File[] getFilesToLoadFromUser( + boolean selectSingleFile, String[] filterExtensions) throws FileLoadException; public Data[] loadFilesFromUserSelection( BundleContext bundleContext, CIShellContext ciShellContext, LogService logger, - ProgressMonitor progressMonitor) throws FileLoadException; + ProgressMonitor progressMonitor, + boolean selectSingleFile) throws FileLoadException; public Data[] loadFiles( BundleContext bundleContext, CIShellContext ciShellContext, Added: trunk/core/org.cishell.framework/src/org/cishell/app/service/filesaver/AbstractFileSaverService.java =================================================================== --- trunk/core/org.cishell.framework/src/org/cishell/app/service/filesaver/AbstractFileSaverService.java (rev 0) +++ trunk/core/org.cishell.framework/src/org/cishell/app/service/filesaver/AbstractFileSaverService.java 2011-03-01 20:10:28 UTC (rev 1231) @@ -0,0 +1,80 @@ +package org.cishell.app.service.filesaver; + +import java.io.File; +import java.util.Collection; + +import org.cishell.framework.data.Data; +import org.cishell.service.conversion.ConversionException; +import org.cishell.service.conversion.Converter; + +public abstract class AbstractFileSaverService implements FileSaverService { + private Collection<FileSaveListener> listeners; + + public void registerListener(FileSaveListener listener) { + this.listeners.add(listener); + } + + public void unregisterListener(FileSaveListener listener) { + this.listeners.remove(listener); + } + + public File promptForTargetFile() throws FileSaveException { + return promptForTargetFile(""); + } + + public File promptForTargetFile(Data datum) throws FileSaveException { + return promptForTargetFile((File) datum.getData()); + } + + public File promptForTargetFile(File outputFile) throws FileSaveException { + return promptForTargetFile(outputFile.getAbsolutePath()); // TODO getName? + } + + public File save(Data sourceDatum) throws FileSaveException { + return save((File) sourceDatum.getData()); + } + + public File save(File sourceFile) throws FileSaveException { + File targetFile = promptForTargetFile(sourceFile); + saveTo(sourceFile, targetFile); + + return targetFile; + } + + public Data save(Data sourceDatum, String targetMimeType) + throws FileSaveException { + Converter converter = promptForConverter(sourceDatum, targetMimeType); + + if (converter != null) { + return save(converter, sourceDatum); + } else { + // TODO: CanceledException? + return null; + } + } + + // TODO: What to actually return here? Maybe Pair<Data, File> (LOL)? + public Data save(Converter converter, Data sourceDatum) + throws FileSaveException { + File targetFile = promptForTargetFile(sourceDatum); + + if (targetFile != null) { + return save(converter, sourceDatum, targetFile); + } else { + // TODO: CanceledException? + return null; + } + } + + public Data save( + Converter converter, Data sourceDatum, File targetFile) throws FileSaveException { + try { + Data convertedDatum = converter.convert(sourceDatum); + saveTo((File) convertedDatum.getData(), targetFile); + + return convertedDatum; + } catch (ConversionException e) { + throw new FileSaveException(e.getMessage(), e); + } + } +} \ No newline at end of file Added: trunk/core/org.cishell.framework/src/org/cishell/app/service/filesaver/FileSaveException.java =================================================================== --- trunk/core/org.cishell.framework/src/org/cishell/app/service/filesaver/FileSaveException.java (rev 0) +++ trunk/core/org.cishell.framework/src/org/cishell/app/service/filesaver/FileSaveException.java 2011-03-01 20:10:28 UTC (rev 1231) @@ -0,0 +1,17 @@ +package org.cishell.app.service.filesaver; + +public class FileSaveException extends Exception { + private static final long serialVersionUID = 1L; + + public FileSaveException(String message, Throwable exception) { + super(message, exception); + } + + public FileSaveException(Throwable exception) { + super(exception); + } + + public FileSaveException(String message) { + super(message); + } +} Added: trunk/core/org.cishell.framework/src/org/cishell/app/service/filesaver/FileSaveListener.java =================================================================== --- trunk/core/org.cishell.framework/src/org/cishell/app/service/filesaver/FileSaveListener.java (rev 0) +++ trunk/core/org.cishell.framework/src/org/cishell/app/service/filesaver/FileSaveListener.java 2011-03-01 20:10:28 UTC (rev 1231) @@ -0,0 +1,7 @@ +package org.cishell.app.service.filesaver; + +import java.io.File; + +public interface FileSaveListener { + void fileSaved(File file); +} \ No newline at end of file Added: trunk/core/org.cishell.framework/src/org/cishell/app/service/filesaver/FileSaverService.java =================================================================== --- trunk/core/org.cishell.framework/src/org/cishell/app/service/filesaver/FileSaverService.java (rev 0) +++ trunk/core/org.cishell.framework/src/org/cishell/app/service/filesaver/FileSaverService.java 2011-03-01 20:10:28 UTC (rev 1231) @@ -0,0 +1,40 @@ +package org.cishell.app.service.filesaver; + +import java.io.File; + +import org.cishell.framework.data.Data; +import org.cishell.service.conversion.Converter; + +/* TODO Push down methods with an obvious implementation in terms of the "atomic" methods + * (choose converter, choose file, perform save) into an abstract class that implements this. + * Then FileSaverServiceImpl extends the abstract class. + */ +public interface FileSaverService { + public void registerListener(FileSaveListener listener); + public void unregisterListener(FileSaveListener listener); + + public Converter promptForConverter(final Data outDatum, String targetMimeType) + throws FileSaveException; + + public File promptForTargetFile() throws FileSaveException; + public File promptForTargetFile(Data datum) throws FileSaveException; + public File promptForTargetFile(File outputFile) throws FileSaveException; + public File promptForTargetFile(String fileName) throws FileSaveException; + + /* TODO I'm seriously tempted to recommend that all methods beyond this point be called + * "save" or "saveToFile" or something, and just have a bit of very concise Javadoc that + * explains what may be prompted for? Alternatively, ask another dev about doing the null + * arguments idea. + */ + // TODO (NEW): Just Javadoc these really well? + public File save(Data sourceDatum) throws FileSaveException; + public File save(File sourceFile) throws FileSaveException; + public void saveTo(File sourceFile, File targetFile) throws FileSaveException; + + // TODO: What to actually return here? the File object for the one on disk + /* TODO sourceDatum always first, targetType/File last */ + public Data save(Data sourceDatum, String targetMimeType) throws FileSaveException; + public Data save(Converter converter, Data sourceDatum) throws FileSaveException; + public Data save( + Converter converter, Data sourceDatum, File targetFile) throws FileSaveException; +} \ No newline at end of file Modified: trunk/core/org.cishell.reference/META-INF/MANIFEST.MF =================================================================== --- trunk/core/org.cishell.reference/META-INF/MANIFEST.MF 2011-03-01 20:09:46 UTC (rev 1230) +++ trunk/core/org.cishell.reference/META-INF/MANIFEST.MF 2011-03-01 20:10:28 UTC (rev 1231) @@ -2,8 +2,11 @@ Bundle-Name: CIShell Reference Service Implementations Bundle-SymbolicName: org.cishell.reference Bundle-Version: 1.0.0 -Import-Package: org.cishell.app.service.datamanager, +Import-Package: com.google.common.base, + com.google.common.collect, + org.cishell.app.service.datamanager, org.cishell.app.service.fileloader, + org.cishell.app.service.filesaver, org.cishell.app.service.scheduler;version="1.0.0", org.cishell.framework;version="1.0.0", org.cishell.framework.algorithm;version="1.0.0", @@ -13,12 +16,15 @@ org.cishell.service.guibuilder;version="1.0.0", org.osgi.framework, org.osgi.service.cm;version="1.2.0", + org.osgi.service.component;version="1.0.0", org.osgi.service.log, org.osgi.service.metatype;version="1.1.0", org.osgi.service.prefs Export-Package: org.cishell.reference.app.service.algorithminvocation, org.cishell.reference.app.service.datamanager, org.cishell.reference.app.service.fileloader, + org.cishell.reference.app.service.filesaver, + org.cishell.reference.app.service.persistence, org.cishell.reference.app.service.scheduler, org.cishell.reference.service.conversion, org.cishell.reference.service.metatype @@ -27,6 +33,6 @@ org.eclipse.ui, org.eclipse.core.runtime, org.eclipse.update.ui -Service-Component: OSGI-INF/fileloader.xml +Service-Component: OSGI-INF/fileloader.xml, OSGI-INF/filesaver.xml Bundle-RequiredExecutionEnvironment: J2SE-1.5 X-AutoStart: true Modified: trunk/core/org.cishell.reference/OSGI-INF/fileloader.properties =================================================================== --- trunk/core/org.cishell.reference/OSGI-INF/fileloader.properties 2011-03-01 20:09:46 UTC (rev 1230) +++ trunk/core/org.cishell.reference/OSGI-INF/fileloader.properties 2011-03-01 20:10:28 UTC (rev 1231) @@ -4,7 +4,7 @@ #description=This allows users to select files from the file system and load them to Data Model window. #in_data=null #out_data=java.lang.Object -service.pid=org.cishell.reference.app.service.fileloader.FileLoadServiceImpl +service.pid=org.cishell.reference.app.service.fileloader.FileLoaderServiceImpl remoteable=true prefs_published=local receive_prefs=true Added: trunk/core/org.cishell.reference/OSGI-INF/filesaver.properties =================================================================== --- trunk/core/org.cishell.reference/OSGI-INF/filesaver.properties (rev 0) +++ trunk/core/org.cishell.reference/OSGI-INF/filesaver.properties 2011-03-01 20:10:28 UTC (rev 1231) @@ -0,0 +1,11 @@ +#menu_path=File/start +#label=Load... +#shortcut=ctrl+alt+o +#description=This allows users to select files from the file system and load them to Data Model window. +#in_data=null +#out_data=java.lang.Object +service.pid=org.cishell.reference.app.service.filesaver.FileSaverServiceImpl +remoteable=true +prefs_published=local +receive_prefs=true +#documentation_url=http://wiki.slis.indiana.edu:8080/display/ALGDOC/Data+Formats \ No newline at end of file Added: trunk/core/org.cishell.reference/OSGI-INF/filesaver.xml =================================================================== --- trunk/core/org.cishell.reference/OSGI-INF/filesaver.xml (rev 0) +++ trunk/core/org.cishell.reference/OSGI-INF/filesaver.xml 2011-03-01 20:10:28 UTC (rev 1231) @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<component name="org.cishell.reference.app.service.filesaver.FileSaverServiceImpl.component" immediate="true"> + <implementation class="org.cishell.reference.app.service.filesaver.FileSaverServiceImpl"/> + <reference name="DCS" interface="org.cishell.service.conversion.DataConversionService"/> + <reference name="GBS" interface="org.cishell.service.guibuilder.GUIBuilderService"/> + <reference name="LOG" interface="org.osgi.service.log.LogService"/> + + <service> + <provide interface="org.cishell.app.service.filesaver.FileSaverService"/> + </service> +</component> \ No newline at end of file Deleted: trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/fileloader/AbstractDialog.java =================================================================== --- trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/fileloader/AbstractDialog.java 2011-03-01 20:09:46 UTC (rev 1230) +++ trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/fileloader/AbstractDialog.java 2011-03-01 20:10:28 UTC (rev 1231) @@ -1,490 +0,0 @@ -/* - * InfoVis CyberInfrastructure: A Data-Code-Compute Resource for Research - * and Education in Information Visualization (http://iv.slis.indiana.edu/). - * - * Created on Feb 22, 2005 at Indiana University. - */ -package org.cishell.reference.app.service.fileloader; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.ShellAdapter; -import org.eclipse.swt.events.ShellEvent; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Dialog; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; - - -/** - * This class provides a DialogBox structure that can be extended to create Dialogs for CIShell. - * This framework will enforce consistency in the look and feel of Dialogs in CIShell by providing a - * standard layout of description, content, and buttons[, along with a choice of icon images - * defined as constants in this class]. An optional details section allows the Dialog designer - * to provide additional information when the details button is pressed. - * - * @author Team IVC - */ -public abstract class AbstractDialog extends Dialog { - private static final int DETAILS_HEIGHT = 75; - - public static Image INFORMATION; - public static Image WARNING; - public static Image ERROR; - public static Image QUESTION; - public static Image WORKING; - - static { - Runnable runner = new Runnable() { - public void run() { - INFORMATION = Display.getDefault().getSystemImage(SWT.ICON_INFORMATION); - WARNING = Display.getDefault().getSystemImage(SWT.ICON_WARNING); - ERROR = Display.getDefault().getSystemImage(SWT.ICON_ERROR); - QUESTION = Display.getDefault().getSystemImage(SWT.ICON_QUESTION); - WORKING = Display.getDefault().getSystemImage(SWT.ICON_WORKING); - }}; - - if (Display.getDefault().getThread() == Thread.currentThread()) { - runner.run(); - } else { - Display.getDefault().asyncExec(runner); - } - } - - - private String description = ""; - private String detailsString = ""; - private Text detailsText; - private Shell shell; - private Image image; - private boolean success; - private Composite header; - private Composite content; - private Composite buttons; - private Shell parent; - - /** - * Creates a new AbstractDialog object. - * - * @param parent the parent Shell of this AbstractDialog - * @param title the title to put in the title bar of this AbstractDialog - * @param image the Image to display to the left of the description specified - * for this AbstractDialog. This will usually be one of: - * <ul> - * <li>AbstractDialog.WARNING</li> - * <li>AbstractDialog.INFORMATION</li> - * <li>AbstractDialog.ERROR</li> - * <li>AbstractDialog.WORKING</li> - * <li>AbstractDialog.QUESTION</li> - * </ul> - */ - public AbstractDialog(Shell parent, String title, Image image) { - super(parent, 0); - setText(title); - this.image = image; - this.parent = parent; - init(); - } - - /** - * Closes this AbstractDialog. - * - * @param success true if the dialog was successful, false if it - * was cancelled by the user (or closed prematurely) - */ - public void close(boolean success){ - shell.dispose(); - this.success = success; - } - - /** - * Returns the shell used by this AbstractDialog - * - * @return the shell used by this AbstractDialog - */ - public Shell getShell(){ - return shell; - } - - /** - * Initializes this AbstractDialog. This consists of resetting all of the - * customizable components like the content area, details pane, buttons, - * and description label, and readying the dialog to be refilled with - * new content. - */ - public void init(){ - if(shell != null) - shell.dispose(); - - shell = new Shell(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | SWT.RESIZE); - - if (parent != null) - shell.setImage(parent.getImage()); - - shell.setText(getText()); - GridLayout layout = new GridLayout(); - layout.numColumns = 1; - shell.setLayout(layout); - } - - /** - * Opens this AbstractDialog. - * - * @return true if this AbstractDialog was closed by clicking the 'x' in the upper right - * corner of the window, signifying a cancellation, false if the dialog is exited otherwise. - */ - public boolean open() { - if (shell.getDisplay().getThread() == Thread.currentThread()) { - doOpen(); - } else { - shell.getDisplay().syncExec(new Runnable() { - public void run() { - doOpen(); - }}); - } - - Display display = getParent().getDisplay(); - - while (!shell.isDisposed()) { - if (!display.readAndDispatch()) { - display.sleep(); - } - } - - return success; - } - - protected void doOpen() { - success = true; - - setupHeader(); - setupContent(); - setupButtons(); - - shell.pack(); - setLocation(); - shell.open(); - shell.addShellListener(new ShellAdapter(){ - public void shellClosed(ShellEvent e) { - success = false; - } - }); - } - - /* - * centers the dialog on its parents shell - */ - private void setLocation(){ - Point parentLocation = parent.getLocation(); - int parentWidth = parent.getSize().x; - int parentHeight = parent.getSize().y; - int shellWidth = shell.getSize().x; - int shellHeight = shell.getSize().y; - - int x = parentLocation.x + (parentWidth - shellWidth)/2; - int y = parentLocation.y + (parentHeight - shellHeight)/2; - shell.setLocation(x, y); - } - - /** - * Sets the Description of this AbstractDialog. This is the textField that is displayed in the - * top section of the Dialog window, giving information about the question that is being - * asked or the information that is being given. - * - * @param description the description for this AbstractDialog to use - */ - public void setDescription(String description) { - this.description = description; - } - - /** - * Sets the details textField of this AbstractDialog. This is the textField that is displayed in the lower - * section of the Dialog window when the user presses the "Details >>" button. If this String - * is null or the empty string, the details button will be disabled. - * - * @param details DOCUMENT ME! - */ - public void setDetails(String details) { - this.detailsString = details; - } - - /** - * Creates the Buttons to use in this AbstractDialog based on the given parent. These are - * the buttons that show up at the bottom of the dialog for user input, such as a - * "Yes/No" group or "Continue/Cancel" or something like that. This does not encompass all - * Buttons created in the dialog (such as those created in the content section), just those - * to display at the bottom of the dialog. - * - * @param parent the parent to be used to create the Buttons for this AbstractDialog - */ - public abstract void createDialogButtons(Composite parent); - - /** - * Creates the content section of this AbstractDialog based on the given parent. - * This section is where all of the "guts" of the AbstractDialog go, specifying the controls - * that are needed to interact with the user and provide whatever questions or information - * are needed. - * - * @param parent the parent to be used to create the Buttosn for this AbstractDialog - * - * @return the Composite that is created to display the content of this AbstractDialog - */ - public abstract Composite createContent(Composite parent); - - /* - * Sets up the header section of the dialog. This section contains the image for the - * type of dialog it is, as well as the description label - */ - private void setupHeader() { - header = new Composite(shell, SWT.NONE); - header.setLayoutData(new GridData(GridData.FILL_BOTH)); - GridLayout layout = new GridLayout(); - layout.numColumns = 2; - header.setLayout(layout); - - Label canvas = new Label(header, SWT.NONE); - if (image != null) { - canvas.setImage(image); - } - GridData canvasData = new GridData(); - canvasData.heightHint = image.getBounds().height; - canvas.setLayoutData(canvasData); - - Label desc = new Label(header, SWT.WRAP); - - if ((description != null) && !description.equals("")) { - desc.setText(description); - } - } - - /* - * sets up the content section of the dialog, this calls the abstract method to - * create the content that must be implemented by all subclasses - */ - private void setupContent() { - content = createContent(shell); - - if (content != null) { - content.setLayoutData(new GridData(GridData.FILL_BOTH)); - } - } - - /* - * sets up the button section in the bottom of the dialog. These buttons - * are created in the abstract method createDialogButtons(parent). In addition to - * any created buttons, a "Details >>" button is added to allow the user to see any - * details that are available in the current Dialog. - */ - private void setupButtons() { - buttons = new Composite(shell, SWT.NONE); - buttons.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.HORIZONTAL_ALIGN_END)); - - //there are two sections, all the user stuff to the left, and - //then the details button on the far right - //User Buttons Section - createDialogButtons(buttons); - Control[] controls = buttons.getChildren(); - GridLayout buttonsLayout = new GridLayout(); - buttonsLayout.numColumns = controls.length + 1; - buttonsLayout.makeColumnsEqualWidth = true; - buttons.setLayout(buttonsLayout); - - //setup the grid data for each button for standard look - for (int i = 0; i < controls.length; i++) { - controls[i].setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - } - - //Details Button section - final Button details = new Button(buttons, SWT.PUSH); - details.setText("Details >>"); - details.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - details.addSelectionListener(new SelectionAdapter() { - public synchronized void widgetSelected(SelectionEvent e) { - GridData data = (GridData) detailsText.getLayoutData(); - - if (detailsText.getVisible()) { - detailsText.setText(""); - details.setText("Details >>"); - data.heightHint = 0; - data.grabExcessHorizontalSpace = false; - data.grabExcessVerticalSpace = false; - } else { - detailsText.setText(detailsString); - details.setText("Details <<"); - data.heightHint = DETAILS_HEIGHT; - data.grabExcessHorizontalSpace = true; - data.grabExcessVerticalSpace = true; - } - - detailsText.setLayoutData(data); - detailsText.setVisible(!detailsText.getVisible()); - - shell.setSize(shell.computeSize(SWT.DEFAULT, SWT.DEFAULT)); - shell.layout(); - } - }); - - setupDetails(); - details.setEnabled(detailsString != null && !detailsString.equals("")); - } - - /* - * creates the details textField box when the "Details >>" button is toggled - */ - private void setupDetails() { - detailsText = new Text(shell, SWT.BORDER | SWT.WRAP | SWT.V_SCROLL); - detailsText.setEditable(false); - detailsText.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)); - - GridData data = new GridData(GridData.FILL_BOTH | - GridData.GRAB_VERTICAL | GridData.GRAB_HORIZONTAL); - data.widthHint = 400; - - detailsText.setLayoutData(data); - detailsText.setVisible(false); - } - - /** - * Open a standard error dialog with OK button - * - * @param parent the parent Shell of this dialog - * @param title the textField to display in the title bar of this dialog - * @param message the message to give in the dialog's body - * @param details the textField to put in the details pane to be visible when the - * "Details >>" button is pressed (can be null or empty, resulting - * in the "Details >>" button not being enabled) - * @return true if the dialog was exited by pressing the OK button, false - * if it was cancelled by pressing the 'x' in the title bar - */ - public static boolean openError(Shell parent, String title, String message, String details){ - return openOKDialog(parent, ERROR, title, message, details); - } - - /** - * Open a standard information dialog with OK button - * - * @param parent the parent Shell of this dialog - * @param title the textField to display in the title bar of this dialog - * @param message the message to give in the dialog's body - * @param details the textField to put in the details pane to be visible when the - * "Details >>" button is pressed (can be null or empty, resulting - * in the "Details >>" button not being enabled) * @return true if the dialog was exited by pressing the OK button, false - * if it was cancelled by pressing the 'x' in the title bar - */ - public static boolean openInformation(Shell parent, String title, String message, String details){ - return openOKDialog(parent, INFORMATION, title, message, details); - } - - /** - * Open a standard warning dialog with OK button - * - * @param parent the parent Shell of this dialog - * @param title the textField to display in the title bar of this dialog - * @param message the message to give in the dialog's body - * @param details the textField to put in the details pane to be visible when the - * "Details >>" button is pressed (can be null or empty, resulting - * in the "Details >>" button not being enabled) * @return true if the dialog was exited by pressing the OK button, false - * if it was cancelled by pressing the 'x' in the title bar - */ - public static boolean openWarning(Shell parent, String title, String message, String details){ - return openOKDialog(parent, WARNING, title, message, details); - } - - /** - * Open a standard question dialog with Yes/No buttons - * - * @param parent the parent Shell of this dialog - * @param title the textField to display in the title bar of this dialog - * @param message the message to give in the dialog's body - * @param details the textField to put in the details pane to be visible when the - * "Details >>" button is pressed (can be null or empty, resulting - * in the "Details >>" button not being enabled) * @return true if the dialog was exited by pressing the OK button, false - * if it was cancelled by pressing the 'x' in the title bar or pressing the - * No button - */ - public static boolean openQuestion(Shell parent, String title, String message, String details){ - return openConfirmDenyDialog(parent, QUESTION, title, message, details, "Yes", "No"); - } - - /** - * Open a standard confirmation dialog with OK/Cancel buttons - * - * @param parent the parent Shell of this dialog - * @param title the textField to display in the title bar of this dialog - * @param message the message to give in the dialog's body - * @param details the textField to put in the details pane to be visible when the - * "Details >>" button is pressed (can be null or empty, resulting - * in the "Details >>" button not being enabled) * @return true if the dialog was exited by pressing the OK button, false - * if it was cancelled by pressing the 'x' in the title bar or pressing - * the Cancel button - */ - public static boolean openConfirm(Shell parent, String title, String message, String details){ - return openConfirmDenyDialog(parent, QUESTION, title, message, details, "OK", "Cancel"); - } - - /* - * helper to create OK dialogs: error, warning, information - */ - private static boolean openOKDialog(Shell parent, Image image, String title, String message, String details){ - AbstractDialog okDialog = new AbstractDialog(parent, title, image){ - public void createDialogButtons(Composite parent) { - Button ok = new Button(parent, SWT.PUSH); - ok.setText("OK"); - ok.addSelectionListener(new SelectionAdapter(){ - public void widgetSelected(SelectionEvent e) { - close(true); - } - }); - } - - public Composite createContent(Composite parent) { - return null; - } - }; - okDialog.setDescription(message); - okDialog.setDetails(details); - return okDialog.open(); - } - - /* - * helper to create confirm/deny dialogs: question, confirmation - */ - private static boolean openConfirmDenyDialog(Shell parent, Image image, String title, String message, String details, final String confirmLabel, final String denyLabel){ - AbstractDialog dialog = new AbstractDialog(parent, title, image){ - public void createDialogButtons(Composite parent) { - Button confirm = new Button(parent, SWT.PUSH); - if(confirmLabel != null) - confirm.setText(confirmLabel); - confirm.addSelectionListener(new SelectionAdapter(){ - public void widgetSelected(SelectionEvent e) { - close(true); - } - }); - Button deny = new Button(parent, SWT.PUSH); - if(denyLabel != null) - deny.setText(denyLabel); - deny.addSelectionListener(new SelectionAdapter(){ - public void widgetSelected(SelectionEvent e) { - close(false); - } - }); - } - - public Composite createContent(Composite parent) { - return null; - } - }; - dialog.setDescription(message); - dialog.setDetails(details); - return dialog.open(); - } -} Modified: trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/fileloader/FileFormatSelector.java =================================================================== --- trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/fileloader/FileFormatSelector.java 2011-03-01 20:09:46 UTC (rev 1230) +++ trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/fileloader/FileFormatSelector.java 2011-03-01 20:10:28 UTC (rev 1231) @@ -3,6 +3,7 @@ import java.io.File; import org.cishell.framework.algorithm.AlgorithmFactory; +import org.cishell.reference.app.service.persistence.AbstractDialog; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; Modified: trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/fileloader/FileLoaderServiceImpl.java =================================================================== --- trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/fileloader/FileLoaderServiceImpl.java 2011-03-01 20:09:46 UTC (rev 1230) +++ trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/fileloader/FileLoaderServiceImpl.java 2011-03-01 20:10:28 UTC (rev 1231) @@ -43,18 +43,25 @@ } } + public File[] getFilesToLoadFromUser(boolean selectSingleFile, String[] filterExtensions) + throws FileLoadException { + IWorkbenchWindow window = getFirstWorkbenchWindow(); + Display display = PlatformUI.getWorkbench().getDisplay(); + + return getFilesToLoadFromUserInternal(window, display, selectSingleFile, filterExtensions); + } + public Data[] loadFilesFromUserSelection( BundleContext bundleContext, CIShellContext ciShellContext, LogService logger, - ProgressMonitor progressMonitor) throws FileLoadException { + ProgressMonitor progressMonitor, + boolean selectSingleFile) throws FileLoadException { if ("".equals(defaultLoadDirectory)) { defaultLoadDirectory = determineDefaultLoadDirectory(); } - IWorkbenchWindow window = getFirstWorkbenchWindow(); - Display display = PlatformUI.getWorkbench().getDisplay(); - File[] files = getFilesToLoadFromUser(window, display); + File[] files = getFilesToLoadFromUser(selectSingleFile, null); if (files != null) { return loadFiles(bundleContext, ciShellContext, logger, progressMonitor, files); @@ -255,8 +262,13 @@ } } - private File[] getFilesToLoadFromUser(IWorkbenchWindow window, Display display) { - FileSelectorRunnable fileSelector = new FileSelectorRunnable(window); + private File[] getFilesToLoadFromUserInternal( + IWorkbenchWindow window, + Display display, + boolean selectSingleFile, + String[] filterExtensions) { + FileSelectorRunnable fileSelector = + new FileSelectorRunnable(window, selectSingleFile, filterExtensions); if (Thread.currentThread() != display.getThread()) { display.syncExec(fileSelector); Modified: trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/fileloader/FileSelectorRunnable.java =================================================================== --- trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/fileloader/FileSelectorRunnable.java 2011-03-01 20:09:46 UTC (rev 1230) +++ trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/fileloader/FileSelectorRunnable.java 2011-03-01 20:10:28 UTC (rev 1231) @@ -8,11 +8,15 @@ public final class FileSelectorRunnable implements Runnable { private IWorkbenchWindow window; - + private boolean selectSingleFile; + private String[] filterExtensions; private File[] files; - public FileSelectorRunnable(IWorkbenchWindow window) { + public FileSelectorRunnable( + IWorkbenchWindow window, boolean selectSingleFile, String[] filterExtensions) { this.window = window; + this.selectSingleFile = selectSingleFile; + this.filterExtensions = filterExtensions; } public File[] getFiles() { @@ -35,7 +39,6 @@ fileDialog.open(); String path = fileDialog.getFilterPath(); String[] fileNames = fileDialog.getFileNames(); - // TODO: Ask Angela about the order here, i.e. should they be sorted alphabetically? if ((fileNames == null) || (fileNames.length == 0)) { return new File[0]; @@ -54,10 +57,24 @@ private FileDialog createFileDialog() { File currentDirectory = new File(FileLoaderServiceImpl.defaultLoadDirectory); String absolutePath = currentDirectory.getAbsolutePath(); - FileDialog fileDialog = new FileDialog(this.window.getShell(), SWT.OPEN | SWT.MULTI); + FileDialog fileDialog = + new FileDialog(this.window.getShell(), SWT.OPEN | determineSWTFileSelectFlag()); fileDialog.setFilterPath(absolutePath); + + if ((this.filterExtensions != null) && (this.filterExtensions.length > 0)) { + fileDialog.setFilterExtensions(this.filterExtensions); + } + fileDialog.setText("Select Files"); return fileDialog; } + + private int determineSWTFileSelectFlag() { + if (this.selectSingleFile) { + return SWT.SINGLE; + } else { + return SWT.MULTI; + } + } } \ No newline at end of file Added: trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/filesaver/DataFormatChooser.java =================================================================== --- trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/filesaver/DataFormatChooser.java (rev 0) +++ trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/filesaver/DataFormatChooser.java 2011-03-01 20:10:28 UTC (rev 1231) @@ -0,0 +1,338 @@ +package org.cishell.reference.app.service.filesaver; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.Dictionary; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +import org.cishell.framework.algorithm.AlgorithmProperty; +import org.cishell.framework.data.Data; +import org.cishell.reference.app.service.persistence.AbstractDialog; +import org.cishell.service.conversion.Converter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyleRange; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.List; +import org.eclipse.swt.widgets.Shell; +import org.osgi.framework.ServiceReference; + +/* TODO Kill dead methods */ +public class DataFormatChooser extends AbstractDialog implements AlgorithmProperty { +// public static final Image QUESTION_ICON = +// Display.getCurrent().getSystemImage(SWT.ICON_QUESTION); + + protected Data data; + protected Converter[] converters; + private List converterListComponent; + private StyledText detailPane; + private Converter chosenConverter; + + public DataFormatChooser(Data data, Shell parent, Converter[] converters, String title) { + super(parent, title, AbstractDialog.QUESTION); + this.data = data; + this.converters = alphabetizeConverters(filterConverters(converters)); + } + + public Converter getChosenConverter() { + return this.chosenConverter; + } + + private Composite initializeGUI(Composite parent) { + Composite content = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.numColumns = 2; + content.setLayout(layout); + + Group converterGroup = new Group(content, SWT.NONE); + converterGroup.setText("Pick the Output Data Type"); + converterGroup.setLayout(new FillLayout()); + GridData persisterData = new GridData(GridData.FILL_BOTH); + persisterData.widthHint = 200; + converterGroup.setLayoutData(persisterData); + + converterListComponent = + new List(converterGroup, SWT.H_SCROLL | SWT.V_SCROLL | SWT.SINGLE); + initializeConverterListComponent(); + converterListComponent.addMouseListener(new MouseAdapter() { + public void mouseDoubleClick(MouseEvent mouseEvent) { + List list = (List)mouseEvent.getSource(); + int selection = list.getSelectionIndex(); + + if (selection != -1) { + selectionMade(selection); + } + } + }); + converterListComponent.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent selectionEvent) { + List list = (List)selectionEvent.getSource(); + int selection = list.getSelectionIndex(); + + if (selection != -1) { + updateDetailPane(converters[selection]); + } + } + }); + + Group detailsGroup = new Group(content, SWT.NONE); + detailsGroup.setText("Details"); + detailsGroup.setLayout(new FillLayout()); + GridData detailsData = new GridData(GridData.FILL_BOTH); + detailsData.widthHint = 200; + detailsGroup.setLayoutData(detailsData); + + detailPane = initializeDetailPane(detailsGroup); + + // Select the first item by default. + converterListComponent.setSelection(0); + updateDetailPane(converters[0]); + + return content; + } + + /** + * Initialize the Listbox of Persisters using the stored Persister array + */ + private void initializeConverterListComponent() { + for (int ii = 0; ii < converters.length; ii++) { + if (converters[ii] != null) { + Dictionary converterProperties = converters[ii].getProperties(); + + // Get the name of the persister from the property map. + String outData = null; + + ServiceReference[] serviceReferences = converters[ii].getConverterChain(); + + if ((serviceReferences != null) && (serviceReferences.length > 0)) { + outData = (String)serviceReferences[serviceReferences.length - 1].getProperty( + AlgorithmProperty.LABEL); + } + + if (outData == null) { + outData = (String)converterProperties.get(AlgorithmProperty.LABEL); + } + + /* + * If someone was sloppy enough to not provide a name, then use the name of the + * class instead. + */ + if ((outData == null) || (outData.length() == 0)) { + outData = converters[ii].getClass().getName(); + } + + converterListComponent.add(outData); + } + } + } + + private StyledText initializeDetailPane(Group detailsGroup) { + StyledText detailPane = new StyledText(detailsGroup, SWT.H_SCROLL | SWT.V_SCROLL); + detailPane.setEditable(false); + detailPane.getCaret().setVisible(false); + + return detailPane; + } + + private void updateDetailPane(Converter converter) { + Dictionary converterProperties = converter.getProperties(); + Enumeration converterPropertiesKeys = converterProperties.keys(); + + detailPane.setText(""); + + while (converterPropertiesKeys.hasMoreElements()) { + Object key = converterPropertiesKeys.nextElement(); + Object value = converterProperties.get(key); + + StyleRange styleRange = new StyleRange(); + styleRange.start = detailPane.getText().length(); + detailPane.append(key + ":\n"); + styleRange.length = key.toString().length() + 1; + styleRange.fontStyle = SWT.BOLD; + detailPane.setStyleRange(styleRange); + + detailPane.append(value + "\n"); + } + } + + private Converter[] filterConverters(Converter[] allConverters) { + Map lastInDataToConverter = new HashMap(); + + for (int ii = 0; ii < allConverters.length; ii++) { + Converter converter = allConverters[ii]; + String lastInputData = getLastConverterInData(converter); + + if (lastInDataToConverter.containsKey(lastInputData)) { + Converter alreadyStoredConverter = + (Converter)lastInDataToConverter.get(lastInputData); + Converter chosenConverter = + returnPreferredConverter(converter, alreadyStoredConverter); + lastInDataToConverter.put(lastInputData, chosenConverter); + } else { + lastInDataToConverter.put(lastInputData, converter); + } + } + + return (Converter[]) lastInDataToConverter.values().toArray(new Converter[0]); + } + + private String getLastConverterInData(Converter converter) { + ServiceReference[] convChain = converter.getConverterChain(); + + if (convChain.length >= 1) { + ServiceReference lastConverter = convChain[convChain.length - 1]; + String lastInData = (String) lastConverter.getProperty("in_data"); + + return lastInData; + } else { + return ""; + } + } + + private Converter returnPreferredConverter(Converter converter1, Converter converter2) { + Dictionary converter1Properties = converter1.getProperties(); + String converter1Lossiness = (String)converter1Properties.get(CONVERSION); + int converter1Quality = determineQuality(converter1Lossiness); + + Dictionary converter2Properties = converter2.getProperties(); + String converter2Lossiness = (String)converter2Properties.get(CONVERSION); + int converter2Quality = determineQuality(converter2Lossiness); + + if (converter1Quality > converter2Quality) { + return converter1; + } else if (converter2Quality > converter1Quality) { + return converter2; + } else { + // They are tied. Look at chosenConverter chain length. + + int converter1Length = converter1.getConverterChain().length; + int converter2Length = converter2.getConverterChain().length; + + if (converter1Length > converter2Length) { + return converter2; + } else if (converter2Length > converter1Length) { + return converter1; + } else { + /* + * Both have the same lossiness and same length. + * Arbitrary pick the first. + */ + return converter1; + } + } + } + + private int determineQuality(String lossiness) { + if (lossiness == LOSSY) { + return 0; + } else if (lossiness == null) { + return 1; + } else { + return 2; + } + } + + private Converter[] alphabetizeConverters(Converter[] converters) { + Arrays.sort(converters, new CompareAlphabetically()); + + return converters; + } + + protected void selectionMade(int selectedIndex) { + try { + getShell().setVisible(false); + this.chosenConverter = converters[selectedIndex]; +// final SaveAsController saver = new SaveAsController(getShell(), ciShellContext); + close(true); +// close(saver.save(chosenConverter, data)); + } catch (Exception exception) { + throw new RuntimeException(exception); + } + } + + public void createDialogButtons(Composite parent) { + Button select = new Button(parent, SWT.PUSH); + select.setText("Select"); + select.addSelectionListener( + new SelectionAdapter() { + public void widgetSelected(SelectionEvent selectionEvent) { + int index = converterListComponent.getSelectionIndex(); + + if (index != -1) { + selectionMade(index); + } + } + } + ); + select.setFocus(); + + Button cancel = new Button(parent, SWT.NONE); + cancel.setText("Cancel"); + cancel.addSelectionListener( + new SelectionAdapter() { + public void widgetSelected(SelectionEvent selectionEvent) { + close(false); + } + } + ); + } + + public Composite createContent(Composite parent) { + if (converters.length == 1) { + close(true); +// final SaveAsController saver = new SaveAsController((Shell) parent, ciShellContext); +// close(saver.save(converters[0], data)); + + return parent; + } else { + return initializeGUI(parent); + } + } + + private class CompareAlphabetically implements Comparator { + public int compare(Object object1, Object object2) { + if ((object1 instanceof Converter) && (object2 instanceof Converter)) { + Converter converter1 = (Converter)object1; + String converter1Label = getLabel(converter1); + + Converter converter2 = (Converter)object2; + String converter2Label = getLabel(converter2); + + if ((converter1Label != null) && (converter2Label != null)) { + return converter1Label.compareTo(converter2Label); + } else if (converter1Label == null) { + return 1; + } else if (converter2Label == null) { + return -1; + } else { + return 0; + } + } else { + throw new IllegalArgumentException("Can only compare Converters"); + } + } + + private String getLabel(Converter converter) { + String label = ""; + ServiceReference[] serviceReferences = converter.getConverterChain(); + + if ((serviceReferences != null) && (serviceReferences.length > 0)) { + label = (String)serviceReferences[serviceReferences.length - 1].getProperty( + AlgorithmProperty.LABEL); + } + + return label; + } + } +} Added: trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/filesaver/FileSaverServiceImpl.java =================================================================== --- trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/filesaver/FileSaverServiceImpl.java (rev 0) +++ trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/filesaver/FileSaverServiceImpl.java 2011-03-01 20:10:28 UTC (rev 1231) @@ -0,0 +1,141 @@ +package org.cishell.reference.app.service.filesaver; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.channels.FileChannel; + +import org.cishell.app.service.filesaver.AbstractFileSaverService; +import org.cishell.app.service.filesaver.FileSaveException; +import org.cishell.framework.data.Data; +import org.cishell.service.conversion.Converter; +import org.cishell.service.conversion.DataConversionService; +import org.cishell.service.guibuilder.GUIBuilderService; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.PlatformUI; +import org.osgi.service.component.ComponentContext; + +public class FileSaverServiceImpl extends AbstractFileSaverService { + public static final String SAVE_DIALOG_TITLE = "Save"; + + private DataConversionService conversionManager; + private GUIBuilderService guiBuilder; + + protected void activate(ComponentContext componentContext) { + this.conversionManager = (DataConversionService) componentContext.locateService("DCS"); + this.guiBuilder = (GUIBuilderService) componentContext.locateService("GBS"); + + } + + public Converter promptForConverter(final Data outDatum, String targetMimeType) + throws FileSaveException { + final Converter[] converters = + this.conversionManager.findConverters(outDatum, targetMimeType); + + if (converters.length == 0) { + throw new FileSaveException("No appropriate converters."); + } else if (converters.length == 1) { + // Only one possible choice in how to save data. Do it. + Converter onlyConverter = converters[0]; + + return onlyConverter; + } else { + final Shell parentShell = PlatformUI.getWorkbench().getWorkbenchWindows()[0].getShell(); + + if (parentShell.isDisposed()) { + throw new FileSaveException( + "Can't create dialog window -- graphical environment not available."); + } + + return showDataFormatChooser(outDatum, converters, parentShell); + } + } + + private Converter showDataFormatChooser( + final Data outDatum, + final Converter[] converters, + final Shell parentShell) throws FileSaveException{ + try { + final Converter[] chosenConverter = new Converter[1]; + guiRun(new Runnable() { + public void run() { + DataFormatChooser formatChooser = new DataFormatChooser( + outDatum, parentShell, converters, SAVE_DIALOG_TITLE); + formatChooser.createContent(new Shell(parentShell)); + formatChooser.open(); + chosenConverter[0] = formatChooser.getChosenConverter(); + } + }); + + return chosenConverter[0]; + } catch (Exception e) { + throw new FileSaveException(e.getMessage(), e); + } + } + + public File promptForTargetFile(final String fileName) throws FileSaveException { + final File[] resultFile = new File[1]; + + try { + guiRun(new Runnable() { + public void run() { + SaveAsController saveAs = + new SaveAsController(FileSaverServiceImpl.this.guiBuilder); + + resultFile[0] = saveAs.open(fileName); + } + }); + + return resultFile[0]; + } catch (Throwable e) { + throw new FileSaveException(e.getMessage(), e); + } + } + + public void saveTo(File sourceFile, File targetFile) throws FileSaveException { + if ((sourceFile != null) && (targetFile != null) && sourceFile.exists()) { + copyFile(sourceFile, targetFile); + } + } + + private void guiRun(Runnable run) { + final Shell parentShell = PlatformUI.getWorkbench().getWorkbenchWindows()[0].getShell(); + + if (Thread.currentThread() == Display.getDefault().getThread()) { + run.run(); + } else { + parentShell.getDisplay().syncExec(run); + } + } + + /* TODO: Don't use cns-utilities, use Files.copy in Guava + * This shouldn't throw FileSaveException -- too specific for a general utility. + * Catch whatever this throws then rethrow as FSE + */ + private static void copyFile(File sourceFile, File targetFile) throws FileSaveException { + try { + FileInputStream inputStream = new FileInputStream(sourceFile); + FileOutputStream outputStream = new FileOutputStream(targetFile); + + FileChannel readableChannel = inputStream.getChannel(); + FileChannel writableChannel = outputStream.getChannel(); + + writableChannel.truncate(0); + writableChannel.transferFrom( + readableChannel, 0, readableChannel.size()); + inputStream.close(); + outputStream.close(); + } catch (IOException ioException) { + String exceptionMessage = + "An error occurred when copying from the file \"" + + sourceFile.getAbsolutePath() + + "\" to the file \"" + + targetFile.getAbsolutePath() + + "\"."; + + throw new FileSaveException(exceptionMessage, ioException); // TODO Just throw IOException + } + } +} \ No newline at end of file Added: trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/filesaver/SaveAsController.java =================================================================== --- trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/filesaver/SaveAsController.java (rev 0) +++ trunk/core/org.cishell.reference/src/org/cishell/reference/app/service/filesaver/SaveAsController.java 2011-03-01 20:10:28 UTC (rev 1231) @@ -0,0 +1,115 @@ +package org.cishell.reference.app.service.filesaver; + +import java.io.File; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +import org.cishell.service.guibuilder.GUIBuilderService; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.PlatformUI; + +public class SaveAsController { + public static final Collection<Character> INVALID_FILENAME_CHARACTERS = + Collections.unmodifiableCollection(Arrays.asList( + '\\', '/', ':', '*', '?', '"', '<', '>', '|', '%')); + public static final char FILENAME_CHARACTER_REPLACEMENT = '#'; + + public static final String FILE_EXTENSION_PREFIX = "file-ext:"; + + private static File currentDirectory; + + private GUIBuilderService guiBuilder; + + public SaveAsController(GUIBuilderService guiBuilder) { + ... [truncated message content] |