blob: 94662a7e3c9a43f9be561378803da46d67121e51 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2016 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.help.ui.internal.views;
import java.util.Observable;
import java.util.Observer;
import org.eclipse.help.IHelpResource;
import org.eclipse.help.IIndexEntry;
import org.eclipse.help.IIndexSee;
import org.eclipse.help.IToc;
import org.eclipse.help.ITopic;
import org.eclipse.help.base.AbstractHelpScope;
import org.eclipse.help.internal.base.scope.ScopeUtils;
import org.eclipse.help.internal.base.scope.WorkingSetScope;
import org.eclipse.help.internal.search.federated.LocalHelpScope;
import org.eclipse.help.internal.workingset.WorkingSet;
import org.eclipse.help.search.ISearchScope;
import org.eclipse.help.ui.internal.HelpUIResources;
import org.eclipse.help.ui.internal.IHelpUIConstants;
import org.eclipse.help.ui.internal.Messages;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseTrackAdapter;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.forms.AbstractFormPart;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.widgets.FormToolkit;
public abstract class HyperlinkTreePart extends AbstractFormPart implements
IHelpPart {
public class ScopeObserver implements Observer {
@Override
public void update(Observable o, Object arg) {
if (o instanceof ScopeSetManager) {
refilter();
}
}
}
private class ScopeFilter extends ViewerFilter {
public ScopeFilter(AbstractHelpScope scope) {
this.scope = scope;
}
AbstractHelpScope scope;
@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
if (element instanceof IToc) {
return ScopeUtils.showInTree((IToc)element, scope);
}
if (element instanceof ITopic) {
return ScopeUtils.showInTree((ITopic)element, scope);
}
if (element instanceof IIndexEntry) {
return ScopeUtils.showInTree((IIndexEntry)element, scope);
}
if (element instanceof IIndexSee) {
return ScopeUtils.showInTree((IIndexSee)element, scope);
}
return true;
}
}
protected ReusableHelpPart parent;
private String id;
//private Composite container;
protected TreeViewer treeViewer;
private TreeItem lastItem;
private Cursor handCursor;
private ScopeObserver scopeObserver;
/**
* @param parent
* @param toolkit
* @param style
*/
public HyperlinkTreePart(Composite parent, final FormToolkit toolkit,
IToolBarManager tbm) {
handCursor = new Cursor(parent.getDisplay(), SWT.CURSOR_HAND);
/*
container = toolkit.createComposite(parent);
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.verticalSpacing = 0;
container.setLayout(layout);
Composite sep = toolkit.createCompositeSeparator(container);
GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
gd.heightHint = 1;
sep.setLayoutData(gd);
treeViewer = new TreeViewer(container, SWT.H_SCROLL | SWT.V_SCROLL);
*/
treeViewer = new TreeViewer(parent, SWT.H_SCROLL | SWT.V_SCROLL);
treeViewer.getTree().setMenu(parent.getMenu());
treeViewer.getTree().setForeground(
toolkit.getHyperlinkGroup().getForeground());
configureTreeViewer();
treeViewer.setInput(this);
treeViewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH));
treeViewer.addOpenListener(event -> doOpenSelection((IStructuredSelection) event.getSelection()));
treeViewer.addSelectionChangedListener(
event -> handleSelectionChanged((IStructuredSelection) event.getSelection()));
treeViewer.getTree().addMouseListener(new MouseAdapter() {
long lastTime;
@Override
public void mouseUp(MouseEvent e) {
long eventTime = e.time & 0xFFFFFFFFL;
if (eventTime - lastTime <= e.display.getDoubleClickTime())
return;
if (e.button != 1)
return;
lastTime = eventTime;
Point p = new Point(e.x, e.y);
TreeItem item = treeViewer.getTree().getItem(p);
if (item != null) {
Object obj = item.getData();
if (obj != null) {
doOpen(obj);
}
}
}
});
treeViewer.getTree().addPaintListener(e -> {
validateLastItem();
if (lastItem == null)
return;
Rectangle bounds = lastItem.getBounds();
boolean selected = false;
TreeItem[] items = lastItem.getParent().getSelection();
for (int i = 0; i < items.length; i++) {
if (items[i].equals(lastItem)) {
selected = true;
break;
}
}
if (selected)
e.gc.setForeground(e.display.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT));
else
e.gc.setForeground(toolkit.getHyperlinkGroup().getActiveForeground());
FontMetrics fm = e.gc.getFontMetrics();
int height = fm.getHeight();
int lineY = bounds.y + height;
e.gc.drawLine(bounds.x, lineY, bounds.x + bounds.width - 1, lineY);
});
treeViewer.getTree().addMouseTrackListener(new MouseTrackAdapter() {
@Override
public void mouseExit(MouseEvent e) {
validateLastItem();
if (lastItem != null) {
TreeItem item = lastItem;
lastItem = null;
item.setForeground(null);
}
}
});
treeViewer.getTree().addMouseMoveListener(e -> {
Point p = new Point(e.x, e.y);
TreeItem item = treeViewer.getTree().getItem(p);
validateLastItem();
if (item != null) {
if (lastItem != null) {
if (!lastItem.equals(item)) {
lastItem.setForeground(null);
repaintItem(lastItem);
updateStatus(null);
lastItem = null;
} else
return;
}
Object obj = item.getData();
treeViewer.getTree().setCursor(handCursor);
IStructuredSelection ssel = (IStructuredSelection) treeViewer.getSelection();
if (ssel.getFirstElement() == obj)
item.setForeground(e.display.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT));
else
item.setForeground(toolkit.getHyperlinkGroup().getActiveForeground());
lastItem = item;
repaintItem(lastItem);
if (obj instanceof IHelpResource)
updateStatus((IHelpResource) obj);
else
updateStatus(null);
return;
} else if (lastItem != null) {
lastItem.setForeground(null);
repaintItem(lastItem);
lastItem = null;
updateStatus(null);
}
treeViewer.getTree().setCursor(null);
});
contributeToToolBar(tbm);
scopeObserver = new ScopeObserver();
ScopeState.getInstance().getScopeSetManager().addObserver(scopeObserver);
}
@Override
public void dispose() {
handCursor.dispose();
if (scopeObserver != null) {
ScopeState.getInstance().getScopeSetManager().deleteObserver(scopeObserver);
}
super.dispose();
}
private void repaintItem(TreeItem item) {
Rectangle bounds = item.getBounds();
item.getParent().redraw(bounds.x, bounds.y, bounds.width,
bounds.height, false);
}
protected void contributeToToolBar(IToolBarManager tbm) {
Action collapseAllAction = new Action() {
@Override
public void run() {
BusyIndicator.showWhile(getControl().getDisplay(), () -> doCollapseAll());
}
};
collapseAllAction.setImageDescriptor(HelpUIResources
.getImageDescriptor(IHelpUIConstants.IMAGE_COLLAPSE_ALL));
collapseAllAction
.setToolTipText(Messages.AllTopicsPart_collapseAll_tooltip);
tbm.insertBefore("back", collapseAllAction); //$NON-NLS-1$
tbm.insertBefore("back", new Separator()); //$NON-NLS-1$
}
private void doCollapseAll() {
Object[] expanded = treeViewer.getExpandedElements();
treeViewer.collapseAll();
treeViewer.update(expanded, null);
}
@Override
public Control getControl() {
return treeViewer.getControl();
}
@Override
public void init(ReusableHelpPart parent, String id, IMemento memento) {
this.parent = parent;
this.id = id;
refilter();
}
@Override
public String getId() {
return id;
}
@Override
public void setVisible(boolean visible) {
getControl().setVisible(visible);
if (visible)
treeViewer.refresh();
}
private void doOpenSelection(IStructuredSelection sel) {
Object obj = sel.getFirstElement();
if (obj != null) {
doOpen(obj);
}
}
protected void handleSelectionChanged(IStructuredSelection sel) {
Object obj = sel.getFirstElement();
if (lastItem != null && !lastItem.isDisposed()) {
Object lastObj = lastItem.getData();
if (lastObj==obj)
lastItem.setForeground(getControl().getDisplay()
.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT));
else
lastItem.setForeground(parent.getForm().getToolkit().getHyperlinkGroup()
.getActiveForeground());
repaintItem(lastItem);
}
if (obj instanceof IHelpResource) {
IHelpResource res = (IHelpResource) obj;
updateStatus(res, false);
} else
updateStatus(null, false);
}
private void updateStatus(IHelpResource res) {
updateStatus(res, true);
}
private void updateStatus(IHelpResource res, boolean defaultToSelection) {
if (defaultToSelection && res == null) {
IStructuredSelection ssel = (IStructuredSelection) treeViewer
.getSelection();
Object obj = ssel.getFirstElement();
if (obj instanceof IHelpResource)
res = (IHelpResource) obj;
}
if (res != null) {
String label = res.getLabel();
String href = getHref(res);
HyperlinkTreePart.this.parent.handleLinkEntered(new HyperlinkEvent(
treeViewer.getTree(), href, label, SWT.NULL));
} else {
HyperlinkTreePart.this.parent.handleLinkExited(null);
}
}
protected String getHref(IHelpResource res) {
return res.getHref();
}
protected abstract void configureTreeViewer();
protected abstract void doOpen(Object obj);
protected void postUpdate(final Object obj) {
treeViewer.getControl().getDisplay().asyncExec(() -> treeViewer.update(obj, null));
}
@Override
public boolean fillContextMenu(IMenuManager manager) {
return parent.fillSelectionProviderMenu(treeViewer, manager,
canAddBookmarks());
}
protected abstract boolean canAddBookmarks();
@Override
public boolean hasFocusControl(Control focusControl) {
return treeViewer.getControl().equals(focusControl);
}
@Override
public void setFocus() {
if (treeViewer != null)
treeViewer.getTree().setFocus();
}
@Override
public IAction getGlobalAction(String id) {
if (id.equals(ActionFactory.COPY.getId()))
return parent.getCopyAction();
return null;
}
@Override
public void stop() {
}
private void validateLastItem() {
if (lastItem != null && lastItem.isDisposed())
lastItem = null;
}
@Override
public void refilter() {
ScopeSetManager manager = ScopeState.getInstance().getScopeSetManager();
ScopeSet set = manager.getActiveSet();
EngineDescriptor[] engineDescriptors = parent.getEngineManager().getDescriptors();
ISearchScope scope = null;
for (int i = 0; i < engineDescriptors.length; i++) {
final EngineDescriptor ed = engineDescriptors[i];
if (ed.getEngineTypeId().equals("org.eclipse.help.ui.localSearch") //$NON-NLS-1$
&& ed.getEngine() != null) {
scope = ed.createSearchScope(set.getPreferenceStore());
}
}
WorkingSet workingSet = null;
LocalHelpScope localScope = (LocalHelpScope) scope;
workingSet = localScope.getWorkingSet() ;
treeViewer.resetFilters();
if (workingSet != null) {
WorkingSetScope helpScope = new WorkingSetScope(workingSet, set.getName());
treeViewer.addFilter(new ScopeFilter(helpScope));
}
treeViewer.refresh();
}
}