AbstractNewFileWizard.java

/**
 * Copyright (c) 2004-2025 Carnegie Mellon University and others. (see Contributors file).
 * All Rights Reserved.
 * 
 * NO WARRANTY. ALL MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE
 * OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT
 * MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
 * 
 * This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 * SPDX-License-Identifier: EPL-2.0
 * 
 * Created, in part, with funding and support from the United States Government. (see Acknowledgments file).
 * 
 * This program includes and/or can make use of certain third party source code, object code, documentation and other
 * files ("Third Party Software"). The Third Party Software that is used by this program is dependent upon your system
 * configuration. By using this program, You agree to comply with any and all relevant Third Party Software terms and
 * conditions contained in any such Third Party Software or separate license file distributed with such Third Party
 * Software. The parties who own the Third Party Software ("Third Party Licensors") are intended third party benefici-
 * aries to this license with respect to the terms applicable to their Third Party Software. Third Party Software li-
 * censes only apply to the Third Party Software and not any other portion of this program or this program as a whole.
 */
package org.osate.ui.wizards;

import com.google.common.base.Objects;
import com.google.common.collect.Iterables;
import java.io.ByteArrayInputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.Token;
import org.apache.commons.lang.StringUtils;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.model.WorkbenchContentProvider;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor;
import org.eclipse.xtend2.lib.StringConcatenation;
import org.eclipse.xtext.xbase.lib.CollectionLiterals;
import org.eclipse.xtext.xbase.lib.Conversions;
import org.eclipse.xtext.xbase.lib.Exceptions;
import org.eclipse.xtext.xbase.lib.Functions.Function1;
import org.eclipse.xtext.xbase.lib.IterableExtensions;
import org.eclipse.xtext.xbase.lib.MapExtensions;
import org.eclipse.xtext.xbase.lib.ObjectExtensions;
import org.eclipse.xtext.xbase.lib.Pair;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
import org.osate.ui.OsateUiPlugin;
import org.osate.xtext.aadl2.properties.parser.antlr.lexer.InternalPropertiesLexer;

/**
 * Abstract wizard for creating new files. Each wizard contains a tree for selecting the parent folder and
 * one or more fields for entering text. Subclasses must specify the fields in the wizard by calling addField
 * before the wizard page is created. This can best be done in the constructor of the subclass.
 */
@FinalFieldsConstructor
@SuppressWarnings("all")
public abstract class AbstractNewFileWizard extends Wizard implements INewWizard {
  private static final List<String> HIDE_FOLDERS = Collections.<String>unmodifiableList(CollectionLiterals.<String>newArrayList("instances", "diagrams", "imv"));

  protected IProject project = null;

  private final String titleFileType;

  private final String descriptionFileType;

  protected final String fileExtension;

  private final int tabIndex;

  private final ILog log;

  private final String pluginId;

  private final LinkedHashMap<String, Function1<? super String, ? extends Boolean>> fieldValidators = CollectionLiterals.<String, Function1<? super String, ? extends Boolean>>newLinkedHashMap();

  private IWorkbench workbench;

  private IContainer initialSelection;

  private TreeViewer folderViewer;

  private LinkedHashMap<String, Text> fields;

  public AbstractNewFileWizard(final String titleFileType, final String fileExtension, final int tabIndex, final ILog log, final String pluginId) {
    this(titleFileType, titleFileType.toLowerCase(), fileExtension, tabIndex, log, pluginId);
  }

  public void addField(final String fieldLabel, final Function1<? super String, ? extends Boolean> fieldValidator) {
    this.fieldValidators.put(fieldLabel, fieldValidator);
  }

  @Override
  public void init(final IWorkbench workbench, final IStructuredSelection selection) {
    this.workbench = workbench;
    IContainer _switchResult = null;
    Object _firstElement = null;
    if (selection!=null) {
      _firstElement=selection.getFirstElement();
    }
    final Object selectedElement = _firstElement;
    boolean _matched = false;
    if (selectedElement instanceof IFile) {
      _matched=true;
      _switchResult = ((IFile)selectedElement).getParent();
    }
    if (!_matched) {
      if (selectedElement instanceof IContainer) {
        _matched=true;
        _switchResult = ((IContainer)selectedElement);
      }
    }
    this.initialSelection = _switchResult;
    IProject _project = null;
    if (this.initialSelection!=null) {
      _project=this.initialSelection.getProject();
    }
    this.project = _project;
    StringConcatenation _builder = new StringConcatenation();
    _builder.append("New ");
    _builder.append(this.titleFileType);
    _builder.append(" File");
    this.setWindowTitle(_builder.toString());
    this.setDefaultPageImageDescriptor(OsateUiPlugin.getImageDescriptor("icons/NewAadl2.gif"));
  }

  @Override
  public boolean performFinish() {
    boolean _xblockexpression = false;
    {
      final IFile newFile = this.getFile();
      final Function1<Text, String> _function = (Text field) -> {
        return field.getText();
      };
      Map<String, String> _mapValues = MapExtensions.<String, Text, String>mapValues(this.fields, _function);
      HashMap<String, String> _hashMap = new HashMap<String, String>(_mapValues);
      final String contents = this.fileContents(_hashMap);
      final WorkspaceModifyOperation _function_1 = new WorkspaceModifyOperation() {
        @Override
        protected void execute(final IProgressMonitor monitor) throws CoreException, InvocationTargetException, InterruptedException {
          byte[] _bytes = contents.getBytes();
          ByteArrayInputStream _byteArrayInputStream = new ByteArrayInputStream(_bytes);
          newFile.create(_byteArrayInputStream, false, monitor);
          boolean _isCanceled = monitor.isCanceled();
          if (_isCanceled) {
            throw new OperationCanceledException();
          }
        }
      };
      final WorkspaceModifyOperation operation = _function_1;
      boolean _xtrycatchfinallyexpression = false;
      try {
        boolean _xblockexpression_1 = false;
        {
          this.getContainer().run(true, true, operation);
          this.openEditor(newFile, contents);
          _xblockexpression_1 = true;
        }
        _xtrycatchfinallyexpression = _xblockexpression_1;
      } catch (final Throwable _t) {
        if (_t instanceof InterruptedException) {
          _xtrycatchfinallyexpression = false;
        } else if (_t instanceof InvocationTargetException) {
          final InvocationTargetException e_1 = (InvocationTargetException)_t;
          boolean _xblockexpression_2 = false;
          {
            String _message = e_1.getMessage();
            Status _status = new Status(IStatus.ERROR, this.pluginId, _message, e_1);
            this.log.log(_status);
            MessageDialog.openError(this.getContainer().getShell(), "Creation Problems", e_1.getTargetException().getMessage());
            _xblockexpression_2 = false;
          }
          _xtrycatchfinallyexpression = _xblockexpression_2;
        } else {
          throw Exceptions.sneakyThrow(_t);
        }
      }
      _xblockexpression = _xtrycatchfinallyexpression;
    }
    return _xblockexpression;
  }

  public void openEditor(final IFile newFile, final String contents) {
    this.openDefaultEditor(newFile, contents);
  }

  protected final void openDefaultEditor(final IFile newFile, final String contents) {
    final IWorkbenchPage activePage = this.workbench.getActiveWorkbenchWindow().getActivePage();
    final String editorId = this.workbench.getEditorRegistry().getDefaultEditor(newFile.getName()).getId();
    try {
      FileEditorInput _fileEditorInput = new FileEditorInput(newFile);
      IEditorPart _openEditor = activePage.openEditor(_fileEditorInput, editorId);
      final ITextEditor editor = ((ITextEditor) _openEditor);
      int _ordinalIndexOf = StringUtils.ordinalIndexOf(contents, "\t", this.tabIndex);
      int _plus = (_ordinalIndexOf + 1);
      editor.selectAndReveal(_plus, 0);
    } catch (final Throwable _t) {
      if (_t instanceof PartInitException) {
        final PartInitException e = (PartInitException)_t;
        String _message = e.getMessage();
        Status _status = new Status(IStatus.WARNING, this.pluginId, _message, e);
        this.log.log(_status);
        MessageDialog.openWarning(this.getContainer().getShell(), "Open Editor", e.getMessage());
      } else {
        throw Exceptions.sneakyThrow(_t);
      }
    }
  }

  /**
   * fieldValues is a map from the field labels to the values in the text fields. The field labels are
   * specified in the calls to addField.
   */
  public abstract String fileContents(final Map<String, String> fieldValues);

  @Override
  public void addPages() {
    abstract class __AbstractNewFileWizard_1 extends WizardPage {
      __AbstractNewFileWizard_1(final String arg0, final String arg1, final ImageDescriptor arg2) {
        super(arg0, arg1, arg2);
      }

      /**
       * The following conditions must be true for the wizard page to be valid:
       * -A parent project or folder must be selected.
       * -For each field:
       *   -Must not be empty.
       *   -Must pass the field's validator
       * -For the first field:
       *   -Must not already exist as a file in the selected project or folder.
       */
      abstract void validate();
    }

    StringConcatenation _builder = new StringConcatenation();
    _builder.append("New ");
    _builder.append(this.titleFileType);
    _builder.append(" File");
    __AbstractNewFileWizard_1 ___AbstractNewFileWizard_1 = new __AbstractNewFileWizard_1("New Object", _builder.toString(), null) {
      @Override
      public void createControl(final Composite parent) {
        Composite _composite = new Composite(parent, SWT.NONE);
        final Procedure1<Composite> _function = (Composite composite) -> {
          composite.setSize(parent.getSize());
          GridLayout _gridLayout = new GridLayout(2, false);
          composite.setLayout(_gridLayout);
          Label _label = new Label(composite, SWT.NONE);
          final Procedure1<Label> _function_1 = (Label label) -> {
            label.setText("Create in project/folder:");
            GridData _gridData = new GridData(SWT.BEGINNING, SWT.CENTER, true, false, 2, 1);
            label.setLayoutData(_gridData);
          };
          ObjectExtensions.<Label>operator_doubleArrow(_label, _function_1);
          TreeViewer _treeViewer = new TreeViewer(composite, (SWT.BORDER | SWT.SINGLE));
          final Procedure1<TreeViewer> _function_2 = (TreeViewer folderViewer) -> {
            Tree _tree = folderViewer.getTree();
            GridData _gridData = new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1);
            _tree.setLayoutData(_gridData);
            folderViewer.setContentProvider(new WorkbenchContentProvider() {
              @Override
              public Object[] getChildren(final Object element) {
                Object[] _switchResult = null;
                boolean _matched = false;
                if (element instanceof IWorkspace) {
                  _matched=true;
                  final Function1<IProject, Boolean> _function = (IProject project) -> {
                    return Boolean.valueOf(project.isOpen());
                  };
                  _switchResult = ((Object[])Conversions.unwrapArray(IterableExtensions.<IProject>filter(((Iterable<IProject>)Conversions.doWrapArray(((IWorkspace)element).getRoot().getProjects())), _function), Object.class));
                }
                if (!_matched) {
                  if (element instanceof IContainer) {
                    _matched=true;
                    Object[] _xtrycatchfinallyexpression = null;
                    try {
                      final Function1<IContainer, Boolean> _function = (IContainer resource) -> {
                        return Boolean.valueOf(((!resource.getName().startsWith(".")) && (!AbstractNewFileWizard.HIDE_FOLDERS.contains(resource.getName()))));
                      };
                      _xtrycatchfinallyexpression = ((Object[])Conversions.unwrapArray(IterableExtensions.<IContainer>filter(Iterables.<IContainer>filter(((Iterable<?>)Conversions.doWrapArray(((IContainer)element).members())), IContainer.class), _function), Object.class));
                    } catch (final Throwable _t) {
                      if (_t instanceof CoreException) {
                        final CoreException e = (CoreException)_t;
                        Object[] _xblockexpression = null;
                        {
                          String _message = e.getMessage();
                          Status _status = new Status(IStatus.WARNING, AbstractNewFileWizard.this.pluginId, _message, e);
                          AbstractNewFileWizard.this.log.log(_status);
                          _xblockexpression = new Object[] {};
                        }
                        _xtrycatchfinallyexpression = _xblockexpression;
                      } else {
                        throw Exceptions.sneakyThrow(_t);
                      }
                    }
                    _switchResult = _xtrycatchfinallyexpression;
                  }
                }
                if (!_matched) {
                  _switchResult = new Object[] {};
                }
                return _switchResult;
              }
            });
            folderViewer.setLabelProvider(WorkbenchLabelProvider.getDecoratingWorkbenchLabelProvider());
            folderViewer.setInput(ResourcesPlugin.getWorkspace());
            if ((AbstractNewFileWizard.this.initialSelection != null)) {
              StructuredSelection _structuredSelection = new StructuredSelection(AbstractNewFileWizard.this.initialSelection);
              folderViewer.setSelection(_structuredSelection, true);
            }
            final ISelectionChangedListener _function_3 = (SelectionChangedEvent it) -> {
              this.validate();
            };
            folderViewer.addSelectionChangedListener(_function_3);
          };
          TreeViewer _doubleArrow = ObjectExtensions.<TreeViewer>operator_doubleArrow(_treeViewer, _function_2);
          AbstractNewFileWizard.this.folderViewer = _doubleArrow;
          final Function1<String, Pair<String, Text>> _function_3 = (String fieldLabel) -> {
            Pair<String, Text> _xblockexpression = null;
            {
              Label _label_1 = new Label(composite, SWT.NONE);
              final Procedure1<Label> _function_4 = (Label label) -> {
                label.setText((fieldLabel + ":"));
                GridData _gridData = new GridData(SWT.BEGINNING, SWT.CENTER, false, false);
                label.setLayoutData(_gridData);
              };
              ObjectExtensions.<Label>operator_doubleArrow(_label_1, _function_4);
              Text _text = new Text(composite, SWT.BORDER);
              final Procedure1<Text> _function_5 = (Text field) -> {
                GridData _gridData = new GridData(SWT.FILL, SWT.CENTER, true, false);
                field.setLayoutData(_gridData);
                final ModifyListener _function_6 = (ModifyEvent it) -> {
                  this.validate();
                };
                field.addModifyListener(_function_6);
              };
              final Text field = ObjectExtensions.<Text>operator_doubleArrow(_text, _function_5);
              _xblockexpression = Pair.<String, Text>of(fieldLabel, field);
            }
            return _xblockexpression;
          };
          AbstractNewFileWizard.this.fields = CollectionLiterals.<String, Text>newLinkedHashMap(((Pair<? extends String, ? extends Text>[])Conversions.unwrapArray(IterableExtensions.<String, Pair<String, Text>>map(AbstractNewFileWizard.this.fieldValidators.keySet(), _function_3), Pair.class)));
          AbstractNewFileWizard.this.addLocalControls(composite);
        };
        Composite _doubleArrow = ObjectExtensions.<Composite>operator_doubleArrow(_composite, _function);
        this.setControl(_doubleArrow);
      }

      @Override
      public void setVisible(final boolean visible) {
        super.setVisible(visible);
        if (visible) {
          IterableExtensions.<Text>head(AbstractNewFileWizard.this.fields.values()).setFocus();
        }
      }

      /**
       * The following conditions must be true for the wizard page to be valid:
       * -A parent project or folder must be selected.
       * -For each field:
       *   -Must not be empty.
       *   -Must pass the field's validator
       * -For the first field:
       *   -Must not already exist as a file in the selected project or folder.
       */
      void validate() {
        String _xifexpression = null;
        boolean _isEmpty = AbstractNewFileWizard.this.folderViewer.getStructuredSelection().isEmpty();
        if (_isEmpty) {
          _xifexpression = "No folder specified.";
        } else {
          final Function1<Map.Entry<String, Text>, String> _function = (Map.Entry<String, Text> entry) -> {
            String _xblockexpression = null;
            {
              final String fieldLabel = entry.getKey();
              final Text field = entry.getValue();
              String _xifexpression_1 = null;
              boolean _isEmpty_1 = field.getText().isEmpty();
              if (_isEmpty_1) {
                _xifexpression_1 = (fieldLabel + " cannot be empty.");
              } else {
                String _xifexpression_2 = null;
                Boolean _apply = AbstractNewFileWizard.this.fieldValidators.get(fieldLabel).apply(field.getText());
                boolean _not = (!(_apply).booleanValue());
                if (_not) {
                  StringConcatenation _builder = new StringConcatenation();
                  _builder.append("The ");
                  _builder.append(fieldLabel);
                  _builder.append(" \'");
                  String _text = field.getText();
                  _builder.append(_text);
                  _builder.append("\' is not valid.");
                  _xifexpression_2 = _builder.toString();
                } else {
                  String _xifexpression_3 = null;
                  String _head = IterableExtensions.<String>head(AbstractNewFileWizard.this.fields.keySet());
                  boolean _equals = Objects.equal(fieldLabel, _head);
                  if (_equals) {
                    String _xblockexpression_1 = null;
                    {
                      Object _firstElement = AbstractNewFileWizard.this.folderViewer.getStructuredSelection().getFirstElement();
                      final IContainer parentContainer = ((IContainer) _firstElement);
                      _xblockexpression_1 = AbstractNewFileWizard.this.validateFileName(parentContainer, IterableExtensions.<Text>head(AbstractNewFileWizard.this.fields.values()).getText());
                    }
                    _xifexpression_3 = _xblockexpression_1;
                  }
                  _xifexpression_2 = _xifexpression_3;
                }
                _xifexpression_1 = _xifexpression_2;
              }
              _xblockexpression = _xifexpression_1;
            }
            return _xblockexpression;
          };
          _xifexpression = IterableExtensions.<String>head(IterableExtensions.<String>filterNull(IterableExtensions.<Map.Entry<String, Text>, String>map(AbstractNewFileWizard.this.fields.entrySet(), _function)));
        }
        this.setErrorMessage(_xifexpression);
        String _errorMessage = this.getErrorMessage();
        boolean _tripleEquals = (_errorMessage == null);
        this.setPageComplete(_tripleEquals);
      }
    };
    final Procedure1<__AbstractNewFileWizard_1> _function = (__AbstractNewFileWizard_1 wizardPage) -> {
      StringConcatenation _builder_1 = new StringConcatenation();
      _builder_1.append("Create a new ");
      _builder_1.append(this.descriptionFileType);
      _builder_1.append(" file.");
      wizardPage.setDescription(_builder_1.toString());
      wizardPage.setPageComplete(false);
    };
    __AbstractNewFileWizard_1 _doubleArrow = ObjectExtensions.<__AbstractNewFileWizard_1>operator_doubleArrow(___AbstractNewFileWizard_1, _function);
    this.addPage(_doubleArrow);
  }

  protected String validateFileName(final IContainer parent, final String name) {
    String _xifexpression = null;
    boolean _exists = this.getFile().exists();
    if (_exists) {
      String _fileName = this.getFileName(name);
      String _plus = ("\'" + _fileName);
      _xifexpression = (_plus + "\' already exists.");
    } else {
      _xifexpression = null;
    }
    return _xifexpression;
  }

  /**
   * A wizard may add more controls to the pane.  They will appear below the widgets created by the
   * {@link #addFields} functionality.  Keep in mind that the layout manager for the pane is a Grid with
   * 2 columns.
   */
  protected void addLocalControls(final Composite parent) {
  }

  protected static boolean isValidId(final String id) {
    boolean _xtrycatchfinallyexpression = false;
    try {
      boolean _xblockexpression = false;
      {
        ANTLRStringStream _aNTLRStringStream = new ANTLRStringStream(id);
        final InternalPropertiesLexer lexer = new InternalPropertiesLexer(_aNTLRStringStream);
        lexer.mRULE_ID();
        Token _nextToken = lexer.nextToken();
        _xblockexpression = Objects.equal(_nextToken, Token.EOF_TOKEN);
      }
      _xtrycatchfinallyexpression = _xblockexpression;
    } catch (final Throwable _t) {
      if (_t instanceof RecognitionException) {
        _xtrycatchfinallyexpression = false;
      } else {
        throw Exceptions.sneakyThrow(_t);
      }
    }
    return _xtrycatchfinallyexpression;
  }

  private IFile getFile() {
    IFile _xblockexpression = null;
    {
      Object _firstElement = this.folderViewer.getStructuredSelection().getFirstElement();
      final IContainer parentContainer = ((IContainer) _firstElement);
      String _fileName = this.getFileName(IterableExtensions.<Text>head(this.fields.values()).getText());
      Path _path = new Path(_fileName);
      _xblockexpression = parentContainer.getFile(_path);
    }
    return _xblockexpression;
  }

  protected String getFileName(final String enteredName) {
    return ((enteredName + ".") + this.fileExtension);
  }

  public AbstractNewFileWizard(final String titleFileType, final String descriptionFileType, final String fileExtension, final int tabIndex, final ILog log, final String pluginId) {
    super();
    this.titleFileType = titleFileType;
    this.descriptionFileType = descriptionFileType;
    this.fileExtension = fileExtension;
    this.tabIndex = tabIndex;
    this.log = log;
    this.pluginId = pluginId;
  }
}