001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.gui.dialog; 020 021import java.awt.BorderLayout; 022import java.awt.Dimension; 023import java.awt.GridBagConstraints; 024import java.awt.GridBagLayout; 025import java.awt.Insets; 026import java.awt.Rectangle; 027import java.awt.event.ActionEvent; 028import java.awt.event.ActionListener; 029import java.awt.geom.Rectangle2D; 030import java.io.IOException; 031import java.nio.channels.ClosedByInterruptException; 032import java.util.ArrayList; 033import java.util.List; 034import java.util.concurrent.Callable; 035 036import javax.swing.BorderFactory; 037import javax.swing.DefaultComboBoxModel; 038import javax.swing.JComboBox; 039import javax.swing.JLabel; 040import javax.swing.JPanel; 041import javax.swing.JSlider; 042import javax.swing.JToggleButton; 043import javax.swing.border.Border; 044import javax.swing.event.ChangeEvent; 045import javax.swing.event.ChangeListener; 046 047import icy.file.Loader; 048import icy.file.SequenceFileGroupImporter; 049import icy.file.SequenceFileImporter; 050import icy.file.SequenceFileSticher.SequenceFileGroup; 051import icy.gui.component.PopupPanel; 052import icy.gui.component.RangeComponent; 053import icy.gui.component.Region2DComponent; 054import icy.gui.component.SpecialValueSpinner; 055import icy.gui.component.ThumbnailComponent; 056import icy.gui.component.model.SpecialValueSpinnerModel; 057import icy.image.IcyBufferedImage; 058import icy.resource.ResourceUtil; 059import icy.sequence.MetaDataUtil; 060import icy.sequence.SequenceIdImporter; 061import icy.system.IcyExceptionHandler; 062import icy.system.thread.ThreadUtil; 063import icy.type.collection.CollectionUtil; 064import icy.util.OMEUtil; 065import ome.xml.meta.OMEXMLMetadata; 066import plugins.kernel.importer.LociImporterPlugin; 067 068public class LoaderOptionPanel extends JPanel 069{ 070 public enum LoaderLoadingType 071 { 072 GROUP 073 { 074 @Override 075 public String toString() 076 { 077 return "Group files"; 078 } 079 }, 080 GROUP_NO_ORDERING 081 { 082 @Override 083 public String toString() 084 { 085 return "Group files (no ordering)"; 086 } 087 }, 088 NO_GROUP 089 { 090 @Override 091 public String toString() 092 { 093 return "Separate files"; 094 } 095 } 096 } 097 098 private class PreviewSingleUpdate extends Thread 099 { 100 SequenceFileImporter importer; 101 List<SequenceFileImporter> importers; 102 List<String> files; 103 int z; 104 int t; 105 boolean imageRefreshOnly; 106 // boolean softInterrupted; 107 108 PreviewSingleUpdate(SequenceFileImporter importer, List<String> files, int z, int t, boolean imageRefreshOnly) 109 { 110 super("Preview single update"); 111 112 this.importer = importer; 113 this.importers = null; 114 this.files = Loader.cleanNonImageFile(files); 115 this.z = z; 116 this.t = t; 117 this.imageRefreshOnly = imageRefreshOnly; 118 // softInterrupted = false; 119 } 120 121 public List<SequenceFileImporter> getSingleFileImporters() 122 { 123 // get importer and open image 124 final List<SequenceFileImporter> result = Loader.getSequenceFileImporters(files.get(0)); 125 126 // adjust importers setting if needed 127 for (SequenceFileImporter imp : result) 128 { 129 // LOCI importer ? 130 if (imp instanceof LociImporterPlugin) 131 { 132 // separate loading wanted ? --> disable grouping in LOCI importer 133 if (isSeparateSequenceSelected()) 134 ((LociImporterPlugin) imp).setGroupFiles(false); 135 } 136 } 137 138 return result; 139 } 140 141 void getImporters() 142 { 143 // already done ? --> exit 144 if (importer != null) 145 return; 146 147 // importers for single file opening 148 importers = getSingleFileImporters(); 149 150 // want to open a group of file ? --> insert the SequenceFileGroupImporter importer 151 if (isGroupedSequenceSelected() && isMultiFile()) 152 importers.add(0, new SequenceFileGroupImporter()); 153 154 // get default importer 155 importer = importers.get(0); 156 } 157 158 void close() 159 { 160 try 161 { 162 // close previous importer (shouldn't exist here) 163 if (importer != null) 164 importer.close(); 165 } 166 catch (IOException e) 167 { 168 // ignore 169 } 170 171 importer = null; 172 } 173 174 boolean internalOpen(SequenceFileImporter imp) throws ClosedByInterruptException 175 { 176 try 177 { 178 if (imp instanceof SequenceFileGroupImporter) 179 ((SequenceFileGroupImporter) imp).open(files, SequenceIdImporter.FLAG_METADATA_MINIMUM); 180 else 181 imp.open(files.get(0), SequenceIdImporter.FLAG_METADATA_MINIMUM); 182 } 183 catch (ClosedByInterruptException e) 184 { 185 throw e; 186 } 187 catch (Exception e) 188 { 189 try 190 { 191 imp.close(); 192 } 193 catch (Throwable e2) 194 { 195 // ignore 196 } 197 } 198 199 // correctly opened ? --> use this importer 200 return imp.getOpened() != null; 201 } 202 203 boolean open() throws ClosedByInterruptException 204 { 205 // get importers first if not already done 206 getImporters(); 207 208 // already opened ? --> exit 209 if (importer.getOpened() != null) 210 return true; 211 212 // case where we just have the good importer that we need to re-open 213 if (importers == null) 214 return internalOpen(importer); 215 216 // try to open from the given importers 217 for (SequenceFileImporter imp : importers) 218 { 219 // correctly opened ? --> use this importer 220 if (internalOpen(imp)) 221 { 222 importer = imp; 223 return true; 224 } 225 } 226 227 // can't open 228 return false; 229 } 230 231 OMEXMLMetadata getMetaData() throws Exception 232 { 233 if (!open()) 234 throw new Exception("Can't open importer !"); 235 236 return importer.getOMEXMLMetaData(); 237 } 238 239 IcyBufferedImage getThumbnail(int s) throws Exception 240 { 241 if (!open()) 242 throw new Exception("Can't open importer !"); 243 244 return importer.getThumbnail(s); 245 } 246 247 IcyBufferedImage getImage(int s, int res) throws Exception 248 { 249 if (!open()) 250 throw new Exception("Can't open importer !"); 251 252 if (pCh == -1) 253 return importer.getImage(s, res, z, t); 254 255 // specific channel 256 return importer.getImage(s, res, z, t, pCh); 257 } 258 259 public boolean isMultiFile() 260 { 261 try 262 { 263 // return true if we have multiple file selection 264 if (files.size() > 1) 265 return true; 266 267 if (importer instanceof SequenceFileGroupImporter) 268 { 269 final SequenceFileGroup group = ((SequenceFileGroupImporter) importer).getOpenedGroup(); 270 271 if (group != null) 272 return (group.positions.size() > 1); 273 } 274 } 275 catch (Throwable t) 276 { 277 // ignore 278 } 279 280 return false; 281 } 282 283 // PreviewSingleUpdate(SequenceFileImporter importer, String[] files, int z, int t, boolean imageRefreshOnly) 284 // { 285 // this(importer, CollectionUtil.asList(files), z, t, imageRefreshOnly); 286 // } 287 // 288 // PreviewSingleUpdate(SequenceFileImporter importer, int z, int t) 289 // { 290 // this(importer, new String[0], z, t, true); 291 // } 292 // 293 // PreviewSingleUpdate(String[] files) 294 // { 295 // this(null, files, -1, -1, false); 296 // } 297 // 298 // PreviewSingleUpdate(List<String> files) 299 // { 300 // this(null, files, -1, -1, false); 301 // } 302 303 @Override 304 public void run() 305 { 306 // interrupt process 307 if (isInterrupted()) 308 return; 309 310 // get current selected series 311 final int s = getSelectedSeries(); 312 313 // only need to update image 314 if (imageRefreshOnly) 315 { 316 // can't re open importer ? --> nothing to do here 317 if ((importer == null) && (files.size() == 0)) 318 return; 319 320 try 321 { 322 // use last - 1 resolution 323 final int res = Math.max(0, resolutionSlider.getMaximum() - 1); 324 325 try 326 { 327 // can't open ? --> error 328 if (!open()) 329 throw new Exception("Can't open '" + files.get(0) + "' image file.."); 330 331 // interrupted ? --> stop here 332 if (isInterrupted()) 333 return; 334 335 // not defined --> use first 336 if (z == -1) 337 z = 0; 338 // not defined --> use first 339 if (t == -1) 340 t = 0; 341 342 // default position --> use thumbnail 343 if ((z == 0) && (t == 0) && (pCh == -1)) 344 preview.setImage(getThumbnail(s)); 345 // specific image 346 else 347 preview.setImage(getImage(s, res)); 348 } 349 finally 350 { 351 // just close internals importers 352 if (importer instanceof SequenceFileGroupImporter) 353 ((SequenceFileGroupImporter) importer).closeInternalsImporters(); 354 } 355 } 356 catch (ClosedByInterruptException e) 357 { 358 // can't use importer anymore 359 close(); 360 } 361 catch (InterruptedException e2) 362 { 363 // can't use importer anymore 364 close(); 365 } 366 catch (Throwable e) 367 { 368 // can't use importer anymore 369 if (e.getCause() instanceof ClosedByInterruptException) 370 close(); 371 372 // no more update ? --> show that an error happened 373 if (!previewUpdater.getNeedUpdate()) 374 preview.setImage(ResourceUtil.ICON_DELETE); 375 } 376 377 // image updated 378 return; 379 } 380 381 try 382 { 383 metadata = null; 384 385 // no files ? 386 if (files.size() == 0) 387 { 388 preview.setImage(null); 389 preview.setInfos(""); 390 metadata = OMEUtil.createOMEXMLMetadata(); 391 392 // use Callable as we can get interrupted here... 393 ThreadUtil.invokeNow(new Callable<Boolean>() 394 { 395 @Override 396 public Boolean call() throws Exception 397 { 398 // disable panel while we are loading metadata 399 disablePanel(); 400 401 return Boolean.TRUE; 402 } 403 }); 404 405 // nothing more to do 406 return; 407 } 408 409 // loading... 410 preview.setImage(ResourceUtil.ICON_WAIT); 411 preview.setInfos("loading..."); 412 413 // use Callable as we can get interrupted here... 414 ThreadUtil.invokeNow(new Callable<Boolean>() 415 { 416 417 @Override 418 public Boolean call() throws Exception 419 { 420 // disable panel while we are loading metadata 421 disablePanel(); 422 423 return Boolean.TRUE; 424 } 425 }); 426 427 // close previous importer (shouldn't exist here) 428 close(); 429 430 // open file(s)... 431 if (!open()) 432 throw new Exception("Can't open '" + files.get(0) + "' image file.."); 433 434 try 435 { 436 // interrupted ? --> stop here 437 if (isInterrupted()) 438 return; 439 440 metadata = getMetaData(); 441 442 // update it as soon as possible (use Callable as we can get interrupted here...) 443 ThreadUtil.invokeNow(new Callable<Boolean>() 444 { 445 446 @Override 447 public Boolean call() throws Exception 448 { 449 // update panel 450 updatePanel(); 451 452 return Boolean.TRUE; 453 } 454 }); 455 456 // now the different "metadata" fields are up to date 457 metadataFieldsOk = true; 458 459 // initial preview --> update default range and channel positions 460 pZMin = getZMin(); 461 pZMax = getZMax(); 462 pTMin = getTMin(); 463 pTMax = getTMax(); 464 pCh = getChannel(); 465 466 final int sizeC = MetaDataUtil.getSizeC(metadata, s); 467 468 // load metadata first 469 preview.setInfos(MetaDataUtil.getSizeX(metadata, s) + " x " + MetaDataUtil.getSizeY(metadata, s) 470 + " - " + MetaDataUtil.getSizeZ(metadata, s) + "Z x " + MetaDataUtil.getSizeT(metadata, s) 471 + "T - " + sizeC + " ch (" + MetaDataUtil.getDataType(metadata, s) + ")"); 472 473 // interrupted ? --> stop here 474 if (isInterrupted()) 475 return; 476 477 // initial preview --> use thumbnail 478 preview.setImage(getThumbnail(s)); 479 } 480 finally 481 { 482 // just close internals importers 483 if (importer instanceof SequenceFileGroupImporter) 484 ((SequenceFileGroupImporter) importer).closeInternalsImporters(); 485 } 486 } 487 catch (ClosedByInterruptException e) 488 { 489 // can't use importer anymore 490 close(); 491 } 492 catch (InterruptedException t) 493 { 494 // can't use importer anymore 495 close(); 496 } 497 catch (Throwable t1) 498 { 499 // System.out.println("Preview: can't load all image information."); 500 // IcyExceptionHandler.showErrorMessage(t1, false); 501 502 // no more update ? --> show that an error happened 503 if (!previewUpdater.getNeedUpdate()) 504 { 505 // fatal error --> failed image 506 preview.setImage(ResourceUtil.ICON_DELETE); 507 508 // cannot even read metadata 509 if (!metadataFieldsOk) 510 { 511 preview.setInfos("Cannot read file"); 512 513 try 514 { 515 // use Callable as we can get interrupted here... 516 ThreadUtil.invokeNow(new Callable<Boolean>() 517 { 518 519 @Override 520 public Boolean call() throws Exception 521 { 522 // update panel 523 updatePanel(); 524 525 return Boolean.TRUE; 526 } 527 }); 528 } 529 catch (Throwable t2) 530 { 531 // probably interrupted... 532 533 } 534 } 535 } 536 } 537 } 538 539 // boolean isSoftInterrupted() 540 // { 541 // return softInterrupted; 542 // } 543 // 544 // void softInterrupt() 545 // { 546 // softInterrupted = true; 547 // } 548 } 549 550 private class PreviewUpdater extends Thread 551 { 552 SequenceFileImporter newImporter; 553 List<String> newFiles; 554 int newZ; 555 int newT; 556 boolean newImageRefreshOnly; 557 558 boolean needUpdate; 559 560 PreviewSingleUpdate singleUpdater; 561 562 PreviewUpdater() 563 { 564 super("Preview updater"); 565 566 singleUpdater = null; 567 needUpdate = false; 568 } 569 570 public boolean getNeedUpdate() 571 { 572 return needUpdate; 573 } 574 575 public boolean isUpdating() 576 { 577 return getNeedUpdate() || ((singleUpdater != null) && singleUpdater.isAlive()); 578 } 579 580 public boolean isMultiFile() 581 { 582 if (singleUpdater == null) 583 return false; 584 585 return singleUpdater.isMultiFile(); 586 } 587 588 /** 589 * previous preview canceled ? 590 */ 591 public boolean isPreviewCanceled() 592 { 593 if (singleUpdater == null) 594 return true; 595 596 return !singleUpdater.isAlive(); 597 } 598 599 /** 600 * Cancel preview refresh 601 */ 602 public void cancelPreview() 603 { 604 // interrupt (soft interrupt to not close IO channel) current preview update 605 if (singleUpdater != null) 606 singleUpdater.interrupt(); 607 } 608 609 /** 610 * Asynchronous image preview refresh only.<br> 611 * ({@link #updatePreview(String)} should have be called once before to give the fileId) 612 */ 613 protected synchronized void updatePreview(int z, int t) 614 { 615 // nothing to do 616 if (singleUpdater == null) 617 return; 618 619 // interrupt previous preview refresh 620 cancelPreview(); 621 622 // prepare params 623 newImporter = singleUpdater.importer; 624 newFiles = singleUpdater.files; 625 // use previous value 626 if (z == -1) 627 newZ = singleUpdater.z; 628 else 629 newZ = z; 630 // use previous value 631 if (t == -1) 632 newT = singleUpdater.t; 633 else 634 newT = t; 635 newImageRefreshOnly = true; 636 637 // request preview update 638 needUpdate = true; 639 } 640 641 /** 642 * Asynchronous preview refresh (complete preview refresh) 643 */ 644 public synchronized void updatePreview() 645 { 646 updatePreview(singleUpdater.files, series); 647 } 648 649 /** 650 * Asynchronous preview refresh.<br> 651 * ({@link #updatePreview(List, int)} should have be called once before to give the fileId) 652 */ 653 public synchronized void updatePreview(int s) 654 { 655 updatePreview(singleUpdater.files, s); 656 } 657 658 /** 659 * Asynchronous preview refresh 660 */ 661 public synchronized void updatePreview(String[] files, int s) 662 { 663 // interrupt previous preview refresh 664 cancelPreview(); 665 666 // reset metadata and series index 667 metadata = null; 668 metadataFieldsOk = false; 669 series = s; 670 671 // prepare params 672 newImporter = null; 673 newFiles = CollectionUtil.asList(files); 674 newZ = -1; 675 newT = -1; 676 newImageRefreshOnly = false; 677 678 // request preview update 679 needUpdate = true; 680 } 681 682 /** 683 * Asynchronous preview refresh 684 */ 685 public synchronized void updatePreview(List<String> files, int s) 686 { 687 // interrupt previous preview refresh 688 cancelPreview(); 689 690 // reset metadata and series index 691 metadata = null; 692 metadataFieldsOk = false; 693 series = s; 694 695 // prepare params 696 newImporter = null; 697 newFiles = files; 698 newZ = -1; 699 newT = -1; 700 newImageRefreshOnly = false; 701 702 // request preview update 703 needUpdate = true; 704 } 705 706 // /** 707 // * Asynchronous preview refresh 708 // */ 709 // public synchronized void updatePreview(String[] files) 710 // { 711 // updatePreview(files, -1); 712 // } 713 714 /** 715 * We are closing the Open Dialog.<br> 716 * Don't forget to call this method otherwise the updater thread will remain active !!<br> 717 * Ensure metadata are correctly loaded (it's important that this method is called from EDT) 718 */ 719 public synchronized void close() 720 { 721 // interrupt preview 722 cancelPreview(); 723 724 if (singleUpdater != null) 725 { 726 // need update metadata fields 727 if (!metadataFieldsOk) 728 { 729 try 730 { 731 // open file(s) if needed... 732 if (!singleUpdater.open()) 733 return; 734 735 try 736 { 737 metadata = singleUpdater.importer.getOMEXMLMetaData(); 738 739 // update panel (we are on EDT) 740 updatePanel(); 741 } 742 finally 743 { 744 singleUpdater.close(); 745 } 746 } 747 catch (Throwable t) 748 { 749 // we tried... 750 } 751 } 752 } 753 754 // finally interrupt the updater thread 755 interrupt(); 756 } 757 758 @Override 759 public void run() 760 { 761 try 762 { 763 // interrupt process 764 while (!isInterrupted()) 765 { 766 // sleep a bit 767 Thread.sleep(10); 768 769 // need to be synchronized 770 synchronized (this) 771 { 772 // previous preview done ? 773 if (isPreviewCanceled()) 774 { 775 // need preview update ? 776 if (needUpdate) 777 { 778 // create new single updater and start it 779 singleUpdater = new PreviewSingleUpdate(newImporter, newFiles, newZ, newT, 780 newImageRefreshOnly); 781 singleUpdater.start(); 782 783 // done 784 needUpdate = false; 785 } 786 } 787 } 788 } 789 } 790 catch (InterruptedException t) 791 { 792 // no need to do more here... 793 } 794 catch (Throwable t) 795 { 796 System.out.println("Preview updater interrupted !"); 797 IcyExceptionHandler.showErrorMessage(t, false); 798 } 799 } 800 } 801 802 /** 803 * 804 */ 805 private static final long serialVersionUID = 4180367632912879286L; 806 807 /** 808 * GUI 809 */ 810 protected ThumbnailComponent preview; 811 protected JPanel optionsPanel; 812 protected PopupPanel popupPanel; 813 protected JComboBox loadingTypeCombo; 814 protected JLabel loadInSeparatedLabel; 815 protected JSlider resolutionSlider; 816 protected JLabel resolutionLevelLabel; 817 protected JLabel zRangeLabel; 818 protected JLabel tRangeLabel; 819 protected JLabel channelLabel; 820 protected RangeComponent zRangeComp; 821 protected RangeComponent tRangeComp; 822 protected SpecialValueSpinner channelSpinner; 823 protected JLabel resolutionFixLabel; 824 protected JToggleButton xyRegionLoadingToggle; 825 protected JLabel seriesLabel; 826 protected SpecialValueSpinner seriesSpinner; 827 protected Region2DComponent xyRegionComp; 828 829 // internals 830 protected boolean metadataFieldsOk; 831 protected PreviewUpdater previewUpdater; 832 protected OMEXMLMetadata metadata; 833 protected int series; 834 protected int pZMin; 835 protected int pZMax; 836 protected int pTMin; 837 protected int pTMax; 838 protected int pCh; 839 // protected boolean multiFile; 840 protected boolean updatingPanel; 841 842 /** 843 * Create the panel. 844 */ 845 public LoaderOptionPanel(LoaderLoadingType loadType) 846 { 847 super(); 848 849 metadataFieldsOk = false; 850 metadata = null; 851 series = -1; 852 pZMin = -1; 853 pZMax = -1; 854 pTMin = -1; 855 pTMax = -1; 856 pCh = -1; 857 updatingPanel = false; 858 859 initialize(loadType); 860 861 // need to be done *before* updatePanel 862 previewUpdater = new PreviewUpdater(); 863 previewUpdater.start(); 864 865 updatePanel(); 866 } 867 868 private void initialize(LoaderLoadingType loadType) 869 { 870 setBorder(BorderFactory.createTitledBorder((Border) null)); 871 setLayout(new BorderLayout()); 872 873 preview = new ThumbnailComponent(false); 874 preview.setMinimumSize(new Dimension(200, 160)); 875 preview.setPreferredSize(new Dimension(240, 200)); 876 preview.setShortDisplay(true); 877 878 add(preview, BorderLayout.CENTER); 879 880 optionsPanel = new JPanel(); 881 popupPanel = new PopupPanel("Advanced options", optionsPanel); 882 popupPanel.setExpanded(true); 883 add(popupPanel, BorderLayout.SOUTH); 884 885 GridBagLayout gbl_optionsPanel = new GridBagLayout(); 886 gbl_optionsPanel.columnWidths = new int[] {0, 100, 0, 0, 0}; 887 gbl_optionsPanel.rowHeights = new int[] {0, 0, 0, 0, 0, 0, 0}; 888 gbl_optionsPanel.columnWeights = new double[] {0.0, 1.0, 1.0, 1.0, Double.MIN_VALUE}; 889 gbl_optionsPanel.rowWeights = new double[] {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; 890 optionsPanel.setLayout(gbl_optionsPanel); 891 GridBagConstraints gbc_loadInSeparatedLabel = new GridBagConstraints(); 892 gbc_loadInSeparatedLabel.anchor = GridBagConstraints.WEST; 893 gbc_loadInSeparatedLabel.insets = new Insets(0, 0, 5, 5); 894 gbc_loadInSeparatedLabel.gridx = 0; 895 gbc_loadInSeparatedLabel.gridy = 0; 896 loadInSeparatedLabel = new JLabel("Load type"); 897 loadInSeparatedLabel.setToolTipText( 898 "Define if we try to group files / series or not (and eventually automatic set Z, T, C ordering from file name)"); 899 optionsPanel.add(loadInSeparatedLabel, gbc_loadInSeparatedLabel); 900 901 loadingTypeCombo = new JComboBox(); 902 loadingTypeCombo.setToolTipText( 903 "Define if we try to group files or not (and eventually automatic set Z, T, C ordering from file name)"); 904 loadingTypeCombo.setModel(new DefaultComboBoxModel(LoaderLoadingType.values())); 905 loadingTypeCombo.setSelectedIndex(loadType.ordinal()); 906 loadingTypeCombo.addActionListener(new ActionListener() 907 { 908 @Override 909 public void actionPerformed(ActionEvent e) 910 { 911 loadingTypeChanged(); 912 } 913 }); 914 GridBagConstraints gbc_loadingTypeCombo = new GridBagConstraints(); 915 gbc_loadingTypeCombo.fill = GridBagConstraints.HORIZONTAL; 916 gbc_loadingTypeCombo.gridwidth = 3; 917 gbc_loadingTypeCombo.insets = new Insets(0, 0, 5, 0); 918 gbc_loadingTypeCombo.gridx = 1; 919 gbc_loadingTypeCombo.gridy = 0; 920 optionsPanel.add(loadingTypeCombo, gbc_loadingTypeCombo); 921 922 seriesLabel = new JLabel("Series"); 923 seriesLabel.setToolTipText("Series to load (only for multi serie image)"); 924 GridBagConstraints gbc_seriesLabel = new GridBagConstraints(); 925 gbc_seriesLabel.anchor = GridBagConstraints.WEST; 926 gbc_seriesLabel.insets = new Insets(0, 0, 5, 5); 927 gbc_seriesLabel.gridx = 0; 928 gbc_seriesLabel.gridy = 1; 929 optionsPanel.add(seriesLabel, gbc_seriesLabel); 930 931 seriesSpinner = new SpecialValueSpinner(new SpecialValueSpinnerModel(-1, -1, 0, 1, -1, "ALL")); 932 seriesSpinner.setPreferredSize(new Dimension(50, 22)); 933 seriesSpinner.addChangeListener(new ChangeListener() 934 { 935 @Override 936 public void stateChanged(ChangeEvent e) 937 { 938 seriesChanged(); 939 } 940 }); 941 seriesSpinner.setToolTipText("Series to load (only for multi serie image)"); 942 GridBagConstraints gbc_seriesSpinner = new GridBagConstraints(); 943 gbc_seriesSpinner.insets = new Insets(0, 0, 5, 5); 944 gbc_seriesSpinner.anchor = GridBagConstraints.WEST; 945 gbc_seriesSpinner.gridx = 1; 946 gbc_seriesSpinner.gridy = 1; 947 optionsPanel.add(seriesSpinner, gbc_seriesSpinner); 948 949 channelLabel = new JLabel("Channel"); 950 channelLabel.setToolTipText("Channel to load"); 951 GridBagConstraints gbc_channelLabel = new GridBagConstraints(); 952 gbc_channelLabel.anchor = GridBagConstraints.EAST; 953 gbc_channelLabel.insets = new Insets(0, 0, 5, 5); 954 gbc_channelLabel.gridx = 2; 955 gbc_channelLabel.gridy = 1; 956 optionsPanel.add(channelLabel, gbc_channelLabel); 957 958 channelSpinner = new SpecialValueSpinner(new SpecialValueSpinnerModel(-1, -1, 0, 1, -1, "ALL")); 959 channelSpinner.setPreferredSize(new Dimension(50, 22)); 960 channelSpinner.addChangeListener(new ChangeListener() 961 { 962 @Override 963 public void stateChanged(ChangeEvent e) 964 { 965 rangeChanged(); 966 } 967 }); 968 channelSpinner.setToolTipText("Channel to load"); 969 GridBagConstraints gbc_channelSpinner = new GridBagConstraints(); 970 gbc_channelSpinner.anchor = GridBagConstraints.EAST; 971 gbc_channelSpinner.insets = new Insets(0, 0, 5, 0); 972 gbc_channelSpinner.gridx = 3; 973 gbc_channelSpinner.gridy = 1; 974 optionsPanel.add(channelSpinner, gbc_channelSpinner); 975 976 resolutionFixLabel = new JLabel("Resolution"); 977 resolutionFixLabel.setToolTipText("Select resolution level to open"); 978 GridBagConstraints gbc_resolutionFixLabel = new GridBagConstraints(); 979 gbc_resolutionFixLabel.anchor = GridBagConstraints.WEST; 980 gbc_resolutionFixLabel.insets = new Insets(0, 0, 5, 5); 981 gbc_resolutionFixLabel.gridx = 0; 982 gbc_resolutionFixLabel.gridy = 2; 983 optionsPanel.add(resolutionFixLabel, gbc_resolutionFixLabel); 984 985 resolutionSlider = new JSlider(); 986 resolutionSlider.setSnapToTicks(true); 987 resolutionSlider.setMinimumSize(new Dimension(80, 22)); 988 resolutionSlider.setMaximumSize(new Dimension(100, 22)); 989 resolutionSlider.setPreferredSize(new Dimension(100, 22)); 990 resolutionSlider.setToolTipText("Select resolution level to open"); 991 resolutionSlider.setValue(0); 992 resolutionSlider.setMaximum(10); 993 resolutionSlider.setFocusable(false); 994 resolutionSlider.addChangeListener(new ChangeListener() 995 { 996 @Override 997 public void stateChanged(ChangeEvent e) 998 { 999 updateFinaleResolution(); 1000 } 1001 }); 1002 1003 resolutionLevelLabel = new JLabel(""); 1004 GridBagConstraints gbc_resolutionLevelLabel = new GridBagConstraints(); 1005 gbc_resolutionLevelLabel.anchor = GridBagConstraints.WEST; 1006 gbc_resolutionLevelLabel.insets = new Insets(0, 0, 5, 5); 1007 gbc_resolutionLevelLabel.gridx = 1; 1008 gbc_resolutionLevelLabel.gridy = 2; 1009 optionsPanel.add(resolutionLevelLabel, gbc_resolutionLevelLabel); 1010 GridBagConstraints gbc_resolutionSlider = new GridBagConstraints(); 1011 gbc_resolutionSlider.fill = GridBagConstraints.BOTH; 1012 gbc_resolutionSlider.gridwidth = 2; 1013 gbc_resolutionSlider.insets = new Insets(0, 0, 5, 0); 1014 gbc_resolutionSlider.gridx = 2; 1015 gbc_resolutionSlider.gridy = 2; 1016 optionsPanel.add(resolutionSlider, gbc_resolutionSlider); 1017 1018 xyRegionLoadingToggle = new JToggleButton("XY region"); 1019 xyRegionLoadingToggle.setFocusPainted(false); 1020 xyRegionLoadingToggle.setIconTextGap(0); 1021 xyRegionLoadingToggle.setMargin(new Insets(2, 4, 2, 4)); 1022 xyRegionLoadingToggle 1023 .setToolTipText("Enable region loading (X,Y)-(W,H) in original resolution coordinates (pixel)"); 1024 xyRegionLoadingToggle.addActionListener(new ActionListener() 1025 { 1026 @Override 1027 public void actionPerformed(ActionEvent e) 1028 { 1029 regionLoadingToggleChanged(); 1030 } 1031 }); 1032 GridBagConstraints gbc_xyRegionLoadingCheck = new GridBagConstraints(); 1033 gbc_xyRegionLoadingCheck.fill = GridBagConstraints.BOTH; 1034 gbc_xyRegionLoadingCheck.insets = new Insets(0, 0, 5, 5); 1035 gbc_xyRegionLoadingCheck.gridx = 0; 1036 gbc_xyRegionLoadingCheck.gridy = 3; 1037 optionsPanel.add(xyRegionLoadingToggle, gbc_xyRegionLoadingCheck); 1038 1039 xyRegionComp = new Region2DComponent(); 1040 xyRegionComp.setMaximumSize(new Dimension(160, 24)); 1041 xyRegionComp.setInteger(true); 1042 xyRegionComp.setToolTipText("Rectangular region to load (X,Y,W,H) in original resolution coordinates"); 1043 GridBagConstraints gbc_xyRegionComp = new GridBagConstraints(); 1044 gbc_xyRegionComp.fill = GridBagConstraints.HORIZONTAL; 1045 gbc_xyRegionComp.gridwidth = 3; 1046 gbc_xyRegionComp.insets = new Insets(0, 0, 5, 0); 1047 gbc_xyRegionComp.gridx = 1; 1048 gbc_xyRegionComp.gridy = 3; 1049 optionsPanel.add(xyRegionComp, gbc_xyRegionComp); 1050 1051 zRangeLabel = new JLabel("Z range "); 1052 zRangeLabel.setToolTipText("Z interval to load"); 1053 GridBagConstraints gbc_zRangeLabel = new GridBagConstraints(); 1054 gbc_zRangeLabel.anchor = GridBagConstraints.WEST; 1055 gbc_zRangeLabel.insets = new Insets(0, 0, 5, 5); 1056 gbc_zRangeLabel.gridx = 0; 1057 gbc_zRangeLabel.gridy = 4; 1058 optionsPanel.add(zRangeLabel, gbc_zRangeLabel); 1059 1060 zRangeComp = new RangeComponent(); 1061 zRangeComp.addChangeListener(new ChangeListener() 1062 { 1063 @Override 1064 public void stateChanged(ChangeEvent e) 1065 { 1066 rangeChanged(); 1067 } 1068 }); 1069 zRangeComp.setToolTipText("Z interval to load"); 1070 zRangeComp.setMinimumSize(new Dimension(130, 22)); 1071 zRangeComp.setMaximumSize(new Dimension(180, 22)); 1072 zRangeComp.getHighSpinner().setPreferredSize(new Dimension(50, 20)); 1073 zRangeComp.getHighSpinner().setMaximumSize(new Dimension(50, 20)); 1074 zRangeComp.getLowSpinner().setMaximumSize(new Dimension(50, 20)); 1075 zRangeComp.getLowSpinner().setPreferredSize(new Dimension(50, 20)); 1076 zRangeComp.setPreferredSize(new Dimension(180, 22)); 1077 zRangeComp.getSlider().setPreferredSize(new Dimension(70, 22)); 1078 zRangeComp.setSliderVisible(true); 1079 GridBagConstraints gbc_zRangeComp = new GridBagConstraints(); 1080 gbc_zRangeComp.gridwidth = 3; 1081 gbc_zRangeComp.insets = new Insets(0, 0, 5, 0); 1082 gbc_zRangeComp.fill = GridBagConstraints.HORIZONTAL; 1083 gbc_zRangeComp.gridx = 1; 1084 gbc_zRangeComp.gridy = 4; 1085 optionsPanel.add(zRangeComp, gbc_zRangeComp); 1086 1087 tRangeLabel = new JLabel("T range "); 1088 tRangeLabel.setToolTipText("T interval to load"); 1089 GridBagConstraints gbc_tRangeLabel = new GridBagConstraints(); 1090 gbc_tRangeLabel.anchor = GridBagConstraints.WEST; 1091 gbc_tRangeLabel.insets = new Insets(0, 0, 0, 5); 1092 gbc_tRangeLabel.gridx = 0; 1093 gbc_tRangeLabel.gridy = 5; 1094 optionsPanel.add(tRangeLabel, gbc_tRangeLabel); 1095 1096 tRangeComp = new RangeComponent(); 1097 tRangeComp.addChangeListener(new ChangeListener() 1098 { 1099 @Override 1100 public void stateChanged(ChangeEvent e) 1101 { 1102 rangeChanged(); 1103 } 1104 }); 1105 tRangeComp.setToolTipText("T interval to load"); 1106 tRangeComp.setMinimumSize(new Dimension(130, 22)); 1107 tRangeComp.setMaximumSize(new Dimension(180, 22)); 1108 tRangeComp.getLowSpinner().setPreferredSize(new Dimension(50, 20)); 1109 tRangeComp.getHighSpinner().setPreferredSize(new Dimension(50, 20)); 1110 tRangeComp.getHighSpinner().setMaximumSize(new Dimension(50, 20)); 1111 tRangeComp.getLowSpinner().setMaximumSize(new Dimension(50, 20)); 1112 tRangeComp.setPreferredSize(new Dimension(180, 22)); 1113 tRangeComp.getSlider().setPreferredSize(new Dimension(70, 22)); 1114 tRangeComp.setSliderVisible(true); 1115 GridBagConstraints gbc_tRangeComp = new GridBagConstraints(); 1116 gbc_tRangeComp.gridwidth = 3; 1117 gbc_tRangeComp.fill = GridBagConstraints.HORIZONTAL; 1118 gbc_tRangeComp.gridx = 1; 1119 gbc_tRangeComp.gridy = 5; 1120 optionsPanel.add(tRangeComp, gbc_tRangeComp); 1121 } 1122 1123 protected void updatePreviewOnChange() 1124 { 1125 if (updatingPanel) 1126 return; 1127 1128 int v; 1129 int z = -1; 1130 int t = -1; 1131 boolean changed = false; 1132 1133 // detect change on z, t, c position in preview 1134 v = getZMin(); 1135 if (pZMin != v) 1136 { 1137 z = v; 1138 pZMin = v; 1139 changed = true; 1140 } 1141 v = getZMax(); 1142 if (pZMax != v) 1143 { 1144 z = v; 1145 pZMax = v; 1146 changed = true; 1147 } 1148 1149 v = getTMin(); 1150 if (pTMin != v) 1151 { 1152 t = v; 1153 pTMin = v; 1154 changed = true; 1155 } 1156 v = getTMax(); 1157 if (pTMax != v) 1158 { 1159 t = v; 1160 pTMax = v; 1161 changed = true; 1162 } 1163 1164 v = getChannel(); 1165 if (pCh != v) 1166 { 1167 pCh = v; 1168 changed = true; 1169 } 1170 1171 // changed ? --> update preview... 1172 if (changed) 1173 updatePreview(z, t); 1174 } 1175 1176 protected void rangeChanged() 1177 { 1178 updatePreviewOnChange(); 1179 } 1180 1181 protected void seriesChanged() 1182 { 1183 // update preview series index 1184 previewUpdater.updatePreview(((Integer) seriesSpinner.getValue()).intValue()); 1185 } 1186 1187 void updateLoadingType() 1188 { 1189 final List<String> files = getFiles(); 1190 1191 loadingTypeCombo.setEnabled((files != null) && !files.isEmpty()); 1192 // loadingTypeCombo.setEnabled(metadata != null); 1193 } 1194 1195 void updateXYRegion() 1196 { 1197 if (metadata != null) 1198 { 1199 final Rectangle2D r = xyRegionComp.getRegion(); 1200 final int s = getSelectedSeries(); 1201 final int sizeX = MetaDataUtil.getSizeX(metadata, s); 1202 final int sizeY = MetaDataUtil.getSizeY(metadata, s); 1203 1204 xyRegionLoadingToggle.setEnabled(canUseAdvancedSetting()); 1205 xyRegionComp.setEnabled(canUseAdvancedSetting() && xyRegionLoadingToggle.isSelected()); 1206 // re-init region if out of bounds 1207 if ((r.getMaxX() > sizeX) || (r.getMaxY() > sizeY)) 1208 xyRegionComp.setRegion(0, 0, sizeX, sizeY); 1209 } 1210 else 1211 { 1212 xyRegionComp.setEnabled(false); 1213 xyRegionLoadingToggle.setEnabled(false); 1214 } 1215 } 1216 1217 void updateZRange() 1218 { 1219 if (metadata != null) 1220 { 1221 final int s = getSelectedSeries(); 1222 final int sizeZ = Math.max(MetaDataUtil.getSizeZ(metadata, s), 1); 1223 1224 zRangeComp.setMinMaxStep(0d, sizeZ - 1d, 1d); 1225 zRangeComp.setLowHigh(0d, sizeZ - 1d); 1226 zRangeComp.setEnabled(canUseAdvancedSetting() && (sizeZ > 1)); 1227 } 1228 else 1229 { 1230 zRangeComp.setMinMaxStep(0d, 0d, 1d); 1231 zRangeComp.setEnabled(false); 1232 } 1233 } 1234 1235 void updateTRange() 1236 { 1237 if (metadata != null) 1238 { 1239 final int s = getSelectedSeries(); 1240 final int sizeT = Math.max(MetaDataUtil.getSizeT(metadata, s), 1); 1241 1242 tRangeComp.setMinMaxStep(0d, sizeT - 1d, 1d); 1243 tRangeComp.setLowHigh(0d, sizeT - 1d); 1244 tRangeComp.setEnabled(canUseAdvancedSetting() && (sizeT > 1)); 1245 } 1246 else 1247 { 1248 tRangeComp.setMinMaxStep(0d, 0d, 1d); 1249 tRangeComp.setEnabled(false); 1250 } 1251 } 1252 1253 void updateChannelRange() 1254 { 1255 if (metadata != null) 1256 { 1257 final int s = getSelectedSeries(); 1258 final int sizeC = Math.max(MetaDataUtil.getSizeC(metadata, s), 1); 1259 1260 channelSpinner.setModel(new SpecialValueSpinnerModel(-1, -1, sizeC - 1, 1, -1, "ALL")); 1261 channelSpinner.setEnabled(canUseAdvancedSetting() && (sizeC > 1)); 1262 } 1263 else 1264 { 1265 channelSpinner.setModel(new SpecialValueSpinnerModel(-1, -1, 0, 1, -1, "ALL")); 1266 channelSpinner.setEnabled(false); 1267 } 1268 } 1269 1270 void updateSeriesRange() 1271 { 1272 if (metadata != null) 1273 { 1274 final int numSeries = Math.max(MetaDataUtil.getNumSeries(metadata), 1); 1275 1276 seriesSpinner.setModel(new SpecialValueSpinnerModel(getSeries(), -1, numSeries - 1, 1, -1, "ALL")); 1277 seriesSpinner.setEnabled(canUseAdvancedSetting() && (numSeries > 1)); 1278 } 1279 else 1280 { 1281 seriesSpinner.setModel(new SpecialValueSpinnerModel(-1, -1, 0, 1, -1, "ALL")); 1282 seriesSpinner.setEnabled(false); 1283 } 1284 } 1285 1286 void updateResolutionSlider() 1287 { 1288 // min sub resolution to open (full resolution by default) 1289 int minRes = 0; 1290 // max sub resolution to open 1291 int maxRes = 0; 1292 1293 if (metadata != null) 1294 { 1295 final int s = getSelectedSeries(); 1296 long sizeXY; 1297 1298 // // size of XY plane 1299 // sizeXY = (long) MetaDataUtil.getSizeX(metadata, s) * (long) MetaDataUtil.getSizeY(metadata, s); 1300 // 1301 // // we can't handle that plane size 1302 // while (sizeXY > Integer.MAX_VALUE) 1303 // { 1304 // // reduce resolution until XY plane size is acceptable 1305 // minRes++; 1306 // sizeXY /= 4; 1307 // } 1308 1309 // size of XY plane 1310 sizeXY = (long) MetaDataUtil.getSizeX(metadata, s) * (long) MetaDataUtil.getSizeY(metadata, s); 1311 1312 // no need to get lower than 128x128 1313 while (sizeXY > 16384) 1314 { 1315 // increase max sub resolution until XY plane is too low 1316 maxRes++; 1317 sizeXY /= 4; 1318 } 1319 } 1320 1321 // apply 1322 resolutionSlider.setMinimum(minRes); 1323 resolutionSlider.setMaximum(maxRes); 1324 resolutionSlider.setValue(minRes); 1325 1326 // no need to enable it 1327 resolutionSlider.setEnabled(canUseAdvancedSetting() && (maxRes > 0)); 1328 1329 updateFinaleResolution(); 1330 } 1331 1332 void updateFinaleResolution() 1333 { 1334 if (metadata != null) 1335 { 1336 final int res = resolutionSlider.getValue(); 1337 final int s = getSelectedSeries(); 1338 final int baseX = MetaDataUtil.getSizeX(metadata, s); 1339 final int baseY = MetaDataUtil.getSizeY(metadata, s); 1340 final double diviser = Math.pow(2d, res); 1341 1342 resolutionLevelLabel.setText(res + " (" + Integer.toString((int) (baseX / diviser)) + " x " 1343 + Integer.toString((int) (baseY / diviser)) + ")"); 1344 } 1345 else 1346 resolutionLevelLabel.setText(""); 1347 } 1348 1349 void disablePanel() 1350 { 1351 loadingTypeCombo.setEnabled(false); 1352 channelSpinner.setEnabled(false); 1353 seriesSpinner.setEnabled(false); 1354 resolutionLevelLabel.setText(""); 1355 resolutionSlider.setEnabled(false); 1356 xyRegionLoadingToggle.setEnabled(false); 1357 xyRegionComp.setEnabled(false); 1358 tRangeComp.setEnabled(false); 1359 zRangeComp.setEnabled(false); 1360 } 1361 1362 void updatePanel() 1363 { 1364 updatingPanel = true; 1365 try 1366 { 1367 updateLoadingType(); 1368 updateResolutionSlider(); 1369 updateXYRegion(); 1370 updateTRange(); 1371 updateZRange(); 1372 updateChannelRange(); 1373 updateSeriesRange(); 1374 } 1375 finally 1376 { 1377 updatingPanel = false; 1378 } 1379 } 1380 1381 void loadingTypeChanged() 1382 { 1383 updatePreview(-1); 1384 } 1385 1386 void regionLoadingToggleChanged() 1387 { 1388 xyRegionComp.setEnabled(xyRegionLoadingToggle.isEnabled() && xyRegionLoadingToggle.isSelected()); 1389 } 1390 1391 public List<String> getFiles() 1392 { 1393 if (previewUpdater != null) 1394 return previewUpdater.newFiles; 1395 1396 return new ArrayList<String>(); 1397 } 1398 1399 public boolean getOptionsVisible() 1400 { 1401 return popupPanel.isExpanded(); 1402 } 1403 1404 public void setOptionsVisible(boolean value) 1405 { 1406 popupPanel.setExpanded(value); 1407 } 1408 1409 public boolean isSeparateSequenceSelected() 1410 { 1411 return loadingTypeCombo.getSelectedItem() == LoaderLoadingType.NO_GROUP; 1412 } 1413 1414 public boolean isGroupedSequenceSelected() 1415 { 1416 return loadingTypeCombo.getSelectedItem() == LoaderLoadingType.GROUP; 1417 } 1418 1419 public boolean isMultiFile() 1420 { 1421 return previewUpdater.isMultiFile(); 1422 } 1423 1424 public boolean canUseAdvancedSetting() 1425 { 1426 return !(isSeparateSequenceSelected() && isMultiFile()); 1427 } 1428 1429 public LoaderLoadingType getLoadingType() 1430 { 1431 return (LoaderLoadingType) loadingTypeCombo.getSelectedItem(); 1432 } 1433 1434 void setLoadingType(LoaderLoadingType value) 1435 { 1436 loadingTypeCombo.setSelectedItem(value); 1437 } 1438 1439 public int getResolutionLevel() 1440 { 1441 if (resolutionSlider.isVisible()) 1442 return resolutionSlider.getValue(); 1443 1444 return 0; 1445 } 1446 1447 public Rectangle getXYRegion() 1448 { 1449 if (xyRegionComp.isVisible() && xyRegionComp.isEnabled()) 1450 return (Rectangle) xyRegionComp.getRegion(); 1451 1452 return null; 1453 } 1454 1455 public void setXYRegion(Rectangle region) 1456 { 1457 // enable region loading 1458 xyRegionLoadingToggle.setSelected(true); 1459 xyRegionComp.setEnabled(true); 1460 xyRegionComp.setRegion(region); 1461 1462 // we want options to be visible in that case 1463 setOptionsVisible(true); 1464 } 1465 1466 public int getZMin() 1467 { 1468 if (zRangeComp.isVisible()) 1469 return (int) zRangeComp.getLow(); 1470 1471 return 0; 1472 } 1473 1474 public int getZMax() 1475 { 1476 if (zRangeComp.isVisible()) 1477 return (int) zRangeComp.getHigh(); 1478 1479 return 0; 1480 } 1481 1482 public boolean getFullZRange() 1483 { 1484 return (getZMin() == 0) && (getZMax() == (int) zRangeComp.getMax()); 1485 } 1486 1487 public int getTMin() 1488 { 1489 if (tRangeComp.isVisible()) 1490 return (int) tRangeComp.getLow(); 1491 1492 return 0; 1493 } 1494 1495 public int getTMax() 1496 { 1497 if (tRangeComp.isVisible()) 1498 return (int) tRangeComp.getHigh(); 1499 1500 return 0; 1501 } 1502 1503 public boolean getFullTRange() 1504 { 1505 return (getTMin() == 0) && (getTMax() == (int) tRangeComp.getMax()); 1506 } 1507 1508 public int getChannel() 1509 { 1510 if (channelSpinner.isVisible()) 1511 return ((Integer) channelSpinner.getValue()).intValue(); 1512 1513 // all by default 1514 return -1; 1515 } 1516 1517 public int getSeries() 1518 { 1519 if (seriesSpinner.isVisible()) 1520 // use cached value 1521 return series; 1522 1523 // all by default 1524 return -1; 1525 } 1526 1527 public void setSeries(int series) 1528 { 1529 // set default series 1530 seriesSpinner.setValue(Integer.valueOf(series)); 1531 1532 // we want options to be visible in that case 1533 setOptionsVisible(true); 1534 } 1535 1536 /** 1537 * Same as {@link #getSeries()} except it returns 0 instead of -1 to ensure we have one selected series 1538 */ 1539 public int getSelectedSeries() 1540 { 1541 final int result = getSeries(); 1542 1543 return (result == -1) ? 0 : result; 1544 } 1545 1546 /** 1547 * Cancel preview refresh 1548 */ 1549 public void cancelPreview() 1550 { 1551 previewUpdater.cancelPreview(); 1552 } 1553 1554 protected void updatePreview(int series) 1555 { 1556 previewUpdater.updatePreview(series); 1557 } 1558 1559 /** 1560 * Asynchronous image preview refresh only, ({@link #updatePreview(String)} should have be called once before to 1561 * give 1562 * the fileId) 1563 */ 1564 protected void updatePreview(int z, int t) 1565 { 1566 previewUpdater.updatePreview(z, t); 1567 } 1568 1569 /** 1570 * Asynchronous preview refresh 1571 */ 1572 public void updatePreview(String[] files, int s) 1573 { 1574 // series or files selection changed ? 1575 if ((series != s) || !CollectionUtil.equals(getFiles(), CollectionUtil.asList(files))) 1576 previewUpdater.updatePreview(files, s); 1577 } 1578 1579 /** 1580 * Asynchronous preview refresh 1581 */ 1582 public void updatePreview(List<String> files, int s) 1583 { 1584 // series or files selection changed ? 1585 if ((series != s) || !CollectionUtil.equals(getFiles(), files)) 1586 previewUpdater.updatePreview(files, s); 1587 } 1588 1589 /** 1590 * Asynchronous preview refresh 1591 */ 1592 public void updatePreview(String[] files) 1593 { 1594 // files selection changed ? 1595 if (!CollectionUtil.equals(getFiles(), CollectionUtil.asList(files))) 1596 previewUpdater.updatePreview(files, -1); 1597 } 1598 1599 /** 1600 * We are closing the Open Dialog. 1601 * Ensure metadata are correctly loaded (it's important that this method is called from EDT) 1602 */ 1603 public void closingFromEDT() 1604 { 1605 previewUpdater.close(); 1606 } 1607}