/*
PathSelector.java
(c) 2012-2015 Edward Swartz
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 v9t9.gui.client.swt;
import java.net.URISyntaxException;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableColorProvider;
import org.eclipse.jface.viewers.ITableFontProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.MenuDetectEvent;
import org.eclipse.swt.events.MenuDetectListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.ejs.gui.common.SwtUtils;
import v9t9.common.files.IPathFileLocator;
import ejs.base.properties.IProperty;
import ejs.base.properties.IPropertyListener;
/**
* This composite allows editing of paths by adding,
* removing, reordering.
* @author ejs
*
*/
public class PathSelector extends Composite {
private final IProperty property;
private final SwtWindow window;
private final String pathLabel;
private TableViewer viewer;
private Composite buttons;
private Button removeButton;
private IPropertyListener propertyListener;
private final IPathFileLocator locator;
public PathSelector(Composite parent, IPathFileLocator locator, SwtWindow window, String pathLabel, IProperty property) {
super(parent, SWT.BORDER);
this.locator = locator;
this.window = window;
this.pathLabel = pathLabel;
this.property = property;
GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(false).applyTo(this);
// left side: the list
createListTable();
// right side: buttons
createButtons();
propertyListener = new IPropertyListener() {
@Override
public void propertyChanged(IProperty property) {
if (!isDisposed()) {
getDisplay().asyncExec(new Runnable() {
public void run() {
viewer.refresh();
}
});
}
}
};
property.addListener(propertyListener);
}
class PathLabelProvider extends LabelProvider implements ITableFontProvider, ITableColorProvider {
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.LabelProvider#getText(java.lang.Object)
*/
@Override
public String getText(Object element) {
return super.getText(element) + (!pathExists(element) ? " (not found)" : "");
}
protected boolean pathExists(Object element) {
boolean found = true;
if (element instanceof String) {
try {
found = locator.exists(locator.createURI(element.toString()));
} catch (URISyntaxException e) {
found = false;
}
}
return found;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITableFontProvider#getFont(java.lang.Object, int)
*/
@Override
public Font getFont(Object element, int columnIndex) {
boolean found = pathExists(element);
return found ? null : JFaceResources.getFontRegistry().getItalic(JFaceResources.DEFAULT_FONT);
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITableColorProvider#getBackground(java.lang.Object, int)
*/
@Override
public Color getBackground(Object element, int columnIndex) {
return null;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITableColorProvider#getForeground(java.lang.Object, int)
*/
@Override
public Color getForeground(Object element, int columnIndex) {
boolean found = pathExists(element);
return found ? null : getDisplay().getSystemColor(SWT.COLOR_TITLE_INACTIVE_FOREGROUND);
}
}
/**
*
*/
private void createListTable() {
viewer = new TableViewer(this, SWT.FULL_SELECTION + SWT.MULTI);
final Table table = viewer.getTable();
GridDataFactory.fillDefaults().grab(true, true).applyTo(table);
table.setHeaderVisible(true);
table.setLinesVisible(true);
final TableColumn column = new TableColumn(table, SWT.LEFT);
column.setText("Search Locations");
addControlListener(new ControlAdapter() {
@Override
public void controlResized(ControlEvent e) {
column.pack();
}
});
table.addMenuDetectListener(new MenuDetectListener() {
@Override
public void menuDetected(MenuDetectEvent e) {
final Item item = table.getItem(
viewer.getControl().toControl(new Point(e.x, e.y))
);
if (item == null)
return;
Menu menu = new Menu(viewer.getControl());
if (item.getData() instanceof String) {
final MenuItem copyItem;
copyItem = new MenuItem(menu, SWT.NONE);
copyItem.setText("Copy");
copyItem.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
Clipboard c = new Clipboard(getDisplay());
c.setContents(new Object[] { item.getData() }, new Transfer[] { TextTransfer.getInstance() });
}
});
}
SwtUtils.runMenu(null, e.x, e.y, menu);
}
});
viewer.addOpenListener(new IOpenListener() {
@Override
public void open(OpenEvent event) {
Object oldDir = ((IStructuredSelection) event.getSelection()).getFirstElement();
String dir = window.openDirectorySelectionDialog("Modify " + pathLabel, oldDir.toString());
if (dir == null || dir.equals(oldDir))
return;
int index = property.getList().indexOf(oldDir);
if (index >= 0)
property.getList().set(index, dir);
else {
property.getList().remove(oldDir);
property.getList().add(dir);
}
viewer.refresh();
firePropertyChangeForOthers();
}
});
viewer.setLabelProvider(new PathLabelProvider());
viewer.setContentProvider(new ArrayContentProvider());
viewer.setInput(property.getList());
}
/**
*
*/
private void createButtons() {
buttons = new Composite(this, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(1).margins(3, 3).applyTo(buttons);
GridDataFactory.fillDefaults().grab(false, true).minSize(-1, 64).applyTo(buttons);
final Button add = new Button(buttons, SWT.PUSH);
GridDataFactory.fillDefaults().grab(true, false).applyTo(add);
add.setText("Add...");
add.addSelectionListener(new SelectionAdapter() {
String lastDirectory;
@Override
public void widgetSelected(SelectionEvent e) {
IStructuredSelection sel = (IStructuredSelection) viewer.getSelection();
Object obj = sel.getFirstElement();
if (obj instanceof String) {
lastDirectory = (String) obj;
} else if (lastDirectory == null) {
if (!property.getList().isEmpty()) {
lastDirectory = (String) property.getList().get(0);
} else {
lastDirectory = ".";
}
}
String dir = window.openDirectorySelectionDialog("Add " + pathLabel, lastDirectory);
if (dir == null)
return;
property.getList().add(dir);
viewer.add(dir);
lastDirectory = dir;
firePropertyChangeForOthers();
}
});
removeButton = new Button(buttons, SWT.PUSH);
GridDataFactory.fillDefaults().grab(true, false).applyTo(removeButton);
removeButton.setText("Remove");
removeButton.setEnabled(false);
removeButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (!viewer.getSelection().isEmpty()) {
for (Object obj : ((IStructuredSelection) viewer.getSelection()).toArray()) {
property.getList().remove(obj);
viewer.remove(obj);
}
firePropertyChangeForOthers();
}
}
});
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
removeButton.setEnabled(!event.getSelection().isEmpty());
}
});
final Button refresh = new Button(buttons, SWT.PUSH);
GridDataFactory.fillDefaults().grab(true, false).applyTo(refresh);
refresh.setText("Rescan");
refresh.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
property.firePropertyChange();
}
});
}
/**
*
*/
protected void firePropertyChangeForOthers() {
property.removeListener(propertyListener);
property.firePropertyChange();
property.addListener(propertyListener);
}
}