FilterTree处于 org.eclipse.ui.dialogs中,他的显示效果大致如下:
由于需求中要同时展示两颗Tree,并且同时具有过滤功能,如果使用两个FilterTree ,在UI上很难看,所以考虑改写FilterTree,使之同时操控两棵树,最初的方案是继承FilterTree改写他的createControl()增加一个treeviewer,但发现其中很多私有属性在改写中收到很多限制,于是直接使用了起源,直接在源码内改写,由于它与PatternFilter关系比较紧密,故同时引入,大体思想就是增加一个TreeViewer,改变treeComposite的Layout,并且为新的treeViewer克隆一份过滤处理程序,与之前默认的treeViewer大体相同,最后增加方法支持是否显示新增treeviewer动态设置。
重要代码
CCBFilterTree.java
package com.benson.ccb.favoritites.filterView.filter;
/*******************************************************************************
* Copyright (c) 2004, 2009 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
* Jacek Pospychala - bug 187762
*******************************************************************************/
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.accessibility.ACC;
import org.eclipse.swt.accessibility.AccessibleAdapter;
import org.eclipse.swt.accessibility.AccessibleControlAdapter;
import org.eclipse.swt.accessibility.AccessibleControlEvent;
import org.eclipse.swt.accessibility.AccessibleEvent;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.MouseTrackListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IWorkbenchPreferenceConstants;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.PatternFilter;
import org.eclipse.ui.internal.WorkbenchMessages;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.eclipse.ui.progress.WorkbenchJob;
/**
* A simple control that provides a text widget and a tree viewer. The contents
* of the text widget are used to drive a PatternFilter that is on the viewer.
*
* @see org.eclipse.ui.dialogs.PatternFilter
* @since 3.2
*/
public class CCBFilterTree extends Composite {
/**
* The filter text widget to be used by this tree. This value may be
* <code>null</code> if there is no filter widget, or if the controls have
* not yet been created.
*/
protected Text filterText;
/**
* The control representing the clear button for the filter text entry. This
* value may be <code>null</code> if no such button exists, or if the
* controls have not yet been created.
* <p>
* <strong>Note:</strong> As of 3.5, this is not used if the new look is chosen.
* </p>
*/
protected ToolBarManager filterToolBar;
/**
* The control representing the clear button for the filter text entry. This
* value may be <code>null</code> if no such button exists, or if the
* controls have not yet been created.
* <p>
* <strong>Note:</strong> This is only used if the new look is chosen.
* </p>
*
* @since 3.5
*/
protected Control clearButtonControl;
/**
* The viewer for the filtered tree. This value should never be
* <code>null</code> after the widget creation methods are complete.
*/
protected TreeViewer treeViewer;
/**
* The viewer for the extra filtered tree. This value is possible
* <code>null</code>.
*/
protected TreeViewer extraTreeViewer;
/**
* The Composite on which the filter controls are created. This is used to
* set the background color of the filter controls to match the surrounding
* controls.
*/
protected Composite filterComposite;
/**
* The pattern filter for the tree. This value must not be <code>null</code>.
*/
private CCBPatternFilter patternFilter;
/**
* The text to initially show in the filter text control.
*/
protected String initialText = ""; //$NON-NLS-1$
/**
* The job used to refresh the tree.
*/
private Job refreshJob;
private Job refreshJobExtra;
/**
* The parent composite of the filtered tree.
*
* @since 3.3
*/
protected Composite parent;
/**
* Whether or not to show the filter controls (text and clear button). The
* default is to show these controls. This can be overridden by providing a
* setting in the product configuration file. The setting to add to not show
* these controls is:
*
* org.eclipse.ui/SHOW_FILTERED_TEXTS=false
*/
protected boolean showFilterControls;
/**
* @since 3.3
*/
protected Composite treeComposite;
/**
* Tells whether to use the pre 3.5 or the new look.
*
* @since 3.5
*/
private boolean useNewLook = false;
/**
* Image descriptor for enabled clear button.
*/
private static final String CLEAR_ICON = "org.eclipse.ui.internal.dialogs.CLEAR_ICON"; //$NON-NLS-1$
/**
* Image descriptor for disabled clear button.
*/
private static final String DISABLED_CLEAR_ICON= "org.eclipse.ui.internal.dialogs.DCLEAR_ICON"; //$NON-NLS-1$
/**
* Maximum time spent expanding the tree after the filter text has been
* updated (this is only used if we were able to at least expand the visible
* nodes)
*/
private static final long SOFT_MAX_EXPAND_TIME = 200;
/**
* Get image descriptors for the clear button.
*/
static {
ImageDescriptor descriptor = AbstractUIPlugin
.imageDescriptorFromPlugin(PlatformUI.PLUGIN_ID,
"$nl$/icons/full/etool16/clear_co.gif"); //$NON-NLS-1$
if (descriptor != null) {
JFaceResources.getImageRegistry().put(CLEAR_ICON, descriptor);
}
descriptor = AbstractUIPlugin.imageDescriptorFromPlugin(
PlatformUI.PLUGIN_ID, "$nl$/icons/full/dtool16/clear_co.gif"); //$NON-NLS-1$
if (descriptor != null) {
JFaceResources.getImageRegistry().put(DISABLED_CLEAR_ICON, descriptor);
}
}
/**
* Create a new instance of the receiver.
*
* @param parent
* the parent <code>Composite</code>
* @param treeStyle
* the style bits for the <code>Tree</code>
* @param filter
* the filter to be used
*
* @deprecated As of 3.5, replaced by
* {@link #FilteredTree(Composite, int, PatternFilter, boolean)} where using the new
* look is encouraged
*/
public CCBFilterTree(Composite parent, int treeStyle, CCBPatternFilter filter) {
super(parent, SWT.NONE);
this.parent = parent;
init(treeStyle, filter);
}
/**
* Create a new instance of the receiver.
*
* @param parent
* the parent <code>Composite</code>
* @param treeStyle
* the style bits for the <code>Tree</code>
* @param filter
* the filter to be used
* @param useNewLook
* <code>true</code> if the new 3.5 look should be used
* @since 3.5
*/
public CCBFilterTree(Composite parent, int treeStyle, CCBPatternFilter filter, boolean useNewLook) {
super(parent, SWT.NONE);
this.parent = parent;
this.useNewLook= useNewLook;
init(treeStyle, filter);
}
/**
* Create a new instance of the receiver. Subclasses that wish to override
* the default creation behavior may use this constructor, but must ensure
* that the <code>init(composite, int, PatternFilter)</code> method is
* called in the overriding constructor.
*
* @param parent
* the parent <code>Composite</code>
* @see #init(int, PatternFilter)
*
* @since 3.3
* @deprecated As of 3.5, replaced by {@link #FilteredTree(Composite, boolean)} where using the
* look is encouraged
* @wbp.parser.constructor
*/
protected CCBFilterTree(Composite parent) {
super(parent, SWT.NONE);
this.parent = parent;
}
/**
* Create a new instance of the receiver. Subclasses that wish to override
* the default creation behavior may use this constructor, but must ensure
* that the <code>init(composite, int, PatternFilter)</code> method is
* called in the overriding constructor.
*
* @param parent
* the parent <code>Composite</code>
* @param useNewLook
* <code>true</code> if the new 3.5 look should be used
* @see #init(int, PatternFilter)
*
* @since 3.5
*/
protected CCBFilterTree(Composite parent, boolean useNewLook) {
super(parent, SWT.NONE);
this.parent = parent;
this.useNewLook = useNewLook;
}
/**
* Create the filtered tree.
*
* @param treeStyle
* the style bits for the <code>Tree</code>
* @param filter
* the filter to be used
*
* @since 3.3
*/
protected void init(int treeStyle, CCBPatternFilter filter) {
patternFilter = filter;
showFilterControls = PlatformUI.getPreferenceStore().getBoolean(
IWorkbenchPreferenceConstants.SHOW_FILTERED_TEXTS);
createControl(parent, treeStyle);
createRefreshJob();
setInitialText(WorkbenchMessages.FilteredTree_FilterMessage);
setFont(parent.getFont());
}
/**
* Create the filtered tree's controls. Subclasses should override.
*
* @param parent
* @param treeStyle
*/
protected void createControl(Composite parent, int treeStyle) {
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
setLayout(layout);
setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
if (showFilterControls) {
if (!useNewLook || useNativeSearchField(parent)) {
filterComposite= new Composite(this, SWT.NONE);
} else {
filterComposite= new Composite(this, SWT.BORDER);
filterComposite.setBackground(getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
}
GridLayout filterLayout= new GridLayout(2, false);
filterLayout.marginHeight= 0;
filterLayout.marginWidth= 0;
filterLayout.numColumns=2;
filterComposite.setLayout(filterLayout);
filterComposite.setFont(parent.getFont());
createFilterControls(filterComposite);
filterComposite.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING,
true, false));
}
treeComposite = new Composite(this, SWT.NONE);
GridLayout treeCompositeLayout = new GridLayout();
treeCompositeLayout.marginHeight = 0;
treeCompositeLayout.marginWidth = 0;
treeCompositeLayout.numColumns=2;
treeComposite.setLayout(treeCompositeLayout);
GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
treeComposite.setLayoutData(data);
treeViewer = createTreeViewer(treeComposite, treeStyle);
extraTreeViewer = createTreeViewer(treeComposite, treeStyle);
treeViewer.getControl().addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
refreshJob.cancel();
}
});
extraTreeViewer.getControl().addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
refreshJobExtra.cancel();
}
});
}
private static Boolean useNativeSearchField;
private static boolean useNativeSearchField(Composite composite) {
if (useNativeSearchField == null) {
useNativeSearchField = Boolean.FALSE;
Text testText = null;
try {
testText = new Text(composite, SWT.SEARCH | SWT.ICON_CANCEL);
useNativeSearchField = new Boolean((testText.getStyle() & SWT.ICON_C