/*******************************************************************************
* Copyright (c) 2008, 2011 Thomas Holland (thomas@innot.de) and others.
* 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:
* Thomas Holland - initial API and implementation
*******************************************************************************/
package de.innot.avreclipse.ui.preferences;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.StatusDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.part.PageBook;
import de.innot.avreclipse.AVRPlugin;
import de.innot.avreclipse.core.paths.AVRPathManager;
import de.innot.avreclipse.core.paths.AVRPathManager.SourceType;
/**
* Custom dialog to modify a plugin path.
*
* @author Thomas Holland
*
*/
public class PathSettingDialog extends StatusDialog {
// The GUI Widgets
private Combo fTypeCombo = null;
private Combo fBundleCombo = null;
private Text fPathText = null;
private Button fFolderButton = null;
private PageBook fPageBook = null;
private Composite fSystemPage = null;
private Composite fBundlePage = null;
private Composite fCustomPage = null;
// Internal path storage
private AVRPathManager fPathManager = null;
/**
* Constructor for a new PathSettingDialog.
*
* The passed IPathManager is copied and any changes to the path are only written back to it
* when the {@link #getResult()} method is called.
*
* @param parent
* Parent <code>Shell</code>
* @param pathmanager
* IPathManager with the path to edit
*/
public PathSettingDialog(Shell parent, AVRPathManager pathmanager) {
super(parent);
// make a copy of the given IPathManager
fPathManager = new AVRPathManager(pathmanager);
setTitle("Change Path for " + pathmanager.getName());
// Allow this dialog to be resizeable
setShellStyle(getShellStyle() | SWT.RESIZE);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
*/
@Override
protected Control createDialogArea(Composite parent) {
Composite composite = (Composite) super.createDialogArea(parent);
// The list of supported Source types
String[] types = { AVRPathManager.SourceType.System.toString(),
AVRPathManager.SourceType.Bundled.toString(),
AVRPathManager.SourceType.Custom.toString() };
// TODO: try to determine the size dynamically
getShell().setMinimumSize(400, 220);
// The description Label
Label description = new Label(composite, SWT.NONE);
description.setText(fPathManager.getDescription());
// The Top part contains the Source Type Combo
Composite top = new Composite(composite, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.numColumns = 2;
top.setLayout(layout);
// The Source Type combo
Label typelabel = new Label(top, SWT.NONE);
typelabel.setText("Path source:");
fTypeCombo = new Combo(top, SWT.READ_ONLY | SWT.DROP_DOWN);
fTypeCombo.setItems(types);
fTypeCombo.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
String value = fTypeCombo.getText();
changeSourceType(value);
}
});
// Separator Label as eye candy
Label separator = new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL);
separator.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false));
// The path editors for the different source types are organized as
// pages of a PageBook, so only one is shown at a time
fPageBook = new PageBook(composite, SWT.NONE);
fPageBook.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
fSystemPage = addSystemPage(fPageBook);
fBundlePage = addBundlePage(fPageBook);
fCustomPage = addCustomPage(fPageBook);
// show the current path / source values
String currenttype = fPathManager.getSourceType().toString();
fTypeCombo.select(fTypeCombo.indexOf(currenttype));
changeSourceType(currenttype);
return composite;
}
/**
* Add an editor page for System source type.
*
* This only shows the system value read-only
*
* @param parent
* PageBook
* @return Composite containing the System source editor
*/
private Composite addSystemPage(Composite parent) {
Composite page = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.numColumns = 3;
page.setLayout(layout);
Label label = new Label(page, SWT.NONE);
label.setText("System value:");
final Text text = new Text(page, SWT.BORDER | SWT.READ_ONLY);
text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
// text.setBackground(page.getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
text.setText(fPathManager.getSystemPath(false).toOSString());
Button rescanbutton = new Button(page, SWT.NONE);
rescanbutton.setText("Rescan");
rescanbutton.addSelectionListener(new SelectionAdapter() {
/*
* (non-Javadoc)
*
* @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
*/
@Override
public void widgetSelected(SelectionEvent e) {
BusyIndicator.showWhile(fPageBook.getDisplay(), new Runnable() {
public void run() {
fPathManager.getSystemPath(true);
}
});
// Get the updated system path from the cache
text.setText(fPathManager.getSystemPath(false).toOSString());
}
});
return page;
}
/**
* Add an editor page for Bundle source type.
*
* Bundle sources are currently not implemented.
*
* @param parent
* PageBook
* @return Composite containing the Bundle source editor
*/
private Composite addBundlePage(Composite parent) {
Composite page = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.numColumns = 2;
page.setLayout(layout);
Label label = new Label(page, SWT.NONE);
label.setText("Select AVR-GCC Bundle");
// TODO: Bundle: Add choices here
fBundleCombo = new Combo(page, SWT.READ_ONLY | SWT.DROP_DOWN);
fBundleCombo.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
String value = fTypeCombo.getText();
System.out.println(value);
// TODO: Bundle: do something
}
});
return page;
}
/**
* Add an editor page for Custom source type.
*
* @param parent
* PageBook
* @return Composite containing the Custom source editor
*/
private Composite addCustomPage(Composite parent) {
Composite page = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.numColumns = 3;
page.setLayout(layout);
Label label = new Label(page, SWT.NONE);
label.setText("Custom value:");
// label.setLayoutData(new GridData(SWT.NONE, SWT.NONE, false, false));
fPathText = new Text(page, SWT.SINGLE | SWT.BORDER);
fPathText.setText(fPathManager.getPath().toOSString());
fPathText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
fPathText.addListener(SWT.Modify, new Listener() {
public void handleEvent(Event event) {
// test the path on all modifications
String newpath = fPathText.getText();
fPathManager.setPath(newpath, SourceType.Custom);
testStatus();
}
});
fFolderButton = new Button(page, SWT.NONE);
fFolderButton.setText("Browse...");
// fFolderButton.setLayoutData(new GridData(SWT.NONE, SWT.NONE, false,
// false));
fFolderButton.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
// open directory dialog
String newpath = getDirectory(fPathText.getText());
if (newpath != null) {
fPathText.setText(newpath);
fPathManager.setPath(newpath, SourceType.Custom);
}
testStatus();
}
});
return page;
}
/**
* Get the results from this dialog.
* <p>
* It will return a IPathManager with the selected path.
* </p>
* <p>
* This should only be called when <code>open()</code> returned <code>OK</code> (OK Button
* clicked). Otherwise canceled changes will be returned.
* </p>
*
* @return The IPathManager with the modified path.
*/
public AVRPathManager getResult() {
return fPathManager;
}
/**
* Change the source type and show the associated editor page.
*
* This method will also change the internally stored path to the selected source type.
* <p>
* The sourcetype is passed as a <code>String</code> (iso <code>SourceType</code>) as it
* comes directly from the Source Type combo widget.
* </p>
*
* @param type
*/
private void changeSourceType(String type) {
if (type.equals(SourceType.System.toString())) {
// System source
fPageBook.showPage(fSystemPage);
fPathManager.setPath(fPathManager.getSystemPath(false).toOSString(), SourceType.System);
}
if (type.equals(SourceType.Bundled.toString())) {
// Bundle source
fPageBook.showPage(fBundlePage);
// TODO: Bundle: load bundle id
updateStatus(new Status(IStatus.ERROR, AVRPlugin.PLUGIN_ID,
"Bundled toolchains not yet supported"));
return;
}
if (type.equals(SourceType.Custom.toString())) {
// Custom source
fPageBook.showPage(fCustomPage);
fPathManager.setPath(fPathText.getText(), SourceType.Custom);
}
// Update the status line for the new values
testStatus();
}
/**
* Update the status line for the current path / source.
*
* It shows
* <ul>
* <li>nothing if the path is valid and not empty </li>
* <li>a Warning if the path is empty, but still valid (optional paths)</li>
* <li>an Error if the path is invalid</li>
* </ul>
*/
private void testStatus() {
IStatus status = Status.OK_STATUS;
boolean empty = "".equals(fPathManager.getPath().toString());
boolean valid = fPathManager.isValid();
if (empty && valid) {
// warning only
status = new Status(IStatus.WARNING, AVRPlugin.PLUGIN_ID, "Optional path is empty");
}
if (!valid) {
// error
status = new Status(IStatus.ERROR, AVRPlugin.PLUGIN_ID, "Path is invalid");
}
super.updateStatus(status);
}
/**
* Helper that opens the directory chooser dialog.
*
* @param startingDirectory
* The directory the dialog will open in.
* @return File File or <code>null</code>.
*
*/
private String getDirectory(String startingDirectory) {
DirectoryDialog fileDialog = new DirectoryDialog(getShell(), SWT.OPEN);
if (startingDirectory != null) {
fileDialog.setFilterPath(startingDirectory);
}
String dir = fileDialog.open();
if (dir != null) {
dir = dir.trim();
if (dir.length() > 0) {
return dir;
}
}
return null;
}
}