package org.xmind.ui.internal.views;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.util.OpenStrategy;
import org.eclipse.jface.viewers.IBaseLabelProvider;
import org.eclipse.jface.viewers.IElementComparer;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.widgets.Hyperlink;
import org.xmind.gef.IGraphicalViewer;
import org.xmind.gef.IViewer;
import org.xmind.gef.part.IGraphicalPart;
import org.xmind.gef.part.IPart;
import org.xmind.gef.service.IRevealService;
import org.xmind.gef.service.IRevealServiceListener;
import org.xmind.gef.service.RevealEvent;
import org.xmind.gef.service.ZoomingAndPanningRevealService;
import org.xmind.gef.ui.editor.IGraphicalEditor;
import org.xmind.gef.ui.editor.IGraphicalEditorPage;
public class ContentListViewer extends StructuredViewer {
private class CenteredRevealHelper implements IRevealServiceListener {
private ZoomingAndPanningRevealService service;
private boolean oldCentered;
public CenteredRevealHelper(IViewer viewer) {
Object service = viewer.getService(IRevealService.class);
if (service != null
&& service instanceof ZoomingAndPanningRevealService) {
this.service = (ZoomingAndPanningRevealService) service;
this.oldCentered = this.service.isCentered();
} else {
this.service = null;
this.oldCentered = false;
}
}
public void start(IGraphicalPart part) {
if (this.service != null) {
this.service.setCentered(true);
this.service.reveal(new StructuredSelection(part));
this.service.addRevealServiceListener(this);
}
}
public void revealingStarted(RevealEvent event) {
}
public void revealingCanceled(RevealEvent event) {
restore();
}
public void revealingFinished(RevealEvent event) {
restore();
}
void restore() {
this.service.removeRevealServiceListener(this);
this.service.setCentered(this.oldCentered);
}
}
protected static class ContentItem {
private ContentListViewer listViewer;
private Object data;
private Composite bar;
private Label imageLabel;
private Label textLabel;
private Hyperlink hyperlink;
public ContentItem(ContentListViewer listViewer, Composite parent) {
this.listViewer = listViewer;
bar = new Composite(parent, SWT.NONE);
bar.setBackground(parent.getBackground());
bar.setData(this);
// GridLayoutFactory.fillDefaults().numColumns(3)
// .extendedMargins(5, 5, 1, 1).applyTo(bar);
imageLabel = new Label(bar, SWT.NONE);
imageLabel.setImage(null);
imageLabel.setBackground(bar.getBackground());
GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER)
.applyTo(imageLabel);
textLabel = new Label(bar, SWT.NONE);
textLabel.setText(""); //$NON-NLS-1$
textLabel.setBackground(bar.getBackground());
GridDataFactory.fillDefaults().grab(false, false)
.align(SWT.FILL, SWT.CENTER).applyTo(textLabel);
hyperlink = new Hyperlink(bar, SWT.NONE);
hyperlink.setText(""); //$NON-NLS-1$
hyperlink.setBackground(bar.getBackground());
hyperlink.setForeground(Display.getCurrent().getSystemColor(
SWT.COLOR_BLUE));
hyperlink.setUnderlined(true);
GridDataFactory.fillDefaults().grab(true, false)
.align(SWT.FILL, SWT.CENTER).applyTo(hyperlink);
hyperlink.addHyperlinkListener(new HyperlinkAdapter() {
public void linkActivated(HyperlinkEvent e) {
try {
PlatformUI.getWorkbench().getBrowserSupport()
.getExternalBrowser()
.openURL(new URL(getCompleteURL(e.getLabel())));
} catch (Exception exception) {
exception.printStackTrace();
}
}
});
addControlListeners();
}
protected String getCompleteURL(String label) {
if (!label.startsWith("http://") && !label.startsWith("https://")) //$NON-NLS-1$ //$NON-NLS-2$
return "http://" + label; //$NON-NLS-1$
return label;
}
protected void selectTopic(Event event) {
getListViewer().getControl().setFocus();
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public ContentListViewer getListViewer() {
return listViewer;
}
public Control getControl() {
return bar;
}
protected Composite getBarComposite() {
return bar;
}
public String getText() {
return textLabel.getText();
}
public void setText(String text) {
textLabel.setText(text);
}
public Image getImage() {
return imageLabel.getImage();
}
public void setImage(Image image) {
imageLabel.setImage(image);
}
public String getHyperink() {
return hyperlink.getText();
}
public void setHyperlink(String link) {
if (link == null) {
hyperlink.dispose();
GridLayoutFactory.fillDefaults().numColumns(2)
.extendedMargins(5, 5, 1, 1).applyTo(bar);
} else {
hyperlink.setText(link);
GridLayoutFactory.fillDefaults().numColumns(3)
.extendedMargins(5, 5, 1, 1).applyTo(bar);
}
}
protected void addControlListeners() {
Listener listener = new Listener() {
public void handleEvent(Event event) {
int type = event.type;
switch (type) {
case SWT.MouseExit:
userExit(event);
break;
case SWT.MouseDoubleClick:
if (OpenStrategy.getOpenMethod() == OpenStrategy.DOUBLE_CLICK) {
userOpen(event);
}
break;
case SWT.MouseMove:
userSelect(event);
break;
case SWT.MouseDown:
userSelect(event);
break;
}
}
};
bar.addListener(SWT.MouseDoubleClick, listener);
bar.addListener(SWT.MouseMove, listener);
bar.addListener(SWT.MouseExit, listener);
bar.addListener(SWT.MouseDown, listener);
imageLabel.addListener(SWT.MouseDoubleClick, listener);
imageLabel.addListener(SWT.MouseMove, listener);
imageLabel.addListener(SWT.MouseExit, listener);
imageLabel.addListener(SWT.MouseDown, listener);
textLabel.addListener(SWT.MouseDoubleClick, listener);
textLabel.addListener(SWT.MouseMove, listener);
textLabel.addListener(SWT.MouseExit, listener);
textLabel.addListener(SWT.MouseDown, listener);
}
protected void userOpen(Event e) {
getListViewer().reveal(data);
}
protected void userSelect(Event e) {
bar.redraw();
textLabel.redraw();
// bar.setBackground(getSelectionBackground());
imageLabel.setBackground(getSelectionBackground());
textLabel.setBackground(getSelectionBackground());
}
protected void userExit(Event event) {
bar.redraw();
textLabel.redraw();
Color background = bar.getParent().getBackground();
bar.setBackground(background);
imageLabel.setBackground(background);
textLabel.setBackground(background);
}
public void dispose() {
bar.dispose();
}
public boolean isDisposed() {
return bar.isDisposed();
}
}
private static Color selectionBackground = null;
public static final String SEP = "[topic+link]"; //$NON-NLS-1$
protected static Color getSelectionBackground() {
if (selectionBackground == null) {
selectionBackground = Display.getCurrent().getSystemColor(
SWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT);
}
return selectionBackground;
}
private Composite list;
private List<Object> listMap = new ArrayList<Object>();
private List<ContentItem> items = new ArrayList<ContentItem>();
public ContentListViewer(Composite parent, int style) {
list = new Composite(parent, style) {
@Override
public boolean setFocus() {
return super.setFocus();
}
@Override
public Point computeSize(int wHint, int hHint, boolean changed) {
Point size;
if (getItemCount() == 0) {
size = new Point(0, 0);
if (wHint != SWT.DEFAULT)
size.x = wHint;
if (hHint != SWT.DEFAULT)
size.y = hHint;
Rectangle trim = computeTrim(0, 0, size.x, size.y);
size = new Point(trim.width, trim.height);
} else {
size = super.computeSize(wHint, hHint, changed);
}
return size;
}
};
list.setTabList(new Control[0]);
list.setBackground(parent.getBackground());
GridLayoutFactory.fillDefaults().spacing(0, 0).applyTo(list);
list.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
handleDispose(e);
}
});
}
public int getItemCount() {
return listGetItemCount();
}
protected int listGetItemCount() {
return items.size();
}
protected ContentItem listAdd(Image image, String text, Object data,
int index) {
ContentItem newItem = new ContentItem(this, list);
GridDataFactory.fillDefaults().grab(true, false)
.applyTo(newItem.getControl());
setItem(image, text, data, newItem);
list.layout();
if (index < 0 || index >= listGetItemCount()) {
items.add(newItem);
} else {
ContentItem oldItem = items.get(index);
items.add(index, newItem);
newItem.getControl().moveAbove(oldItem.getControl());
}
return newItem;
}
protected ContentItem listRemove(int index) {
if (index < 0 || index >= listGetItemCount())
return null;
ContentItem item = items.remove(index);
if (item != null)
item.dispose();
return item;
}
protected void listRemoveAll() {
for (ContentItem item : items)
item.dispose();
items.clear();
}
protected void listSetItem(Image image, String text, Object data, int index) {
if (index < 0 || index >= listGetItemCount())
return;
ContentItem item = items.get(index);
setItem(image, text, data, item);
}
private void setItem(Image image, String text, Object data, ContentItem item) {
String content = null;
String link = null;
if (text.contains(SEP)) {
int index = text.indexOf(SEP);
content = text.substring(0, index);
link = text.substring(index + SEP.length(), text.length());
} else {
content = text;
}
if (!item.isDisposed()) {
item.setImage(image);
item.setText(content);
item.setHyperlink(link);
item.setData(data);
}
}
protected int getElementIndex(Object element) {
IElementComparer comparer = getComparer();
if (comparer == null) {
return listMap.indexOf(element);
}
int size = listMap.size();
for (int i = 0; i < size; i++) {
if (comparer.equals(element, listMap.get(i)))
return i;
}
return -1;
}
public Object getElementAt(int index) {
if (index >= 0 && index < listMap.size())
return listMap.get(index);
return null;
}
public int indexForElement(Object element) {
ViewerComparator comparator = getComparator();
if (comparator == null) {
return listGetItemCount();
}
int count = listGetItemCount();
int min = 0, max = count - 1;
while (min <= max) {
int mid = (min + max) / 2;
Object data = listMap.get(mid);
int compare = comparator.compare(this, data, element);
if (compare == 0) {
// find first item > element
while (compare == 0) {
++mid;
if (mid >= count) {
break;
}
data = listMap.get(mid);
compare = comparator.compare(this, data, element);
}
return mid;
}
if (compare < 0) {
min = mid + 1;
} else {
max = mid - 1;
}
}
return min;
}
public void inputChanged(Object input, Object oldInput) {
listMap.clear();
Object[] children = getSortedChildren(getRoot());
int size = children.length;
listRemoveAll();
for (int i = 0; i < size; i++) {
Object el = children[i];
Image image = getImage((ILabelProvider) getLabelProvider(), el);
String text = getLabelProviderText(
(ILabelProvider) getLabelProvider(), el);
ContentItem item = listAdd(image, text, el, -1);
listMap.add(el);
mapElement(el, item.getControl());
}
}
public IBaseLabelProvider getLabelProvider() {
return super.getLabelProvider();
}
@Override
public void setLabelProvider(IBaseLabelProvider labelProvider) {
Assert.isTrue(labelProvider instanceof ILabelProvider);
super.setLabelProvider(labelProvider);
}
public void remove(Object element) {
remove(new Object[] { element });
}
public void remove(final Object[] elements) {
assertElementsNotNull(elements);
if (elements.length == 0)
return;
preservingSelection(new Runnable() {
public void run() {
internalRemove(elements);
}
});
}
private void internalRemove(final Object[] elements) {
Object input = getInput();
for (int i = 0; i < elements.length; ++i) {
if (equals(elements[i], input)) {
setInput(null);
return;
}
int ix = getElementIndex(elements[i]);
if (ix >= 0) {
ContentItem item = listRemove(ix);
listMap.remove(ix);
unmapElement(elements[i], item.getControl());
}
}
}
@Override
protected Widget doFindInputItem(Object element) {
if (element != null && equals(element, getRoot())) {
return getControl();
}
return null;
}
@Override
protected Widget doFindItem(Object element) {
if (element != null) {
int index = getElementIndex(element);
if (index >= 0) {
return items.get(index).getControl();
}
}
return null;
}
@Override
protected void doUpdateItem(Widget item, Object element, boolean fullMap) {
if (element != null) {
int ix = getElementIndex(element);
if (ix >= 0) {
ILabelProvider labelProvider = (ILabelProvider) getLabelProvider();
Image image = getImage(labelProvider, element);
String text = getLabelProviderText(labelProvider, element);
listSetItem(image, text, element, ix);
}
}
}
@Override
protected List getSelectionFromWidget() {
List<Object> list = new ArrayList<Object>();
return list;
}
@Override
protected void internalRefresh(Object element) {
Control list = getControl();
if (element == null || equals(element, getRoot())) {
// the parent
if (listMap != null) {
listMap.clear();
}
unmapAllElements();
List selection = getSelectionFromWidget();
int topIndex = -1;
if (selection == null || selection.isEmpty()) {
topIndex = listGetTopIndex();
}
list.setRedraw(false);
listRemoveAll();
Object[] children = getSortedChildren(getRoot());
//String[] items = new String[children.length];
ILabelProvider labelProvider = (ILabelProvider) getLabelProvider();
for (int i = 0; i < children.length; i++) {
Object el = children[i];
Image image = getImage(labelProvider, el);
String text = getLabelProviderText(labelProvider, el);
ContentItem item = listAdd(image, text, el, -1);
listMap.add(el);
mapElement(el, item.getControl()); // must map it, since findItem only looks in map, if enabled
}
//listSetItems(items);
list.setRedraw(true);
if (topIndex == -1) {
setSelectionToWidget(selection, false);
} else {
listSetTopIndex(Math.min(topIndex, children.length));
}
} else {
doUpdateItem(list, element, true);
}
}
@Override
public void reveal(Object element) {
if (element == null)
return;
IEditorPart activeEditor = null;
IWorkbenchWindow window = PlatformUI.getWorkbench()
.getActiveWorkbenchWindow();
if (window != null) {
IWorkbenchPage page = window.getActivePage();
if (page != null)
activeEditor = page.getActiveEditor();
}
if (activeEditor == null)
return;
activeEditor.getSite().getPage().activate(activeEditor);
ISelectionProvider selectionProvider = activeEditor.getSite()
.getSelectionProvider();
if (selectionProvider != null)
selectionProvider.setSelection(new StructuredSelection(element));
if (activeEditor instanceof IGraphicalEditor) {
Object selectedPage = ((IGraphicalEditor) activeEditor)
.getSelectedPage();
if (selectedPage instanceof IGraphicalEditorPage) {
IGraphicalEditorPage page = (IGraphicalEditorPage) selectedPage;
IGraphicalViewer viewer = page.getViewer();
if (viewer == null)
return;
IPart selectedPart = viewer.getFocusedPart();
if (selectedPart instanceof IGraphicalPart) {
IGraphicalPart part = (IGraphicalPart) selectedPart;
new CenteredRevealHelper(viewer).start(part);
}
}
}
}
@Override
protected void setSelectionToWidget(List in, boolean reveal) {
if (in == null || in.size() == 0) { // clear selection
listDeselectAll();
} else {
int n = in.size();
int[] ixs = new int[n];
int count = 0;
for (int i = 0; i < n; ++i) {
Object el = in.get(i);
int ix = getElementIndex(el);
if (ix >= 0) {
ixs[count++] = ix;
}
}
if (count < n) {
System.arraycopy(ixs, 0, ixs = new int[count], 0, count);
}
listSetSelection(ixs);
if (reveal) {
listShowSelection();
}
}
}
private void listDeselectAll() {
}
protected void listSetSelection(int[] ixs) {
}
protected void listShowSelection() {
}
@Override
public Control getControl() {
return list;
}
public Composite getListComposite() {
return list;
}
protected int listGetTopIndex() {
return -1;
}
protected void listSetTopIndex(int index) {
}
private Image getImage(ILabelProvider labelProvider, Object element) {
return labelProvider.getImage(element);
}
private String getLabelProviderText(ILabelProvider labelProvider,
Object element) {
String text = labelProvider.getText(element);
if (text == null) {
return "";//$NON-NLS-1$
}
return text;
}
}