001package icy.gui.dialog; 002 003import java.awt.Dimension; 004import java.awt.Rectangle; 005import java.beans.PropertyChangeEvent; 006import java.beans.PropertyChangeListener; 007import java.io.File; 008import java.util.Collection; 009import java.util.List; 010 011import javax.swing.JFileChooser; 012import javax.swing.filechooser.FileFilter; 013 014import icy.file.FileImporter; 015import icy.file.FileUtil; 016import icy.file.Loader; 017import icy.file.SequenceFileImporter; 018import icy.file.SequenceFileSticher; 019import icy.file.SequenceFileSticher.SequenceFileGroup; 020import icy.gui.dialog.LoaderOptionPanel.LoaderLoadingType; 021import icy.main.Icy; 022import icy.preferences.ApplicationPreferences; 023import icy.preferences.GeneralPreferences; 024import icy.preferences.XMLPreferences; 025import icy.type.collection.CollectionUtil; 026import icy.util.StringUtil; 027 028/** 029 * Loader dialog used to load resource or image from the {@link FileImporter} or 030 * {@link SequenceFileImporter}. 031 * 032 * @author Stephane 033 * @see Loader 034 */ 035public class LoaderDialog extends JFileChooser implements PropertyChangeListener 036{ 037 /** 038 * 039 */ 040 private static final long serialVersionUID = 5162434537949723956L; 041 042 public static class AllImagesFileFilter extends FileFilter 043 { 044 @Override 045 public boolean accept(File file) 046 { 047 if (file.isDirectory()) 048 return true; 049 050 return !Loader.canDiscardImageFile(file.getName()); 051 } 052 053 @Override 054 public String getDescription() 055 { 056 return "All images file"; 057 } 058 } 059 060 public static class AllFileFilter extends FileFilter 061 { 062 @Override 063 public boolean accept(File file) 064 { 065 return file.exists(); 066 } 067 068 @Override 069 public String getDescription() 070 { 071 return "All files"; 072 } 073 } 074 075 public static AllImagesFileFilter allImagesFileFilter = new AllImagesFileFilter(); 076 public static AllFileFilter allFileFilter = new AllFileFilter(); 077 078 private static final String PREF_ID = "frame/imageLoader"; 079 080 private static final String ID_WIDTH = "width"; 081 private static final String ID_HEIGTH = "heigth"; 082 private static final String ID_LOADTYPE = "loadtype"; 083 private static final String ID_EXTENSION = "extension"; 084 085 // GUI 086 protected final LoaderOptionPanel optionPanel; 087 protected final List<SequenceFileImporter> sequenceImporters; 088 protected final List<FileImporter> fileImporters; 089 090 /** 091 * Display a dialog to select image or resource file(s) and load them.<br> 092 * <br> 093 * To only get selected files from the dialog you must do:<br> 094 * <code> LoaderDialog dialog = new LoaderDialog(false);</code><br> 095 * <code> File[] selectedFiles = dialog.getSelectedFiles()</code><br> 096 * <br> 097 * To directly load selected files just use:<br> 098 * <code>new LoaderDialog(true);</code><br> 099 * or<br> 100 * <code>new LoaderDialog();</code> 101 * 102 * @param defaultPath 103 * default file path (can be null) 104 * @param region 105 * default XY region (can be null) 106 * @param series 107 * default series (can be -1) 108 * @param autoLoad 109 * If true the selected file(s) are automatically loaded. 110 */ 111 public LoaderDialog(String defaultPath, Rectangle region, int series, boolean autoLoad) 112 { 113 super(); 114 115 final XMLPreferences preferences = ApplicationPreferences.getPreferences().node(PREF_ID); 116 sequenceImporters = Loader.getSequenceFileImporters(); 117 fileImporters = Loader.getFileImporters(); 118 119 // create option panel 120 optionPanel = new LoaderOptionPanel( 121 LoaderLoadingType.values()[preferences.getInt(ID_LOADTYPE, LoaderLoadingType.GROUP.ordinal())]); 122 123 // we can only store dimension for JFileChooser 124 setPreferredSize(new Dimension(preferences.getInt(ID_WIDTH, 600), preferences.getInt(ID_HEIGTH, 400))); 125 126 setMultiSelectionEnabled(true); 127 setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); 128 129 setAcceptAllFileFilterUsed(false); 130 resetChoosableFileFilters(); 131 132 // add file filter from importers 133 for (SequenceFileImporter importer : sequenceImporters) 134 { 135 final List<FileFilter> filters = importer.getFileFilters(); 136 137 if (filters != null) 138 { 139 for (FileFilter filter : filters) 140 addChoosableFileFilter(filter); 141 } 142 } 143 for (FileImporter importer : fileImporters) 144 { 145 final List<FileFilter> filters = importer.getFileFilters(); 146 147 if (filters != null) 148 { 149 for (FileFilter filter : filters) 150 addChoosableFileFilter(filter); 151 } 152 } 153 // add "all files" filter 154 addChoosableFileFilter(allFileFilter); 155 156 // we use a default path ? 157 if (defaultPath != null) 158 { 159 // set all files filter 160 setFileFilter(allFileFilter); 161 162 final File file = new File(defaultPath); 163 164 if (file.isDirectory()) 165 setCurrentDirectory(file); 166 else 167 setSelectedFile(file); 168 } 169 else 170 { 171 // set last used file filter 172 setFileFilter(getFileFilter(preferences.get(ID_EXTENSION, allImagesFileFilter.getDescription()))); 173 // set last used directory 174 setCurrentDirectory(new File(GeneralPreferences.getLoaderFolder())); 175 } 176 177 // setting GUI 178 updateGUI(); 179 180 // we use a default path ? 181 if (defaultPath != null) 182 { 183 // refresh preview 184 optionPanel.updatePreview(new String[] {defaultPath}, series); 185 // updateOptionPanel(); 186 // have a default XY region ? 187 if (region != null) 188 optionPanel.setXYRegion(region); 189 } 190 191 // listen file filter change 192 addPropertyChangeListener(this); 193 194 // display loader 195 final int value = showOpenDialog(Icy.getMainInterface().getMainFrame()); 196 197 // action confirmed ? 198 if (value == JFileChooser.APPROVE_OPTION) 199 { 200 // store current path 201 GeneralPreferences.setLoaderFolder(getCurrentDirectory().getAbsolutePath()); 202 preferences.putInt(ID_LOADTYPE, optionPanel.getLoadingType().ordinal()); 203 preferences.put(ID_EXTENSION, getFileFilter().getDescription()); 204 205 // load if requested 206 if (autoLoad) 207 { 208 // get selected paths 209 final List<String> paths = CollectionUtil.asList(FileUtil.toPaths(getSelectedFiles())); 210 // first path 211 final String firstPath = paths.get(0); 212 // get the selected importer from file filter 213 final Object importer = getSelectedImporter(); 214 215 // multiple files or folder loading 216 if ((paths.size() > 1) || FileUtil.isDirectory(firstPath)) 217 { 218 if (importer instanceof FileImporter) 219 { 220 // load selected non image file(s) 221 Loader.load((FileImporter) importer, paths, true); 222 } 223 else 224 { 225 if (isSeparateSequenceSelected()) 226 // load selected image file(s) separately 227 Loader.load((SequenceFileImporter) importer, paths, true, false, true); 228 else 229 { 230 // build groups 231 final Collection<SequenceFileGroup> groups = SequenceFileSticher 232 .groupAllFiles((SequenceFileImporter) importer, paths, isAutoOrderSelected(), null); 233 234 // then load them 235 for (SequenceFileGroup group : groups) 236 { 237 // we don't have series for image grouped loading 238 Loader.load(group, optionPanel.getResolutionLevel(), optionPanel.getXYRegion(), 239 optionPanel.getFullZRange() ? -1 : optionPanel.getZMin(), 240 optionPanel.getFullZRange() ? -1 : optionPanel.getZMax(), 241 optionPanel.getFullTRange() ? -1 : optionPanel.getTMin(), 242 optionPanel.getFullTRange() ? -1 : optionPanel.getTMax(), 243 optionPanel.getChannel(), false, true, true); 244 } 245 } 246 } 247 } 248 else 249 { 250 // single file loading 251 if (importer instanceof FileImporter) 252 { 253 // load selected non image file 254 Loader.load((FileImporter) importer, paths, true); 255 } 256 else 257 { 258 // load selected image file with advanced option 259 Loader.load((SequenceFileImporter) importer, firstPath, optionPanel.getSeries(), 260 optionPanel.getResolutionLevel(), optionPanel.getXYRegion(), 261 optionPanel.getFullZRange() ? -1 : optionPanel.getZMin(), 262 optionPanel.getFullZRange() ? -1 : optionPanel.getZMax(), 263 optionPanel.getFullTRange() ? -1 : optionPanel.getTMin(), 264 optionPanel.getFullTRange() ? -1 : optionPanel.getTMax(), optionPanel.getChannel(), 265 isSeparateSequenceSelected(), true, true); 266 } 267 } 268 } 269 } 270 271 // store interface option 272 preferences.putInt(ID_WIDTH, getWidth()); 273 preferences.putInt(ID_HEIGTH, getHeight()); 274 } 275 276 /** 277 * Display a dialog to select image or resource file(s) and load them.<br> 278 * <br> 279 * To only get selected files from the dialog you must do:<br> 280 * <code> LoaderDialog dialog = new LoaderDialog(false);</code><br> 281 * <code> File[] selectedFiles = dialog.getSelectedFiles()</code><br> 282 * <br> 283 * To directly load selected files just use:<br> 284 * <code>new LoaderDialog(true);</code><br> 285 * or<br> 286 * <code>new LoaderDialog();</code> 287 * 288 * @param defaultPath 289 * default file path (can be null) 290 * @param region 291 * default XY region (can be null) 292 * @param autoLoad 293 * If true the selected file(s) are automatically loaded. 294 */ 295 public LoaderDialog(String defaultPath, Rectangle region, boolean autoLoad) 296 { 297 this(defaultPath, region, -1, autoLoad); 298 } 299 300 /** 301 * Display a dialog to select image or resource file(s) and load them.<br> 302 * <br> 303 * To only get selected files from the dialog you must do:<br> 304 * <code> LoaderDialog dialog = new LoaderDialog(false);</code><br> 305 * <code> File[] selectedFiles = dialog.getSelectedFiles()</code><br> 306 * <br> 307 * To directly load selected files just use:<br> 308 * <code>new LoaderDialog(true);</code><br> 309 * or<br> 310 * <code>new LoaderDialog();</code> 311 * 312 * @param autoLoad 313 * If true the selected file(s) are automatically loaded. 314 */ 315 public LoaderDialog(boolean autoLoad) 316 { 317 this(null, null, autoLoad); 318 } 319 320 /** 321 * Display a dialog to select file(s) and load them. 322 */ 323 public LoaderDialog() 324 { 325 this(null, null, true); 326 } 327 328 protected FileFilter getFileFilter(String description) 329 { 330 final FileFilter[] filters = getChoosableFileFilters(); 331 332 for (FileFilter filter : filters) 333 if (StringUtil.equals(filter.getDescription(), description)) 334 return filter; 335 336 // take first filter by default 337 if (filters.length > 0) 338 return filters[0]; 339 340 return null; 341 } 342 343 protected int getFileFilterIndex() 344 { 345 final FileFilter[] filters = getChoosableFileFilters(); 346 final FileFilter filter = getFileFilter(); 347 348 for (int i = 0; i < filters.length; i++) 349 if (filter == filters[i]) 350 return i; 351 352 return -1; 353 } 354 355 protected boolean isImageFilter() 356 { 357 return getSelectedImporter() instanceof SequenceFileImporter; 358 } 359 360 protected boolean isAllFileFilter() 361 { 362 return getFileFilter() == allFileFilter; 363 } 364 365 protected Object getImporter(int filterIndex) 366 { 367 int ind = 0; 368 369 for (SequenceFileImporter importer : sequenceImporters) 370 { 371 final List<FileFilter> filters = importer.getFileFilters(); 372 final int count = (filters != null) ? filters.size() : 0; 373 374 if (filterIndex < (ind + count)) 375 return importer; 376 377 ind += count; 378 } 379 for (FileImporter importer : fileImporters) 380 { 381 final List<FileFilter> filters = importer.getFileFilters(); 382 final int count = (filters != null) ? filters.size() : 0; 383 384 if (filterIndex < (ind + count)) 385 return importer; 386 387 ind += count; 388 } 389 390 return null; 391 } 392 393 public Object getSelectedImporter() 394 { 395 return getImporter(getFileFilterIndex()); 396 } 397 398 /** 399 * Returns true if user checked the "Separate sequence" option. 400 */ 401 public boolean isSeparateSequenceSelected() 402 { 403 return optionPanel.isSeparateSequenceSelected(); 404 } 405 406 /** 407 * Returns true if user checked the "Auto Ordering" option. 408 */ 409 public boolean isAutoOrderSelected() 410 { 411 return optionPanel.getLoadingType() == LoaderLoadingType.GROUP; 412 } 413 414 /** 415 * Get selected resolution level 416 */ 417 public int getResolutionLevel() 418 { 419 return optionPanel.getResolutionLevel(); 420 } 421 422 /** 423 * Get selected XY region (when region loading is enabled) 424 */ 425 public Rectangle getXYRegion() 426 { 427 return optionPanel.getXYRegion(); 428 } 429 430 /** 431 * Get minimum Z (Z range selection) 432 */ 433 public int getZMin() 434 { 435 return optionPanel.getZMin(); 436 } 437 438 /** 439 * Get maximum Z (Z range selection) 440 */ 441 public int getZMax() 442 { 443 return optionPanel.getZMax(); 444 } 445 446 /** 447 * Get minimum T (T range selection) 448 */ 449 public int getTMin() 450 { 451 return optionPanel.getTMin(); 452 } 453 454 /** 455 * Get maximum T (T range selection) 456 */ 457 public int getTMax() 458 { 459 return optionPanel.getTMax(); 460 } 461 462 /** 463 * Get channel selection (-1 for all) 464 */ 465 public int getChannel() 466 { 467 return optionPanel.getChannel(); 468 } 469 470 /** 471 * Get series selection (-1 for all) 472 */ 473 public int getSeries() 474 { 475 return optionPanel.getSeries(); 476 } 477 478 @Override 479 public void propertyChange(PropertyChangeEvent evt) 480 { 481 final String prop = evt.getPropertyName(); 482 483 // filter change ? 484 if (prop.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)) 485 updateGUI(); 486 // single selection change ? 487 // else if (prop.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) 488 // { 489 // // multiple selection --> ignore this event 490 // if (getSelectedFiles().length > 1) 491 // return; 492 // 493 // final File f = getSelectedFile(); 494 // 495 // // folder or file don't exist ? 496 // if ((f == null) || f.isDirectory() || !f.exists()) 497 // optionPanel.updatePreview(new String[0]); 498 // else 499 // // refresh preview 500 // optionPanel.updatePreview(new String[] {f.getAbsolutePath()}); 501 // 502 // // updateOptionPanel(); 503 // } 504 // multi selection change ? 505 else if (prop.equals(JFileChooser.SELECTED_FILES_CHANGED_PROPERTY)) 506 { 507 final File[] files = getSelectedFiles(); 508 509 // single selection 510 if (files.length < 2) 511 { 512 final File f = getSelectedFile(); 513 514 // folder or file don't exist ? 515 if ((f == null) || f.isDirectory() || !f.exists()) 516 optionPanel.updatePreview(new String[0]); 517 else 518 // refresh preview 519 optionPanel.updatePreview(new String[] {f.getAbsolutePath()}); 520 } 521 else 522 optionPanel.updatePreview(FileUtil.toPaths(files)); 523 } 524 // closing ? --> do some final operation on option panel 525 else if (prop.equals("JFileChooserDialogIsClosingProperty")) 526 optionPanel.closingFromEDT(); 527 // else 528 // updateOptionPanel(); 529 } 530 531 protected void updateGUI() 532 { 533 if (isImageFilter() || isAllFileFilter()) 534 { 535 setDialogTitle("Load image file(s)"); 536 setAccessory(optionPanel); 537 // updateOptionPanel(); 538 revalidate(); 539 } 540 else 541 { 542 setDialogTitle("Load file(s)"); 543 setAccessory(null); 544 revalidate(); 545 } 546 } 547 548 // protected void updateOptionPanel() 549 // { 550 // final int numFile = getSelectedFiles().length; 551 // final boolean multi; 552 // 553 // if (numFile > 1) 554 // multi = true; 555 // else 556 // { 557 // final File file = getSelectedFile(); 558 // multi = (file != null) && file.isDirectory(); 559 // } 560 // 561 // optionPanel.setMultiFile(multi); 562 // } 563}