annotate java/src/uk/ac/qmul/eecs/ccmi/gui/FileService.java @ 8:ea7885bd9bff tip

fixed bug : render solid line as dotted/dashed when moving the stylus from dotted/dashed to solid
author ccmi-guest
date Thu, 03 Jul 2014 16:12:20 +0100
parents 1c5af356bb99
children
rev   line source
fiore@3 1 /*
fiore@3 2 CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool
fiore@3 3
fiore@3 4 Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
fiore@3 5
fiore@3 6 This program is free software: you can redistribute it and/or modify
fiore@3 7 it under the terms of the GNU General Public License as published by
fiore@3 8 the Free Software Foundation, either version 3 of the License, or
fiore@3 9 (at your option) any later version.
fiore@3 10
fiore@3 11 This program is distributed in the hope that it will be useful,
fiore@3 12 but WITHOUT ANY WARRANTY; without even the implied warranty of
fiore@3 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
fiore@3 14 GNU General Public License for more details.
fiore@3 15
fiore@3 16 You should have received a copy of the GNU General Public License
fiore@3 17 along with this program. If not, see <http://www.gnu.org/licenses/>.
fiore@3 18 */
fiore@0 19 package uk.ac.qmul.eecs.ccmi.gui;
fiore@0 20
fiore@0 21 import java.awt.Frame;
fiore@0 22 import java.io.BufferedInputStream;
fiore@0 23 import java.io.BufferedOutputStream;
fiore@0 24 import java.io.File;
fiore@0 25 import java.io.FileInputStream;
fiore@0 26 import java.io.FileNotFoundException;
fiore@0 27 import java.io.FileOutputStream;
fiore@0 28 import java.io.IOException;
fiore@0 29 import java.io.InputStream;
fiore@0 30 import java.io.OutputStream;
fiore@0 31 import java.util.ResourceBundle;
fiore@0 32
fiore@0 33 import javax.swing.JFileChooser;
fiore@0 34 import javax.swing.JOptionPane;
fiore@0 35
fiore@0 36 import uk.ac.qmul.eecs.ccmi.gui.filechooser.FileChooser;
fiore@0 37 import uk.ac.qmul.eecs.ccmi.gui.filechooser.FileChooserFactory;
fiore@0 38 import uk.ac.qmul.eecs.ccmi.sound.SoundEvent;
fiore@0 39 import uk.ac.qmul.eecs.ccmi.sound.SoundFactory;
fiore@0 40 import uk.ac.qmul.eecs.ccmi.utils.PreferencesService;
fiore@0 41
fiore@5 42 /**
fiore@5 43 * A Utility class providing inner classes and interfaces for handling
fiore@5 44 * files.
fiore@5 45 */
fiore@0 46 public abstract class FileService
fiore@0 47 {
fiore@0 48
fiore@3 49 /**
fiore@3 50 * An Open object encapsulates the stream, name and path of the file that the user selected for opening.
fiore@3 51 */
fiore@3 52 public interface Open
fiore@3 53 {
fiore@3 54 /**
fiore@3 55 * Gets the input stream corresponding to the user selection.
fiore@3 56 * @return the input stream, or null if the user cancels the file selection task
fiore@3 57 */
fiore@5 58 InputStream getInputStream();
fiore@3 59 /**
fiore@3 60 * Gets the name of the file that the user selected.
fiore@3 61 * @return the file name, or null if the user cancels the file selection task
fiore@3 62 */
fiore@5 63 String getName();
fiore@0 64
fiore@3 65 /**
fiore@3 66 * Gets the path of the file that the user selected.
fiore@3 67 * @return the file path , or null if the user cancels the file selection task
fiore@3 68 */
fiore@5 69 String getPath();
fiore@0 70
fiore@3 71 }
fiore@0 72
fiore@3 73 /**
fiore@3 74 * A Save object encapsulates the stream and name of the file that the user selected for saving.
fiore@3 75 */
fiore@3 76 public interface Save
fiore@3 77 {
fiore@3 78 /**
fiore@3 79 * Gets the output stream corresponding to the user selection.
fiore@3 80 * @return the output stream, or null if the user cancels the file selection task
fiore@3 81 */
fiore@3 82 OutputStream getOutputStream();
fiore@3 83 /**
fiore@3 84 * Gets the name of the file that the user selected.
fiore@3 85 * @return the file name, or null if the user cancels the file selection task
fiore@3 86 */
fiore@3 87 String getName();
fiore@3 88 /**
fiore@3 89 * Gets the path of the file that the user selected.
fiore@3 90 * @return the file path, or null if the user cancels the file selection task
fiore@3 91 */
fiore@3 92 String getPath();
fiore@3 93 }
fiore@0 94
fiore@3 95 /**
fiore@5 96 * This class returns a FileService for opening and saving files, with either a JFileChooser or a
fiore@5 97 * SpeechFileChooser
fiore@3 98 */
fiore@3 99 public static class ChooserService
fiore@3 100 {
fiore@5 101 /**
fiore@5 102 * Creates a new {@code ChooserService}.
fiore@5 103 *
fiore@5 104 * @param initialDirectory the directory displayed when the files service is displayed
fiore@5 105 */
fiore@3 106 public ChooserService(File initialDirectory){
fiore@3 107 useAccessible = Boolean.parseBoolean(PreferencesService.getInstance().get("use_accessible_filechooser", "true"));
fiore@3 108 fileChooser = FileChooserFactory.getFileChooser(useAccessible);
fiore@3 109 fileChooser.setCurrentDirectory(initialDirectory);
fiore@3 110 }
fiore@0 111
fiore@5 112 /**
fiore@5 113 * Returns a {@code FileService.Open} out of a file chosen by the user. The user is prompted
fiore@5 114 * with either a normal or an accessible file choser.
fiore@5 115 *
fiore@5 116 * @param defaultDirectory the directory to open the file chooser, prompted to the user
fiore@5 117 * @param defaultFile the file selected when the file chooser is prompted to the user
fiore@5 118 * @param filter an {@code ExtensionFilter} to filter the filed displayed on the file chooser
fiore@5 119 * @param frame the frame where the file chooser is displayed
fiore@5 120 * @return an {@code FileService.Open} to handle the file selected by the user
fiore@5 121 * @throws IOException if the file chosen by the uses doesn't exist.
fiore@5 122 */
fiore@3 123 public FileService.Open open(String defaultDirectory, String defaultFile,
fiore@5 124 ExtensionFilter filter, Frame frame) throws IOException {
fiore@3 125 checkChangedOption();
fiore@3 126 fileChooser.resetChoosableFileFilters();
fiore@3 127 fileChooser.setFileFilter(filter);
fiore@3 128 if (defaultDirectory != null)
fiore@3 129 fileChooser.setCurrentDirectory(new File(defaultDirectory));
fiore@3 130 if (defaultFile == null)
fiore@3 131 fileChooser.setSelectedFile(null);
fiore@3 132 else
fiore@3 133 fileChooser.setSelectedFile(new File(defaultFile));
fiore@3 134 int response = fileChooser.showOpenDialog(frame);
fiore@3 135 if (response == JFileChooser.APPROVE_OPTION)
fiore@3 136 return new OpenImpl(fileChooser.getSelectedFile());
fiore@3 137 else{
fiore@3 138 /* If the user cancels the task (presses cancel button or the X at the top left corner) *
fiore@3 139 * the CANCEl sound is played (together with the registered playerListeenr if any) */
fiore@3 140 if(useAccessible)
fiore@3 141 SoundFactory.getInstance().play(SoundEvent.CANCEL);
fiore@3 142 return new OpenImpl(null);
fiore@3 143 }
fiore@3 144 }
fiore@3 145
fiore@5 146 /**
fiore@5 147 * Returns a {@code FileService.Save} out of a file chosen by the user. The user is prompted
fiore@5 148 * with either a normal or an accessible file chooser.
fiore@5 149 *
fiore@5 150 * @param defaultDirectory the directory to open the file chooser, prompted to the user
fiore@5 151 * @param defaultFile the file selected when the file chooser is prompted to the user
fiore@5 152 * @param filter an {@code ExtensionFilter} to filter the filed displayed on the file chooser
fiore@5 153 * @param removeExtension the extension to be removed from the chosen file name. Use {@code null} for removing no extension
fiore@5 154 * @param addExtension the extension to be added to the chosen file name.
fiore@5 155 * @param currentTabs an array of already open files names. If the selected file matches any of these, then an
fiore@6 156 * Exception is thrown. If {@code null} is passed, then this parameter will be ignored and no check will be done.
fiore@5 157 * @return an {@code FileService.Save} to handle the file selected by the user
fiore@5 158 * @throws IOException if the file chosen by the uses doesn't exist or has a file name that's already
fiore@5 159 * in {@code currentTabs}.
fiore@5 160 */
fiore@3 161 public FileService.Save save(String defaultDirectory, String defaultFile,
fiore@3 162 ExtensionFilter filter, String removeExtension, String addExtension, String[] currentTabs) throws IOException {
fiore@3 163 checkChangedOption();
fiore@3 164 fileChooser.resetChoosableFileFilters();
fiore@3 165 fileChooser.setFileFilter(filter);
fiore@3 166 if (defaultDirectory == null)
fiore@3 167 fileChooser.setCurrentDirectory(new File("."));
fiore@3 168 else
fiore@3 169 fileChooser.setCurrentDirectory(new File(defaultDirectory));
fiore@3 170 if (defaultFile != null){
fiore@3 171 File f = new File(editExtension(defaultFile, removeExtension, addExtension));
fiore@3 172 if(f.exists())
fiore@3 173 fileChooser.setSelectedFile(f);
fiore@3 174 else
fiore@3 175 fileChooser.setSelectedFile(null);
fiore@3 176 }else
fiore@3 177 fileChooser.setSelectedFile(null);
fiore@3 178 int response = fileChooser.showSaveDialog(null);
fiore@3 179 if (response == JFileChooser.APPROVE_OPTION){
fiore@3 180 ResourceBundle resources = ResourceBundle.getBundle(EditorFrame.class.getName());
fiore@3 181 File f = fileChooser.getSelectedFile();
fiore@3 182 if (addExtension != null && f.getName().indexOf(".") < 0) // no extension supplied
fiore@3 183 f = new File(f.getPath() + addExtension);
fiore@3 184
fiore@3 185 String fileName = getFileNameFromPath(f.getAbsolutePath(),false);
fiore@5 186 /* check the name against the names of already open tabs */
fiore@5 187 if(currentTabs != null){
fiore@5 188 for(String tab : currentTabs){
fiore@5 189 if(fileName.equals(tab))
fiore@5 190 throw new IOException(resources.getString("dialog.error.same_file_name"));
fiore@5 191 }
fiore@3 192 }
fiore@3 193
fiore@3 194 if (!f.exists()) // file doesn't exits return the new SaveImpl with no problems
fiore@3 195 return new SaveImpl(f);
fiore@3 196
fiore@3 197 /* file with this name already exists, we must ask the user to confirm */
fiore@3 198 if(useAccessible){
fiore@3 199 int result = SpeechOptionPane.showConfirmDialog(
fiore@3 200 null,
fiore@3 201 resources.getString("dialog.overwrite"),
fiore@3 202 SpeechOptionPane.YES_NO_OPTION);
fiore@3 203 if (result == SpeechOptionPane.YES_OPTION)
fiore@3 204 return new SaveImpl(f);
fiore@3 205 }else{
fiore@3 206 int result = JOptionPane.showConfirmDialog(
fiore@3 207 null,
fiore@3 208 resources.getString("dialog.overwrite"),
fiore@3 209 null,
fiore@3 210 JOptionPane.YES_NO_OPTION);
fiore@3 211 if (result == JOptionPane.YES_OPTION)
fiore@3 212 return new SaveImpl(f);
fiore@3 213 }
fiore@3 214 }
fiore@5 215 /* If the user cancels the task (presses cancel button or the X at the top left) *
fiore@5 216 * the CANCEl sound is played (together with the registered playerListeenr if any) */
fiore@3 217 if(useAccessible)
fiore@3 218 SoundFactory.getInstance().play(SoundEvent.CANCEL);
fiore@3 219 /* returned if the user doesn't want to overwrite the file */
fiore@3 220 return new SaveImpl(null);
fiore@3 221 }
fiore@3 222
fiore@3 223 /* check if the user has changed the configuration since the last time a the fileChooser was shown */
fiore@3 224 private void checkChangedOption(){
fiore@3 225 boolean useAccessible = Boolean.parseBoolean(PreferencesService.getInstance().get("use_accessible_filechooser", "true"));
fiore@3 226 if(this.useAccessible != useAccessible){
fiore@3 227 this.useAccessible = useAccessible;
fiore@3 228 File currentDir = fileChooser.getCurrentDirectory();
fiore@3 229 fileChooser = FileChooserFactory.getFileChooser(useAccessible);
fiore@3 230 fileChooser.setCurrentDirectory(currentDir);
fiore@3 231 }
fiore@3 232 }
fiore@3 233
fiore@3 234 private FileChooser fileChooser;
fiore@3 235 private boolean useAccessible;
fiore@3 236 }
fiore@3 237
fiore@5 238 /**
fiore@5 239 * A file service which doesn't show any dialog to let
fiore@5 240 * the user choose which file to open or save.
fiore@5 241 */
fiore@3 242 public static class DirectService {
fiore@5 243 /**
fiore@5 244 * Creates a {@code FileService.Open} out of the file passed as argument.
fiore@5 245 *
fiore@5 246 * @param file the file to open
fiore@5 247 * @return a new {@code FileService.Open} instance
fiore@5 248 * @throws IOException if {@code file} cannot be found
fiore@5 249 */
fiore@5 250 public FileService.Open open(File file) throws IOException{
fiore@3 251 return new OpenImpl(file);
fiore@3 252 }
fiore@3 253
fiore@5 254 /**
fiore@5 255 * Creates a {@code FileService.Save} out of the file passed as argument.
fiore@5 256 *
fiore@5 257 * @param file the file to save
fiore@5 258 * @return a new {@code FileService.Save} instance
fiore@5 259 * @throws IOException if {@code file} cannot be found
fiore@5 260 */
fiore@5 261 public FileService.Save save(File file) throws IOException{
fiore@3 262 return new SaveImpl(file);
fiore@3 263 }
fiore@3 264 }
fiore@3 265
fiore@3 266 private static class SaveImpl implements FileService.Save{
fiore@3 267 public SaveImpl(File f) throws FileNotFoundException{
fiore@3 268 if (f != null){
fiore@3 269 path = f.getPath();
fiore@3 270 name = getFileNameFromPath(path,false);
fiore@3 271 out = new BufferedOutputStream(new FileOutputStream(f));
fiore@3 272 }
fiore@3 273 }
fiore@3 274
fiore@3 275 @Override
fiore@3 276 public String getName() { return name; }
fiore@3 277 @Override
fiore@3 278 public String getPath() {return path; }
fiore@3 279 @Override
fiore@3 280 public OutputStream getOutputStream() { return out; }
fiore@3 281
fiore@3 282 private String name;
fiore@3 283 private String path;
fiore@3 284 private OutputStream out;
fiore@3 285 }
fiore@3 286
fiore@5 287 private static class OpenImpl implements FileService.Open{
fiore@3 288 public OpenImpl(File f) throws FileNotFoundException{
fiore@3 289 if (f != null){
fiore@3 290 path = f.getPath();
fiore@3 291 name = getFileNameFromPath(path,false);
fiore@3 292 in = new BufferedInputStream(new FileInputStream(f));
fiore@3 293 }
fiore@3 294 }
fiore@3 295
fiore@3 296 @Override
fiore@3 297 public String getName() { return name; }
fiore@3 298 @Override
fiore@3 299 public String getPath() { return path; }
fiore@3 300 @Override
fiore@3 301 public InputStream getInputStream() { return in; }
fiore@3 302
fiore@3 303 private String path;
fiore@3 304 private String name;
fiore@3 305 private InputStream in;
fiore@3 306 }
fiore@3 307
fiore@3 308 /**
fiore@5 309 * Edits the file path so that it ends in the desired
fiore@5 310 * extension.
fiore@5 311 * @param original the file to use as a starting point
fiore@5 312 * @param toBeRemoved the extension that is to be
fiore@5 313 * removed before adding the desired extension. Use
fiore@5 314 * null if nothing needs to be removed.
fiore@5 315 * @param desired the desired extension (e.g. ".png"),
fiore@5 316 * or a | separated list of extensions
fiore@5 317 * @return original if it already has the desired
fiore@5 318 * extension, or a new file with the edited file path
fiore@3 319 */
fiore@3 320 public static String editExtension(String original,
fiore@3 321 String toBeRemoved, String desired){
fiore@3 322 if (original == null) return null;
fiore@3 323 int n = desired.indexOf('|');
fiore@3 324 if (n >= 0) desired = desired.substring(0, n);
fiore@3 325 String path = original;
fiore@3 326 if (!path.toLowerCase().endsWith(desired.toLowerCase())){
fiore@3 327 if (toBeRemoved != null && path.toLowerCase().endsWith(
fiore@3 328 toBeRemoved.toLowerCase()))
fiore@3 329 path = path.substring(0, path.length() - toBeRemoved.length());
fiore@3 330 path = path + desired;
fiore@3 331 }
fiore@3 332 return path;
fiore@3 333 }
fiore@3 334
fiore@5 335 /**
fiore@5 336 * Returns the single file name from a file path
fiore@5 337 *
fiore@5 338 * @param path the path to extract the file name from
fiore@5 339 * @param keepExtension whether to keep the extension of the file
fiore@5 340 * in the returned string
fiore@5 341 * @return the name of the file identified by {@code path}
fiore@5 342 */
fiore@3 343 public static String getFileNameFromPath(String path,boolean keepExtension){
fiore@3 344 int index = path.lastIndexOf(System.getProperty("file.separator"));
fiore@3 345 String name;
fiore@3 346 if(index == -1)
fiore@3 347 name = path;
fiore@3 348 else
fiore@3 349 name = path.substring(index+1);
fiore@3 350 if(!keepExtension){
fiore@3 351 index = name.lastIndexOf('.');
fiore@3 352 if(index != -1)
fiore@3 353 name = name.substring(0, index);
fiore@3 354 }
fiore@3 355 return name;
fiore@3 356 }
fiore@0 357 }