/*******************************************************************************
* Copyright (c) 2010 Martin Schnabel <mb0@mb0.org>.
* 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 org.axdt.asdoc.ui.preferences;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import org.axdt.asdoc.ui.AsdocUiActivator;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.StatusDialog;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.preference.FieldEditor;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CellLabelProvider;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnLayoutData;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Widget;
import com.google.common.collect.Lists;
public class DocTableFieldEditor extends FieldEditor {
private Composite baseComp;
private TableViewer tableViewer;
public DocTableFieldEditor(String name, String labelText, Composite comp) {
super(name, labelText, comp);
}
@Override
protected void adjustForNumColumns(int numColumns) {
GridData layoutData = (GridData) baseComp.getLayoutData();
layoutData.horizontalSpan = numColumns;
}
protected Composite createBaseComposite(Composite parent, int numColumns) {
Composite result = new Composite(parent,SWT.NONE);
GridData gd = new GridData(GridData.FILL_BOTH);
gd.horizontalSpan = numColumns;
result.setLayoutData(gd);
result.setLayout(new GridLayout(1,false));
return result;
}
protected Label createLabel(Composite parent) {
Label labelControl = getLabelControl(parent);
labelControl.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
return labelControl;
}
protected SashForm createSashForm(Composite parent) {
final SashForm splitComp = new SashForm(parent,SWT.NONE);
splitComp.setLayoutData(new GridData(GridData.FILL_BOTH));
splitComp.addControlListener(new ControlAdapter() {
@Override
public void controlResized(ControlEvent e) {
int width = splitComp.getBounds().width;
double percent = (width -100.0) / width;
int weight = (int)Math.round(percent*100);
splitComp.setWeights(new int[] {weight, 100 - weight});
}
});
return splitComp;
}
protected TableViewer createTableViewer(Composite parent) {
Composite tableComp = new Composite(parent,SWT.NONE);
tableComp.setLayout(new TableColumnLayout());
TableViewer tableViewer = new TableViewer(tableComp, SWT.MULTI|SWT.BORDER|SWT.FULL_SELECTION);
tableViewer.setContentProvider(new ArrayContentProvider());
tableViewer.getTable().setHeaderVisible(true);
tableViewer.getTable().setLinesVisible(true);
createTableViwerColumn(tableViewer,"Name",new ColumnLabelProvider(){
@Override
public String getText(Object element) {
if (element instanceof DocItem) {
DocItem item = (DocItem) element;
return item.name;
}
return super.getText(element);
}
}, new ColumnWeightData(1,50,true));
createTableViwerColumn(tableViewer,"Url",new ColumnLabelProvider(){
@Override
public String getText(Object element) {
if (element instanceof DocItem) {
DocItem item = (DocItem) element;
return item.url;
}
return super.getText(element);
}
}, new ColumnWeightData(5,250,true));
return tableViewer;
}
private void createTableViwerColumn(TableViewer tableViewer2, String string, CellLabelProvider labelProvider, ColumnLayoutData layoutData) {
TableViewerColumn viewerNameColumn = new TableViewerColumn(tableViewer2, SWT.NONE);
viewerNameColumn.getColumn().setText(string);
viewerNameColumn.setLabelProvider(labelProvider);
Layout layout = tableViewer2.getControl().getParent().getLayout();
if (layout instanceof TableColumnLayout) {
((TableColumnLayout) layout).setColumnData(viewerNameColumn.getColumn(), layoutData);
}
}
protected Button createButton(Composite parent, String label, SelectionListener listener) {
Button button = new Button(parent, SWT.PUSH);
button.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
button.setText(label);
button.addSelectionListener(listener);
return button;
}
protected Composite createButtons(Composite parent) {
Composite buttonsComp = new Composite(parent,SWT.NONE);
buttonsComp.setLayout(new GridLayout(1,true));
createButton(buttonsComp, "Add", new SelectionAdapter(){
@Override
public void widgetSelected(SelectionEvent e) {
DocItem item = new DocItem("New","");
boolean doAdd = doEdit(item);
if (doAdd) {
Object[] input = (Object[]) tableViewer.getInput();
List<Object> list = new ArrayList<Object>();
list.addAll(Arrays.asList(input));
list.add(item);
tableViewer.setInput(list.toArray());
}
}
});
createButton(buttonsComp,"Remove",new SelectionAdapter(){
@Override
public void widgetSelected(SelectionEvent e) {
IStructuredSelection selection = (IStructuredSelection) tableViewer.getSelection();
Object firstElement = selection.getFirstElement();
Object[] input = (Object[]) tableViewer.getInput();
List<Object> list = new ArrayList<Object>();
list.addAll(Arrays.asList(input));
list.remove(firstElement);
tableViewer.setInput(list.toArray());
}
});
createButton(buttonsComp,"Edit",new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
IStructuredSelection selection = (IStructuredSelection) tableViewer.getSelection();
Object firstElement = selection.getFirstElement();
if (firstElement instanceof DocItem) {
doEdit((DocItem)firstElement);
tableViewer.refresh();
}
}
});
return buttonsComp;
}
protected boolean doEdit(DocItem item) {
EditDialog dialog = new EditDialog(tableViewer.getControl().getShell(),item.name,item.url);
if (dialog.open() == Window.OK) {
IStatus status = dialog.getStatus();
if (status.getCode() == IStatus.OK) {
item.name = dialog.getNameText();
item.url = dialog.getUrlText();
return true;
}
}
return false;
}
@Override
protected void doFillIntoGrid(Composite parent, int numColumns) {
baseComp = createBaseComposite(parent, numColumns);
createLabel(baseComp);
SashForm sashForm = createSashForm(baseComp);
tableViewer = createTableViewer(sashForm);
createButtons(sashForm);
}
@Override
protected void doLoad() {
if (tableViewer != null) {
String value = getPreferenceStore().getString(getPreferenceName());
Object[] objects = deserializeValue(value);
tableViewer.setInput(objects);
}
}
@Override
protected void doLoadDefault() {
if (tableViewer != null) {
String value = getPreferenceStore().getDefaultString(getPreferenceName());
Object[] objects = deserializeValue(value);
tableViewer.setInput(objects);
}
}
protected static Object[] deserializeValue(String value) {
List<DocItem> list = deserializeList(value);
return list.toArray();
}
protected static List<DocItem> deserializeList(String value) {
List<DocItem> list = Lists.newArrayList();
if (value == null) return list;
value = value.trim();
if (value.length() == 0) return list;
if (Pattern.matches("('[^']*')([,;]('[^']*'))*", value)) {
// rows
for (String part:value.split(";")) {
// items
String[] items = part.split(",");
if (items.length == 0) continue;
String item = items[0].substring(1, items[0].length()-1);
if (items.length == 1) {
list.add(new DocItem("New",item));
} else if (items.length == 2) {
String url = items[1].substring(1, items[1].length()-1);
list.add(new DocItem(item,url));
}
}
} else {
// try to reconstruct from old schema
for (String part:value.split(" ;,")) {
list.add(new DocItem("New",part));
}
}
return list;
}
protected static String serializeValue(Object[] items) {
StringBuilder value = new StringBuilder();
for (Object item:items){
if (value.length()!=0)
value.append(";");
value.append(item.toString());
}
return value.toString();
}
@Override
protected void doStore() {
Object[] items = (Object[])tableViewer.getInput();
getPreferenceStore().setValue(getPreferenceName(), serializeValue(items));
}
@Override
public int getNumberOfControls() {
return 1;
}
public static class DocItem {
public String url;
public String name;
public IStatus status = null;
public String asdocUrl = null;
public DocItem(String name, String url) {
this.name = name;
this.url = url;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append('\'').append(name).append('\'');
builder.append(',');
builder.append('\'').append(url).append('\'');
return builder.toString();
}
}
public static class EditDialog extends StatusDialog {
private Text nameText;
private Text urlText;
private String name;
private String url;
public EditDialog(Shell parent, String initialName, String initialUrl) {
super(parent);
this.name = initialName;
this.url = initialUrl;
}
public String getUrlText() {
return url;
}
public String getNameText() {
return name;
}
@Override
protected Control createDialogArea(Composite ancestor) {
Composite parent= new Composite(ancestor, SWT.NONE);
parent.setLayout(new GridLayout(2,false));
ModifyListener listener= new ModifyListener() {
public void modifyText(ModifyEvent e) {
doTextChanged(e.widget);
}
};
Label description = createLabel(parent, "Please add a name and a valid url to an asdoc folder.");
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 2;
description.setLayoutData(gd);
createLabel(parent, "Name");
nameText = createText(parent, name);
nameText.addModifyListener(listener);
createLabel(parent, "Url");
urlText = createText(parent, url);
urlText.addModifyListener(listener);
return parent;
}
@Override
public void create() {
super.create();
updateStatus(checkValid());
}
protected void doTextChanged(Widget widget) {
updateStatus(checkValid());
}
public IStatus checkValid() {
if (nameText == null || urlText == null)
return EditDialogStatus.INVALID_STATUS;
name = nameText.getText().trim();
url = urlText.getText().trim();
if (name == null || url == null)
return EditDialogStatus.INVALID_STATUS;
if (name.length() == 0)
return EditDialogStatus.getInvalidStatus("name must be set");
if (url.length() == 0)
return EditDialogStatus.getInvalidStatus("url must be set");
try {
URI uri = URI.create(url);
if (!uri.isAbsolute())
return EditDialogStatus.getInvalidStatus("url must be absolute");
} catch (Exception e) {
return EditDialogStatus.getInvalidStatus("url must be valid");
}
return EditDialogStatus.OK_STATUS;
}
private Label createLabel(Composite parent, String string) {
Label label = new Label(parent, SWT.NONE);
label.setText(string);
label.setLayoutData(new GridData());
return label;
}
private Text createText(Composite parent, String string) {
Text text= new Text(parent, SWT.BORDER);
text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
text.setText(string);
return text;
}
}
public static class EditDialogStatus extends Status {
public static final IStatus INVALID_STATUS = getInvalidStatus("Error");
public EditDialogStatus(int severity, String pluginId,
int code, String message, Throwable exception) {
super(severity, pluginId, code, message, exception);
}
public static IStatus getInvalidStatus(String message) {
return getInvalidStatus(message, null);
}
public static IStatus getInvalidStatus(String message, Throwable exception) {
return new EditDialogStatus(ERROR, AsdocUiActivator.PLUGIN_ID, ERROR, message, exception);
}
}
}