/*******************************************************************************
* 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.jface.preference.FieldEditor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import de.innot.avreclipse.core.paths.AVRPath;
import de.innot.avreclipse.core.paths.AVRPathManager;
/**
* A custom field editor to edit all plugin paths.
*
* This can be used on a FieldEditorPreferencePage to manage the the current path settings.
*
* @author Thomas Holland
*
*/
public class AVRPathsFieldEditor extends FieldEditor {
// GUI Widgets
private Table fTable;
private Composite fButtons;
private Button fEditButton;
private Button fRescanButton;
private boolean fValid = true;
// The three columns
private static final int COLUMN_NAME = 0;
private static final int COLUMN_TYPE = 1;
private static final int COLUMN_PATH = 2;
// fonts and colors used
final Font fBoldFont = JFaceResources.getFontRegistry().getBold(
JFaceResources.DIALOG_FONT);
final Font fDialogFont = JFaceResources.getFontRegistry().get(
JFaceResources.DIALOG_FONT);
/**
* Handle selection events from the edit button.
*
* It will open a PathSettingDialog, where the currently selected path can be modified.
*/
private class ButtonSelectionListener implements SelectionListener {
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
public void widgetSelected(SelectionEvent e) {
// Get the selected item and get the associated path.
// open a PathSettingDialog to modify the path.
TableItem selected = fTable.getSelection()[0];
AVRPathManager path = (AVRPathManager) selected.getData();
if (e.getSource() == fEditButton) {
PathSettingDialog dialog = new PathSettingDialog(fTable.getShell(), path);
if (dialog.open() == Window.OK) {
// OK Button selected:
// get the modified Path, keep it and update this Editor
path = dialog.getResult();
}
} else if (e.getSource() == fRescanButton) {
// force a search for the current system path.
// This may take a while so we display a Wait cursor
final AVRPathManager finalpath = path;
BusyIndicator.showWhile(fTable.getDisplay(), new Runnable() {
public void run() {
finalpath.getSystemPath(true);
}
});
}
selected.setData(path);
updateTableItem(selected);
refreshValidState();
}
}
/**
* Handle selection events from the table.
*
* Once a TableItem has been selected, the Edit button is enabled
*
*/
private class TableSelectionListener implements SelectionListener {
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
public void widgetSelected(SelectionEvent e) {
// Enable the Edit button
fEditButton.setEnabled(true);
// Enable the rescan button of a system path item has been selected
TableItem selected = fTable.getSelection()[0];
AVRPathManager path = (AVRPathManager) selected.getData();
switch (path.getSourceType()) {
case System:
fRescanButton.setEnabled(true);
break;
default:
fRescanButton.setEnabled(false);
}
}
}
/**
* Constructor for the AVRPathsFieldEditor.
*
* Sets the preference name (unused) and the labeltext (also unused) to fixed values.
*/
public AVRPathsFieldEditor(Composite parent) {
super("avrpaths", "AVR Paths:", parent);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.preference.FieldEditor#adjustForNumColumns(int)
*/
@Override
protected void adjustForNumColumns(int numColumns) {
// Adjust the Layout for the given number of columns.
// The button will get one column, the table all other columns
GridData buttonsData = (GridData) fButtons.getLayoutData();
buttonsData.horizontalSpan = 1;
GridData tableData = (GridData) fTable.getLayoutData();
tableData.horizontalSpan = numColumns - 1;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.preference.FieldEditor#doFillIntoGrid(org.eclipse.swt.widgets.Composite,
* int)
*/
@Override
protected void doFillIntoGrid(Composite parent, int numColumns) {
// Create the Table for all paths
fTable = new Table(parent, SWT.SINGLE | SWT.BORDER | SWT.FULL_SELECTION);
GridData tableData = new GridData(GridData.FILL_BOTH);
tableData.horizontalSpan = numColumns - 1;
fTable.setLayoutData(tableData);
fTable.addSelectionListener(new TableSelectionListener());
TableColumn nameColumn = new TableColumn(fTable, SWT.LEFT, COLUMN_NAME);
TableColumn typeColumn = new TableColumn(fTable, SWT.LEFT, COLUMN_TYPE);
TableColumn pathColumn = new TableColumn(fTable, SWT.LEFT, COLUMN_PATH);
nameColumn.setText("Path to");
typeColumn.setText("Source");
pathColumn.setText("Current value");
fTable.setHeaderVisible(true);
// Creates the composite containing the button(s)
fButtons = new Composite(parent, SWT.NO_FOCUS);
GridData buttonsData = new GridData(GridData.END);
buttonsData.horizontalSpan = 1;
buttonsData.horizontalAlignment = SWT.FILL;
fButtons.setLayoutData(buttonsData);
FillLayout buttonsLayout = new FillLayout(SWT.VERTICAL);
buttonsLayout.spacing = 5;
fButtons.setLayout(buttonsLayout);
// Create the edit Button
fEditButton = new Button(fButtons, SWT.PUSH);
fEditButton.setText("Edit...");
fEditButton.addSelectionListener(new ButtonSelectionListener());
fEditButton.setEnabled(false);
// Create the rescan Button
fRescanButton = new Button(fButtons, SWT.PUSH);
fRescanButton.setText("Rescan");
fRescanButton.addSelectionListener(new ButtonSelectionListener());
fRescanButton.setEnabled(false);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.preference.FieldEditor#doLoad()
*/
@Override
protected void doLoad() {
// Get the list of all supported paths
AVRPath[] allpaths = AVRPath.values();
for (AVRPath current : allpaths) {
// Create a IPathManager for each path and store it
// within a new TableItem
AVRPathManager item = new AVRPathManager(current);
TableItem ti = new TableItem(fTable, 0);
ti.setData(item);
updateTableItem(ti);
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.preference.FieldEditor#doLoadDefault()
*/
@Override
protected void doLoadDefault() {
// Get all TableItems
TableItem[] allitems = fTable.getItems();
for (TableItem tableitem : allitems) {
// get the IPathManager for the item and set it to the default value
AVRPathManager path = (AVRPathManager) tableitem.getData();
path.setToDefault();
updateTableItem(tableitem);
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.preference.FieldEditor#doStore()
*/
@Override
protected void doStore() {
// Get all TableItems
TableItem[] allitems = fTable.getItems();
for (TableItem tableitem : allitems) {
// Get the IPathManager of the item and store its value to the
// persistent storage
AVRPathManager path = (AVRPathManager) tableitem.getData();
path.store();
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.preference.FieldEditor#store()
*/
@Override
public void store() {
// We need to override this method, because we don't access the
// PreferenceStore directly, but rather indirectly via the IPathManager
// interface. super.store() tried to use setToDefault on the
// PreferenceStore, which does not work here.
if (getPreferenceStore() == null) {
return;
}
doStore();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.preference.FieldEditor#getNumberOfControls()
*/
@Override
public int getNumberOfControls() {
// Table and Buttons
return 2;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.preference.FieldEditor#isValid()
*/
@Override
public boolean isValid() {
return fValid;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.preference.FieldEditor#refreshValidState()
*/
@Override
protected void refreshValidState() {
super.refreshValidState();
// Get all TableItems, extract their IPathManager and check
// if it is valid and not optional.
// If any one IPathManager is invalid, the
// valid boolean is set to false and an error message indicating
// the culprit is shown.
TableItem[] allitems = fTable.getItems();
boolean oldValid = fValid;
boolean newValid = true;
String invalidPath = null;
for (TableItem ti : allitems) {
AVRPathManager pathitem = (AVRPathManager) ti.getData();
if (!pathitem.isValid() && !pathitem.isOptional()) {
newValid = false;
invalidPath = pathitem.getName();
}
}
// Updates validity and error message.
fValid = newValid;
if (fValid == false) {
showErrorMessage("Path for '" + invalidPath + "' is not valid");
} else {
clearErrorMessage();
}
// Send some notifications.
if (newValid != oldValid) {
fireStateChanged(IS_VALID, oldValid, newValid);
}
}
/**
* Updates the visual of the given TableItem according to its IPathManager.
*
* @param item
* TableItem whose visual needs to be updated
*/
private void updateTableItem(TableItem item) {
AVRPathManager path = (AVRPathManager) item.getData();
// add warn / error icons if path is empty / invalid
boolean valid = path.isValid();
boolean optional = path.isOptional();
boolean empty = (path.getPath().isEmpty());
if (valid && !empty) {
// valid path
item.setImage((Image) null);
} else if ((valid && empty) || (!valid && optional)) {
// valid but empty path or invalid and optional path (use for optional paths)
item.setImage(PlatformUI.getWorkbench().getSharedImages().getImage(
ISharedImages.IMG_OBJS_WARN_TSK));
} else {
// Path is invalid
item.setImage(PlatformUI.getWorkbench().getSharedImages().getImage(
ISharedImages.IMG_OBJS_ERROR_TSK));
}
item.setText(COLUMN_NAME, path.getName());
item.setText(COLUMN_TYPE, path.getSourceType().toString());
item.setText(COLUMN_PATH, path.getPath().toOSString());
// Adjust color/font according to source type
switch (path.getSourceType()) {
case System:
item.setFont(COLUMN_TYPE, fDialogFont);
item.setFont(COLUMN_PATH, fDialogFont);
item.setForeground(COLUMN_PATH, fTable.getDisplay().getSystemColor(
SWT.COLOR_DARK_GRAY));
break;
case Bundled:
item.setFont(COLUMN_TYPE, fDialogFont);
item.setFont(COLUMN_PATH, fDialogFont);
item.setForeground(COLUMN_PATH, fTable.getDisplay().getSystemColor(
SWT.COLOR_DARK_GRAY));
break;
case Custom:
item.setFont(COLUMN_TYPE, fBoldFont);
item.setFont(COLUMN_PATH, fBoldFont);
item
.setForeground(COLUMN_PATH, fTable.getDisplay().getSystemColor(
SWT.COLOR_BLACK));
}
// Updates the table layout.
fTable.getColumn(COLUMN_NAME).pack();
fTable.getColumn(COLUMN_TYPE).pack();
fTable.getColumn(COLUMN_PATH).pack();
fTable.layout();
}
}