/*******************************************************************************
* Copyright (c) 2012 Arapiki Solutions Inc.
* 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
*
* Contributors:
* "Peter Smith <psmith@arapiki.com>" - initial API and
* implementation and/or initial documentation
*******************************************************************************/
package com.buildml.eclipse.wizards;
import java.io.File;
import org.eclipse.core.resources.IFile;
import org.eclipse.jface.preference.FileFieldEditor;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
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.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import com.buildml.eclipse.MainEditor;
import com.buildml.eclipse.utils.EclipsePartUtils;
import com.buildml.eclipse.utils.fieldeditors.WorkspaceFileSelectFieldEditor;
/**
* An abstract parent class for any Eclipse import wizard dialog pages that
* take some type of input, and write content to a BuildML (.bml) BuildStore
* file. Each subclass is expected to manage it's own "input source" fields,
* but this class will manage the "output destination" fields (the name of
* the BuildML .bml file).
*
* @author Peter Smith <psmith@arapiki.com>
*/
public abstract class ImportToBuildStorePage extends WizardPage {
/*=====================================================================================*
* FIELDS/TYPES
*=====================================================================================*/
/** The field used to select the output file */
private WorkspaceFileSelectFieldEditor outputFile;
/** The textual name/path of the output file */
private String outputPath;
/** Instruction text, to be displayed near the top of the wizard page */
private String instructions;
/** The combo box from which existing (open) .bml files can be selected */
private Combo bmlFileComboBox;
/**
* The resources that were selected in the Eclipse UI, when the "import" operation was
* invoked. If valid, this is used as the .bml file to import into.
*/
private ISelection selection;
/*=====================================================================================*
* CONSTRUCTORS
*=====================================================================================*/
/**
* Create a new ImportToBuildStorePage. Only subclasses may be instantiated.
*
* @param pageName The title of this wizard page.
* @param instructions The textual instructions to be displayed near the top of the
* page. These guide the user on how to fill out the fields.
* @param selection Resource(s) selected when "import" was invoked.
*/
protected ImportToBuildStorePage(String pageName, String instructions,
ISelection selection) {
super(pageName);
setTitle(pageName);
this.instructions = instructions;
this.selection = selection;
}
/*=====================================================================================*
* PUBLIC METHODS
*=====================================================================================*/
/**
* Create the widgets for this wizard's dialog box. All import dialogs require the
* user to specify an "output" BuildML file (or select the name of a currently open
* editor that contains such a file). However, each subclass must provide its own set of
* input fields, depending on the goal of the import process (by overriding the
* createInputFields() method).
*
* @param parent The containing parent widget.
*/
@Override
public void createControl(Composite parent) {
/* The top-level composite has three columns */
Composite composite = new Composite(parent, SWT.NONE);
GridLayout compositeLayout = new GridLayout(3, false);
compositeLayout.marginWidth = 20;
compositeLayout.marginHeight = 20;
compositeLayout.verticalSpacing = 20;
composite.setLayout(compositeLayout);
/* page is not complete until the fields are valid */
setPageComplete(false);
/*
* Show an introductory piece of text, providing instructions. This
* label also forces the wizard box to be 33% of the screen width.
*/
Label heading = new Label(composite, SWT.WRAP);
GridData headingData = new GridData(SWT.FILL, SWT.CENTER, false, false, 3, 1);
headingData.widthHint = Display.getCurrent().getClientArea().width / 3;
heading.setLayoutData(headingData);
heading.setText(instructions);
/*
* Provide a file input box, each subclass must provide its own set of input files,
* depending on the purpose of the wizard. The createInputFields() method does
* all of that work.
*/
Group inputGroup = new Group(composite, SWT.NONE);
inputGroup.setText("Import Source:");
inputGroup.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 3, 1));
GridLayout inputGroupLayout = new GridLayout();
inputGroupLayout.marginHeight = 10;
inputGroupLayout.marginWidth = 10;
inputGroup.setLayout(inputGroupLayout);
createInputFields(inputGroup);
/*
* Select the destination BuildML file. Either by selecting an open editor from a combo box,
* or by browsing for the .bml file.
*/
Group outputGroup = new Group(composite, SWT.NONE);
outputGroup.setText("Import Destination:");
outputGroup.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 3, 1));
GridLayout outputGroupLayout = new GridLayout(2, false);
outputGroupLayout.marginHeight = 10;
outputGroupLayout.marginWidth = 10;
outputGroup.setLayout(outputGroupLayout);
/* Display list of open editors (if there are some) */
final MainEditor openEditors[] = EclipsePartUtils.getOpenBmlEditors();
boolean openEditorsExist = false;
if ((openEditors != null) && (openEditors.length != 0)) {
openEditorsExist = true;
new Label(outputGroup, SWT.NONE).setText("Choose Open BuildML file:");
bmlFileComboBox = new Combo(outputGroup, SWT.READ_ONLY | SWT.DROP_DOWN);
bmlFileComboBox.add("");
for (int i = 0; i < openEditors.length; i++) {
String option = openEditors[i].getFile().toString();
bmlFileComboBox.add(EclipsePartUtils.absoluteToWorkspaceRelativePath(option));
}
bmlFileComboBox.setLayoutData(
new GridData(SWT.FILL, SWT.CENTER, true, false));
/*
* When the user selects from the combo box, update the text field with the
* workspace-relative path of the build.bml file.
*/
bmlFileComboBox.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
int index = bmlFileComboBox.getSelectionIndex();
if (index > 0) {
String absPath = openEditors[index - 1].getFile().toString();
String relPath = EclipsePartUtils.absoluteToWorkspaceRelativePath(absPath);
if (relPath == null) {
relPath = "";
}
outputFile.setStringValue(relPath);
}
}
});
}
/* Or select the BuildML file via a file browser */
Composite outputFileComposite = new Composite(outputGroup, SWT.NONE);
outputFileComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
outputFile = new WorkspaceFileSelectFieldEditor("outputFile",
(openEditorsExist ? "or " : "") + "Browse BuildML Files: ", outputFileComposite,
new String[] { "*.bml" });
outputFile.getTextControl(outputFileComposite).addModifyListener(new ModifyListener(){
public void modifyText(ModifyEvent e) {
contentChanged();
}
});
/*
* If there was a .bml file selected when the "import" operation was initiated, select
* that file as the default .bml file.
*/
if (selection != null && !selection.isEmpty() &&
selection instanceof IStructuredSelection) {
IStructuredSelection ssel = (IStructuredSelection) selection;
if (ssel.size() == 1) {
Object obj = ssel.getFirstElement();
if (obj instanceof IFile) {
IFile file = (IFile)obj;
String relativePath = file.getFullPath().toString();
if (relativePath.endsWith(".bml")) {
outputFile.setStringValue(relativePath);
if (bmlFileComboBox != null) {
bmlFileComboBox.setText(relativePath);
}
}
}
}
}
/* done */
setControl(composite);
}
/*-------------------------------------------------------------------------------------*/
/**
* Return the absolute path of the output file (with .bml extension) that the user has
* selected. This method should be called once the "finish" button has been pressed.
* @return The output file's full path.
*/
public String getOutputPath()
{
return EclipsePartUtils.workspaceRelativeToAbsolutePath(outputPath);
}
/*=====================================================================================*
* PROTECTED METHODS
*=====================================================================================*/
/**
* Each subclass should implement this method, to create the widgets that appear in
* the "input source" box.
*
* @param parent The "input source" group box (a composite that all widgets should be
* added within).
*/
protected abstract void createInputFields(Composite parent);
/*-------------------------------------------------------------------------------------*/
/**
* Each subclass should implement this method, to determine whether the input fields
* (which are supplied and managed by the subclass) contain valid content, and we
* should therefore enable the "Finish" button.
*
* @return true if the input fields are valid, else false.
*/
protected abstract boolean isInputValid();
/*-------------------------------------------------------------------------------------*/
/**
* This method should be called after any input field is modified (including those
* added by sub-classes). The goal is to determine whether the current combination of
* input fields is valid.
*/
protected void contentChanged() {
outputPath = ImportToBuildStorePage.this.outputFile.getStringValue();
ImportToBuildStorePage.this.setPageComplete(
outputPath.endsWith(".bml") &&
new File(EclipsePartUtils.workspaceRelativeToAbsolutePath(outputPath)).isFile() &&
isInputValid());
}
/*-------------------------------------------------------------------------------------*/
}