/*******************************************************************************
* Copyright (c) 2009, 2017 xored software, Inc. 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:
* xored software, Inc. - initial API and Implementation (Alex Panchenko)
*******************************************************************************/
package org.eclipse.dltk.tcl.internal.ui.documentation;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.dltk.tcl.internal.ui.TclUI;
import org.eclipse.dltk.tcl.ui.manpages.Documentation;
import org.eclipse.dltk.tcl.ui.manpages.ManPageFinder;
import org.eclipse.dltk.tcl.ui.manpages.ManPageFolder;
import org.eclipse.dltk.tcl.ui.manpages.ManPageResource;
import org.eclipse.dltk.tcl.ui.manpages.ManpagesFactory;
import org.eclipse.dltk.ui.DLTKPluginImages;
import org.eclipse.dltk.ui.DLTKUIPlugin;
import org.eclipse.dltk.ui.dialogs.StatusInfo;
import org.eclipse.dltk.ui.dialogs.TimeTriggeredProgressMonitorDialog;
import org.eclipse.emf.common.util.BasicEMap;
import org.eclipse.emf.common.util.EMap;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.dialogs.StatusDialog;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.SWT;
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.graphics.Image;
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.DirectoryDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
public class ManPagesLocationsDialog extends StatusDialog
implements ModifyListener {
private final boolean isNew;
private final ManPageResource documentations;
protected final Documentation documentation;
private final Documentation input;
/**
* @param shell
* @param documentation
*/
public ManPagesLocationsDialog(Shell shell, ManPageResource documentations,
Documentation documentation) {
super(shell);
this.documentations = documentations;
this.input = documentation;
this.isNew = documentation == null;
this.documentation = documentation != null
? (Documentation) EcoreUtil.copy(documentation)
: newDocumentation();
setTitle(isNew ? ManPagesMessages.ManPagesLocationsDialog_AddTtile
: ManPagesMessages.ManPagesLocationsDialog_EditTitle);
setShellStyle(getShellStyle() | SWT.RESIZE);
}
private static Documentation newDocumentation() {
final Documentation value = ManpagesFactory.eINSTANCE
.createDocumentation();
value.setId(EcoreUtil.generateUUID());
value.setName(""); //$NON-NLS-1$
return value;
}
/**
* @return
*/
public Documentation getResult() {
return documentation;
}
private Text nameField;
private TreeViewer pathViewer;
private Button addButton;
private Button removeButton;
@Override
protected Control createDialogArea(Composite parent) {
final Composite dialogArea = (Composite) super.createDialogArea(parent);
final Composite content = new Composite(dialogArea, SWT.NONE);
content.setLayoutData(new GridData(GridData.FILL_BOTH));
content.setLayout(new GridLayout(3, false));
new Label(content, SWT.NONE)
.setText(ManPagesMessages.ManPagesLocationsDialog_Name);
nameField = new Text(content, SWT.BORDER);
final GridData nameGD = new GridData(GridData.FILL_HORIZONTAL);
nameGD.horizontalSpan = 2;
nameField.setLayoutData(nameGD);
nameField.addModifyListener(this);
final Label pathLabel = new Label(content, SWT.NONE);
pathLabel.setText(ManPagesMessages.ManPagesLocationsDialog_Paths);
pathLabel.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING
| GridData.VERTICAL_ALIGN_BEGINNING));
final Composite pathComp = new Composite(content, SWT.NONE);
pathComp.setLayoutData(new GridData(GridData.FILL_BOTH));
final GridLayout pathLayout = new GridLayout(2, false);
pathLayout.marginWidth = pathLayout.marginHeight = 0;
pathComp.setLayout(pathLayout);
pathViewer = new TreeViewer(pathComp);
pathViewer.setContentProvider(new FolderContentProvider());
pathViewer.setLabelProvider(new FolderLabelProvider());
pathViewer.setComparator(new ViewerComparator());
final GridData pathGD = new GridData(GridData.FILL_BOTH);
pathGD.heightHint = convertHeightInCharsToPixels(16);
pathGD.widthHint = convertWidthInCharsToPixels(64);
pathViewer.getControl().setLayoutData(pathGD);
pathViewer.addSelectionChangedListener(event -> pathSelectionChanged());
final Composite buttonComp = new Composite(pathComp, SWT.NONE);
final GridLayout buttonLayout = new GridLayout();
buttonLayout.marginHeight = buttonLayout.marginWidth = 0;
buttonComp.setLayout(buttonLayout);
buttonComp.setLayoutData(new GridData(GridData.FILL_VERTICAL));
addButton = new Button(buttonComp, SWT.PUSH);
ManPagesLocationsBlock.setButtonLayoutData(addButton);
addButton.setText(ManPagesMessages.ManPagesLocationsDialog_AddButton);
addButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
doAdd();
}
});
removeButton = new Button(buttonComp, SWT.PUSH);
ManPagesLocationsBlock.setButtonLayoutData(removeButton);
removeButton
.setText(ManPagesMessages.ManPagesLocationsDialog_RemoveButton);
removeButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
final IStructuredSelection selection = getSelection();
if (canRemove(selection)) {
doRemove(selection);
}
}
});
//
getData(documentation);
//
return dialogArea;
}
static class FolderContentProvider implements ITreeContentProvider {
@Override
public Object[] getChildren(Object parentElement) {
if (parentElement instanceof ManPageFolder) {
final ManPageFolder folder = (ManPageFolder) parentElement;
final EMap<String, String> keywords = folder.getKeywords();
return keywords.toArray(new Map.Entry[keywords.size()]);
}
return new Object[0];
}
@Override
public Object getParent(Object element) {
if (element instanceof EObject) {
return ((EObject) element).eContainer();
} else {
return null;
}
}
@Override
public boolean hasChildren(Object element) {
if (element instanceof ManPageFolder) {
final ManPageFolder folder = (ManPageFolder) element;
return !folder.getKeywords().isEmpty();
}
return false;
}
@Override
public Object[] getElements(Object inputElement) {
if (inputElement instanceof Documentation) {
final Documentation doc = (Documentation) inputElement;
final List<ManPageFolder> folders = doc.getFolders();
return folders.toArray(new Object[folders.size()]);
}
return new Object[0];
}
@Override
public void dispose() {
}
@Override
public void inputChanged(Viewer viewer, Object oldInput,
Object newInput) {
}
}
static class FolderLabelProvider extends LabelProvider {
@Override
public String getText(Object element) {
if (element instanceof ManPageFolder) {
return ((ManPageFolder) element).getPath();
} else if (element instanceof EObject
&& element instanceof BasicEMap.Entry<?, ?>) {
@SuppressWarnings("unchecked")
final BasicEMap.Entry<String, String> entry = (BasicEMap.Entry<String, String>) element;
return entry.getKey() + " (" + entry.getValue() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
}
return super.getText(element);
}
@Override
public Image getImage(Object element) {
if (element instanceof ManPageFolder) {
return DLTKPluginImages.get(DLTKPluginImages.IMG_OBJS_LIBRARY);
} else {
return DLTKUIPlugin.getImageDescriptorRegistry()
.get(DLTKPluginImages.DESC_OBJS_INFO_OBJ);
}
}
}
protected void doAdd() {
final DirectoryDialog dialog = new DirectoryDialog(getShell());
dialog.setMessage(ManPagesMessages.ManPagesLocationsDialog_6);
final String result = dialog.open();
if (result != null) {
final File file = new File(result);
if (file.isDirectory()) {
ProgressMonitorDialog dialog2 = new TimeTriggeredProgressMonitorDialog(
null, 500);
try {
dialog2.run(true, true, monitor -> {
monitor.beginTask(
ManPagesMessages.ManPagesLocationsDialog_7, 1);
final ManPageFinder finder = new ManPageFinder();
finder.find(documentation, file);
monitor.done();
});
} catch (InvocationTargetException e) {
TclUI.error(e);
} catch (InterruptedException e) {
// ignore
}
pathViewer.refresh();
updateStatus();
}
}
}
protected void doRemove(IStructuredSelection selection) {
for (Iterator<?> i = selection.iterator(); i.hasNext();) {
final Object obj = i.next();
if (obj instanceof ManPageFolder) {
EcoreUtil.remove((EObject) obj);
}
}
pathViewer.refresh();
updateStatus();
}
protected void pathSelectionChanged() {
final IStructuredSelection selection = getSelection();
removeButton.setEnabled(canRemove(selection));
}
/**
* @param doc
*/
private void getData(Documentation doc) {
++busyCounter;
try {
nameField.setText(doc.getName());
pathViewer.setInput(documentation);
} finally {
--busyCounter;
}
}
private void setData(Documentation doc) {
doc.setName(nameField.getText().trim());
}
@Override
protected void okPressed() {
setData(documentation);
if (isNew) {
documentations.getContents().add(documentation);
} else {
input.setName(documentation.getName());
// TODO smart update
input.getFolders().clear();
input.getFolders().addAll(documentation.getFolders());
}
super.okPressed();
}
private int busyCounter = 0;
@Override
public void modifyText(ModifyEvent e) {
if (busyCounter > 0) {
return;
}
updateStatus();
}
private void updateStatus() {
updateStatus(validate());
}
private IStatus validate() {
if (nameField.getText().trim().length() == 0) {
return new StatusInfo(IStatus.ERROR,
ManPagesMessages.ManPagesLocationsDialog_ErrorEmptyName);
}
// TODO validate name uniqueness
if (documentation.getFolders().isEmpty()) {
return new StatusInfo(IStatus.ERROR,
ManPagesMessages.ManPagesLocationsDialog_ErrorNoFolders);
}
return StatusInfo.OK_STATUS;
}
protected IStructuredSelection getSelection() {
return (IStructuredSelection) pathViewer.getSelection();
}
protected boolean canRemove(IStructuredSelection selection) {
if (selection.isEmpty()) {
return false;
}
for (Iterator<?> i = selection.iterator(); i.hasNext();) {
final Object obj = i.next();
if (!(obj instanceof ManPageFolder)) {
return false;
}
}
return true;
}
}