/**
   * @param converterSetups list of {@link ConverterSetup} that control min/max and color of
   *     sources.
   * @param sources list of pairs of source of some type and converter from that type to ARGB.
   * @param spimData may be null. The {@link AbstractSpimData} of the dataset (if there is one). If
   *     it exists, it is used to set up a "Crop" dialog.
   * @param numTimepoints the number of timepoints in the dataset.
   * @param cache handle to cache. This is used to control io timing.
   * @param windowTitle title of the viewer window.
   * @param windowWidth width of the viewer window.
   * @param windowHeight height of the viewer window.
   * @param progressWriter a {@link ProgressWriter} to which BDV may report progress (currently only
   *     used in the "Record Movie" dialog).
   */
  public BigDataViewer(
      final ArrayList<ConverterSetup> converterSetups,
      final ArrayList<SourceAndConverter<?>> sources,
      final AbstractSpimData<?> spimData,
      final int numTimepoints,
      final Cache cache,
      final String windowTitle,
      final int windowWidth,
      final int windowHeight,
      final ProgressWriter progressWriter) {
    viewerFrame = new ViewerFrame(windowWidth, windowHeight, sources, numTimepoints, cache);
    if (windowTitle != null) viewerFrame.setTitle(windowTitle);
    viewer = viewerFrame.getViewerPanel();

    for (final ConverterSetup cs : converterSetups)
      if (RealARGBColorConverterSetup.class.isInstance(cs))
        ((RealARGBColorConverterSetup) cs).setViewer(viewer);

    manualTransformation = new ManualTransformation(viewer);
    manualTransformationEditor =
        new ManualTransformationEditor(viewer, viewerFrame.getKeybindings());

    bookmarks = new Bookmarks();
    bookmarkEditor = new BookmarksEditor(viewer, viewerFrame.getKeybindings(), bookmarks);

    setupAssignments = new SetupAssignments(converterSetups, 0, 65535);
    if (setupAssignments.getMinMaxGroups().size() > 0) {
      final MinMaxGroup group = setupAssignments.getMinMaxGroups().get(0);
      for (final ConverterSetup setup : setupAssignments.getConverterSetups())
        setupAssignments.moveSetupToGroup(setup, group);
    }

    brightnessDialog = new BrightnessDialog(viewerFrame, setupAssignments);

    cropDialog =
        (spimData == null)
            ? null
            : new CropDialog(viewerFrame, viewer, spimData.getSequenceDescription());

    movieDialog = new RecordMovieDialog(viewerFrame, viewer, progressWriter);
    // this is just to get updates of window size:
    viewer.getDisplay().addOverlayRenderer(movieDialog);

    activeSourcesDialog =
        new VisibilityAndGroupingDialog(viewerFrame, viewer.getVisibilityAndGrouping());

    helpDialog = new HelpDialog(viewerFrame);

    fileChooser = new JFileChooser();
    fileChooser.setFileFilter(
        new FileFilter() {
          @Override
          public String getDescription() {
            return "xml files";
          }

          @Override
          public boolean accept(final File f) {
            if (f.isDirectory()) return true;
            if (f.isFile()) {
              final String s = f.getName();
              final int i = s.lastIndexOf('.');
              if (i > 0 && i < s.length() - 1) {
                final String ext = s.substring(i + 1).toLowerCase();
                return ext.equals("xml");
              }
            }
            return false;
          }
        });

    final KeyProperties keyProperties = KeyProperties.readPropertyFile();
    NavigationActions.installActionBindings(viewerFrame.getKeybindings(), viewer, keyProperties);
    BigDataViewerActions.installActionBindings(viewerFrame.getKeybindings(), this, keyProperties);

    final JMenuBar menubar = new JMenuBar();
    JMenu menu = new JMenu("File");
    menubar.add(menu);

    final ActionMap actionMap = viewerFrame.getKeybindings().getConcatenatedActionMap();
    final JMenuItem miLoadSettings =
        new JMenuItem(actionMap.get(BigDataViewerActions.LOAD_SETTINGS));
    miLoadSettings.setText("Load settings");
    menu.add(miLoadSettings);

    final JMenuItem miSaveSettings =
        new JMenuItem(actionMap.get(BigDataViewerActions.SAVE_SETTINGS));
    miSaveSettings.setText("Save settings");
    menu.add(miSaveSettings);

    menu = new JMenu("Settings");
    menubar.add(menu);

    final JMenuItem miBrightness =
        new JMenuItem(actionMap.get(BigDataViewerActions.BRIGHTNESS_SETTINGS));
    miBrightness.setText("Brightness & Color");
    menu.add(miBrightness);

    final JMenuItem miVisibility =
        new JMenuItem(actionMap.get(BigDataViewerActions.VISIBILITY_AND_GROUPING));
    miVisibility.setText("Visibility & Grouping");
    menu.add(miVisibility);

    menu = new JMenu("Tools");
    menubar.add(menu);

    if (cropDialog != null) {
      final JMenuItem miCrop = new JMenuItem(actionMap.get(BigDataViewerActions.CROP));
      miCrop.setText("Crop");
      menu.add(miCrop);
    }

    final JMenuItem miMovie = new JMenuItem(actionMap.get(BigDataViewerActions.RECORD_MOVIE));
    miMovie.setText("Record Movie");
    menu.add(miMovie);

    final JMenuItem miManualTransform =
        new JMenuItem(actionMap.get(BigDataViewerActions.MANUAL_TRANSFORM));
    miManualTransform.setText("Manual Transform");
    menu.add(miManualTransform);

    menu = new JMenu("Help");
    menubar.add(menu);

    final JMenuItem miHelp = new JMenuItem(actionMap.get(BigDataViewerActions.SHOW_HELP));
    miHelp.setText("Show Help");
    menu.add(miHelp);

    viewerFrame.setJMenuBar(menubar);
  }
 /**
  * Set a "good" initial viewer transform. The viewer transform is chosen such that for the first
  * source,
  *
  * <ul>
  *   <li>the XY plane is aligned with the screen plane,
  *   <li>the <em>z = dim_z / 2</em> slice is shown,
  *   <li>centered and scaled such that the full <em>dim_x</em> by <em>dim_y</em> is visible.
  * </ul>
  *
  * This calls {@link #initTransform(int, int, boolean, ViewerState)}, using the size of the
  * viewer's display component.
  *
  * @param viewer the viewer (containing at least one source) to have its transform set.
  */
 public static void initTransform(final ViewerPanel viewer) {
   final Dimension dim = viewer.getDisplay().getSize();
   final ViewerState state = viewer.getState();
   final AffineTransform3D viewerTransform = initTransform(dim.width, dim.height, false, state);
   viewer.setCurrentViewerTransform(viewerTransform);
 }