+/*******************************************************************************
+ * Copyright (c) 2016 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.dialog;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Shell;
+
+import com.google.common.annotations.VisibleForTesting;
+
+/**
+ * A file dialog factory.
+ * <p>
+ * This allows file dialogs to be stubbed out for SWTBot tests.
+ *
+ * @author Matthew Khouzam
+ * @since 2.2
+ */
+public final class TmfFileDialogFactory {
+ private static @Nullable String[] fOverridePaths = null;
+
+ /**
+ * File dialog factory, creates a {@link FileDialog}.
+ * <p>
+ * Constructs a new instance of this class given only its parent.
+ * </p>
+ * <p>
+ * If the factory is overridden with {@link #setOverrideFiles(String...)},
+ * the FileDialog will return the set String when open is called instead of
+ * opening a system window
+ * </p>
+ *
+ * @param parent
+ * a shell which will be the parent of the new instance
+ * @return the {@link FileDialog}
+ *
+ * @exception IllegalArgumentException
+ * <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException
+ * <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the parent</li>
+ * <li>ERROR_INVALID_SUBCLASS - if this class is not an
+ * allowed subclass</li>
+ * </ul>
+ */
+ public static FileDialog create(Shell parent) {
+ return create(parent, SWT.APPLICATION_MODAL);
+ }
+
+ /**
+ * File dialog factory, creates a {@link FileDialog}.
+ * <p>
+ * Constructs a new instance of this class given its parent and a style
+ * value describing its behavior and appearance.
+ * </p>
+ * <p>
+ * The style value is either one of the style constants defined in class
+ * <code>SWT</code> which is applicable to instances of this class, or must
+ * be built by <em>bitwise OR</em>'ing together (that is, using the
+ * <code>int</code> "|" operator) two or more of those <code>SWT</code>
+ * style constants. The class description lists the style constants that are
+ * applicable to the class. Style bits are also inherited from superclasses.
+ * </p>
+ * <p>
+ * If the factory is overridden with {@link #setOverrideFiles(String[])},
+ * the FileDialog will return the set String when open is called instead of
+ * opening a system window
+ * </p>
+ *
+ * @param parent
+ * a shell which will be the parent of the new instance
+ * @param style
+ * the style of dialog to construct
+ * @return the {@link FileDialog}
+ *
+ * @exception IllegalArgumentException
+ * <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException
+ * <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+ * thread that created the parent</li>
+ * <li>ERROR_INVALID_SUBCLASS - if this class is not an
+ * allowed subclass</li>
+ * </ul>
+ *
+ * @see SWT#SAVE
+ * @see SWT#OPEN
+ * @see SWT#MULTI
+ */
+ public static FileDialog create(Shell parent, int style) {
+ String[] overridePath = fOverridePaths;
+ if (overridePath != null) {
+ fOverridePaths = null;
+ return createNewFileDialog(parent, style, Arrays.asList(overridePath));
+ }
+ return new FileDialog(parent, style);
+ }
+
+ /**
+ * Set the override string name that will be returned for the next
+ * {@link FileDialog}. Must be called before creating the dialogs.
+ *
+ * This is a method aimed for testing, This should not be used in product
+ * code.
+ *
+ * @param paths
+ * the paths to override the {@link FileDialog}. They must be
+ * absolute. One or many absolute paths may be entered. When many
+ * paths are entered, it return an input of a multi-select action
+ * if paths is null, it will undo overriding, if paths is a zero
+ * length array, it will behave as if the dialog was cancelled.
+ */
+ @VisibleForTesting
+ @SuppressWarnings("null")
+ public static void setOverrideFiles(String... paths) {
+ fOverridePaths = paths;
+ }
+
+ private static FileDialog createNewFileDialog(Shell parent, int style, List<String> overridePaths) {
+ return new FileDialog(parent, style) {
+ @Override
+ public String open() {
+ return !overridePaths.isEmpty() ? overridePaths.get(0) : null;
+ }
+
+ @Override
+ protected void checkSubclass() {
+ /*
+ * do nothing, allow this class to be overridden without
+ * throwing a runtime exception
+ */
+ }
+
+ @Override
+ public String getFileName() {
+ return !overridePaths.isEmpty() ? getFileName(overridePaths.get(0)) : ""; //$NON-NLS-1$
+ }
+
+ @Override
+ public String[] getFileNames() {
+ List<String> outStrings = new ArrayList<>();
+ for (String entry : overridePaths) {
+ outStrings.add(getFileName(entry));
+ }
+ return outStrings.toArray(new String[outStrings.size()]);
+ }
+
+ @Override
+ public String getFilterPath() {
+ return !overridePaths.isEmpty() ? new Path(overridePaths.get(0)).removeLastSegments(1).toString() : ""; //$NON-NLS-1$
+ }
+
+ private String getFileName(String path) {
+ return new Path(path).lastSegment();
+ }
+ };
+ }
+}