fiore@3: /* fiore@3: CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool fiore@3: fiore@3: Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/) fiore@3: fiore@3: This program is free software: you can redistribute it and/or modify fiore@3: it under the terms of the GNU General Public License as published by fiore@3: the Free Software Foundation, either version 3 of the License, or fiore@3: (at your option) any later version. fiore@3: fiore@3: This program is distributed in the hope that it will be useful, fiore@3: but WITHOUT ANY WARRANTY; without even the implied warranty of fiore@3: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the fiore@3: GNU General Public License for more details. fiore@3: fiore@3: You should have received a copy of the GNU General Public License fiore@3: along with this program. If not, see . fiore@3: */ fiore@0: package uk.ac.qmul.eecs.ccmi.gui; fiore@0: fiore@0: import java.awt.Frame; fiore@0: import java.io.BufferedInputStream; fiore@0: import java.io.BufferedOutputStream; fiore@0: import java.io.File; fiore@0: import java.io.FileInputStream; fiore@0: import java.io.FileNotFoundException; fiore@0: import java.io.FileOutputStream; fiore@0: import java.io.IOException; fiore@0: import java.io.InputStream; fiore@0: import java.io.OutputStream; fiore@0: import java.util.ResourceBundle; fiore@0: fiore@0: import javax.swing.JFileChooser; fiore@0: import javax.swing.JOptionPane; fiore@0: fiore@0: import uk.ac.qmul.eecs.ccmi.gui.filechooser.FileChooser; fiore@0: import uk.ac.qmul.eecs.ccmi.gui.filechooser.FileChooserFactory; fiore@0: import uk.ac.qmul.eecs.ccmi.sound.SoundEvent; fiore@0: import uk.ac.qmul.eecs.ccmi.sound.SoundFactory; fiore@0: import uk.ac.qmul.eecs.ccmi.utils.PreferencesService; fiore@0: fiore@0: public abstract class FileService fiore@0: { fiore@0: fiore@3: /** fiore@3: * An Open object encapsulates the stream, name and path of the file that the user selected for opening. fiore@3: */ fiore@3: public interface Open fiore@3: { fiore@3: /** fiore@3: * Gets the input stream corresponding to the user selection. fiore@3: * @return the input stream, or null if the user cancels the file selection task fiore@3: */ fiore@3: InputStream getInputStream() throws IOException ; fiore@3: /** fiore@3: * Gets the name of the file that the user selected. fiore@3: * @return the file name, or null if the user cancels the file selection task fiore@3: */ fiore@3: String getName() throws IOException ; fiore@0: fiore@3: /** fiore@3: * Gets the path of the file that the user selected. fiore@3: * @return the file path , or null if the user cancels the file selection task fiore@3: */ fiore@3: String getPath() throws IOException; fiore@0: fiore@3: } fiore@0: fiore@3: /** fiore@3: * A Save object encapsulates the stream and name of the file that the user selected for saving. fiore@3: */ fiore@3: public interface Save fiore@3: { fiore@3: /** fiore@3: * Gets the output stream corresponding to the user selection. fiore@3: * @return the output stream, or null if the user cancels the file selection task fiore@3: */ fiore@3: OutputStream getOutputStream(); fiore@3: /** fiore@3: * Gets the name of the file that the user selected. fiore@3: * @return the file name, or null if the user cancels the file selection task fiore@3: */ fiore@3: String getName(); fiore@3: /** fiore@3: * Gets the path of the file that the user selected. fiore@3: * @return the file path, or null if the user cancels the file selection task fiore@3: */ fiore@3: String getPath(); fiore@3: } fiore@0: fiore@3: /** fiore@3: * This class implements a FileService with a JFileChooser fiore@3: */ fiore@3: public static class ChooserService fiore@3: { fiore@3: public ChooserService(File initialDirectory){ fiore@3: useAccessible = Boolean.parseBoolean(PreferencesService.getInstance().get("use_accessible_filechooser", "true")); fiore@3: fileChooser = FileChooserFactory.getFileChooser(useAccessible); fiore@3: fileChooser.setCurrentDirectory(initialDirectory); fiore@3: } fiore@0: fiore@3: public FileService.Open open(String defaultDirectory, String defaultFile, fiore@3: ExtensionFilter filter, Frame frame) throws FileNotFoundException { fiore@3: checkChangedOption(); fiore@3: fileChooser.resetChoosableFileFilters(); fiore@3: fileChooser.setFileFilter(filter); fiore@3: if (defaultDirectory != null) fiore@3: fileChooser.setCurrentDirectory(new File(defaultDirectory)); fiore@3: if (defaultFile == null) fiore@3: fileChooser.setSelectedFile(null); fiore@3: else fiore@3: fileChooser.setSelectedFile(new File(defaultFile)); fiore@3: int response = fileChooser.showOpenDialog(frame); fiore@3: if (response == JFileChooser.APPROVE_OPTION) fiore@3: return new OpenImpl(fileChooser.getSelectedFile()); fiore@3: else{ fiore@3: /* If the user cancels the task (presses cancel button or the X at the top left corner) * fiore@3: * the CANCEl sound is played (together with the registered playerListeenr if any) */ fiore@3: if(useAccessible) fiore@3: SoundFactory.getInstance().play(SoundEvent.CANCEL); fiore@3: return new OpenImpl(null); fiore@3: } fiore@3: } fiore@3: fiore@3: fiore@3: /* If the user cancels the task (presses cancel button or the X at the top left) * fiore@3: * the CANCEl sound is played (together with the registered playerListeenr if any) */ fiore@3: public FileService.Save save(String defaultDirectory, String defaultFile, fiore@3: ExtensionFilter filter, String removeExtension, String addExtension, String[] currentTabs) throws IOException { fiore@3: checkChangedOption(); fiore@3: fileChooser.resetChoosableFileFilters(); fiore@3: fileChooser.setFileFilter(filter); fiore@3: if (defaultDirectory == null) fiore@3: fileChooser.setCurrentDirectory(new File(".")); fiore@3: else fiore@3: fileChooser.setCurrentDirectory(new File(defaultDirectory)); fiore@3: if (defaultFile != null){ fiore@3: File f = new File(editExtension(defaultFile, removeExtension, addExtension)); fiore@3: if(f.exists()) fiore@3: fileChooser.setSelectedFile(f); fiore@3: else fiore@3: fileChooser.setSelectedFile(null); fiore@3: }else fiore@3: fileChooser.setSelectedFile(null); fiore@3: int response = fileChooser.showSaveDialog(null); fiore@3: if (response == JFileChooser.APPROVE_OPTION){ fiore@3: ResourceBundle resources = ResourceBundle.getBundle(EditorFrame.class.getName()); fiore@3: File f = fileChooser.getSelectedFile(); fiore@3: if (addExtension != null && f.getName().indexOf(".") < 0) // no extension supplied fiore@3: f = new File(f.getPath() + addExtension); fiore@3: fiore@3: String fileName = getFileNameFromPath(f.getAbsolutePath(),false); fiore@3: for(String tab : currentTabs){ fiore@3: if(fileName.equals(tab)) fiore@3: throw new IOException(resources.getString("dialog.error.same_file_name")); fiore@3: } fiore@3: fiore@3: if (!f.exists()) // file doesn't exits return the new SaveImpl with no problems fiore@3: return new SaveImpl(f); fiore@3: fiore@3: /* file with this name already exists, we must ask the user to confirm */ fiore@3: if(useAccessible){ fiore@3: int result = SpeechOptionPane.showConfirmDialog( fiore@3: null, fiore@3: resources.getString("dialog.overwrite"), fiore@3: SpeechOptionPane.YES_NO_OPTION); fiore@3: if (result == SpeechOptionPane.YES_OPTION) fiore@3: return new SaveImpl(f); fiore@3: }else{ fiore@3: int result = JOptionPane.showConfirmDialog( fiore@3: null, fiore@3: resources.getString("dialog.overwrite"), fiore@3: null, fiore@3: JOptionPane.YES_NO_OPTION); fiore@3: if (result == JOptionPane.YES_OPTION) fiore@3: return new SaveImpl(f); fiore@3: } fiore@3: } fiore@3: if(useAccessible) fiore@3: SoundFactory.getInstance().play(SoundEvent.CANCEL); fiore@3: /* returned if the user doesn't want to overwrite the file */ fiore@3: return new SaveImpl(null); fiore@3: } fiore@3: fiore@3: /* check if the user has changed the configuration since the last time a the fileChooser was shown */ fiore@3: private void checkChangedOption(){ fiore@3: boolean useAccessible = Boolean.parseBoolean(PreferencesService.getInstance().get("use_accessible_filechooser", "true")); fiore@3: if(this.useAccessible != useAccessible){ fiore@3: this.useAccessible = useAccessible; fiore@3: File currentDir = fileChooser.getCurrentDirectory(); fiore@3: fileChooser = FileChooserFactory.getFileChooser(useAccessible); fiore@3: fileChooser.setCurrentDirectory(currentDir); fiore@3: } fiore@3: } fiore@3: fiore@3: private FileChooser fileChooser; fiore@3: private boolean useAccessible; fiore@3: } fiore@3: fiore@3: public static class DirectService { fiore@3: public Open open(File file) throws IOException{ fiore@3: return new OpenImpl(file); fiore@3: } fiore@3: fiore@3: public Save save(File file) throws IOException{ fiore@3: return new SaveImpl(file); fiore@3: } fiore@3: } fiore@3: fiore@3: private static class SaveImpl implements FileService.Save{ fiore@3: public SaveImpl(File f) throws FileNotFoundException{ fiore@3: if (f != null){ fiore@3: path = f.getPath(); fiore@3: name = getFileNameFromPath(path,false); fiore@3: out = new BufferedOutputStream(new FileOutputStream(f)); fiore@3: } fiore@3: } fiore@3: fiore@3: @Override fiore@3: public String getName() { return name; } fiore@3: @Override fiore@3: public String getPath() {return path; } fiore@3: @Override fiore@3: public OutputStream getOutputStream() { return out; } fiore@3: fiore@3: private String name; fiore@3: private String path; fiore@3: private OutputStream out; fiore@3: } fiore@3: fiore@3: private static class OpenImpl implements FileService.Open fiore@3: { fiore@3: public OpenImpl(File f) throws FileNotFoundException{ fiore@3: if (f != null){ fiore@3: path = f.getPath(); fiore@3: name = getFileNameFromPath(path,false); fiore@3: in = new BufferedInputStream(new FileInputStream(f)); fiore@3: } fiore@3: } fiore@3: fiore@3: @Override fiore@3: public String getName() { return name; } fiore@3: @Override fiore@3: public String getPath() { return path; } fiore@3: @Override fiore@3: public InputStream getInputStream() { return in; } fiore@3: fiore@3: private String path; fiore@3: private String name; fiore@3: private InputStream in; fiore@3: } fiore@3: fiore@3: /** fiore@0: Edits the file path so that it ends in the desired fiore@0: extension. fiore@0: @param original the file to use as a starting point fiore@0: @param toBeRemoved the extension that is to be fiore@0: removed before adding the desired extension. Use fiore@0: null if nothing needs to be removed. fiore@0: @param desired the desired extension (e.g. ".png"), fiore@0: or a | separated list of extensions fiore@0: @return original if it already has the desired fiore@0: extension, or a new file with the edited file path fiore@3: */ fiore@3: public static String editExtension(String original, fiore@3: String toBeRemoved, String desired){ fiore@3: if (original == null) return null; fiore@3: int n = desired.indexOf('|'); fiore@3: if (n >= 0) desired = desired.substring(0, n); fiore@3: String path = original; fiore@3: if (!path.toLowerCase().endsWith(desired.toLowerCase())){ fiore@3: if (toBeRemoved != null && path.toLowerCase().endsWith( fiore@3: toBeRemoved.toLowerCase())) fiore@3: path = path.substring(0, path.length() - toBeRemoved.length()); fiore@3: path = path + desired; fiore@3: } fiore@3: return path; fiore@3: } fiore@3: fiore@3: public static String getFileNameFromPath(String path,boolean keepExtension){ fiore@3: int index = path.lastIndexOf(System.getProperty("file.separator")); fiore@3: String name; fiore@3: if(index == -1) fiore@3: name = path; fiore@3: else fiore@3: name = path.substring(index+1); fiore@3: if(!keepExtension){ fiore@3: index = name.lastIndexOf('.'); fiore@3: if(index != -1) fiore@3: name = name.substring(0, index); fiore@3: } fiore@3: return name; fiore@3: } fiore@0: }