/*******************************************************************************
* Copyright (c) 2004, 2010 BREDEX GmbH.
* 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:
* BREDEX GmbH - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.jubula.client.ui.rcp.views;
import javax.persistence.EntityManager;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.GroupMarker;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jubula.client.core.events.DataChangedEvent;
import org.eclipse.jubula.client.core.events.DataEventDispatcher;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.DataState;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.IDataChangedListener;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.IProjectLoadedListener;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.UpdateState;
import org.eclipse.jubula.client.core.model.IPersistentObject;
import org.eclipse.jubula.client.core.persistence.GeneralStorage;
import org.eclipse.jubula.client.core.persistence.IEntityManagerProvider;
import org.eclipse.jubula.client.ui.constants.Constants;
import org.eclipse.jubula.client.ui.constants.IconConstants;
import org.eclipse.jubula.client.ui.rcp.Plugin;
import org.eclipse.jubula.client.ui.rcp.businessprocess.UINodeBP;
import org.eclipse.jubula.client.ui.rcp.controllers.AbstractPartListener;
import org.eclipse.jubula.client.ui.rcp.editors.AbstractTestCaseEditor;
import org.eclipse.jubula.client.ui.rcp.filter.JBBrowserPatternFilter;
import org.eclipse.jubula.client.ui.rcp.filter.JBFilteredTree;
import org.eclipse.jubula.client.ui.rcp.i18n.Messages;
import org.eclipse.jubula.client.ui.rcp.sorter.NodeNameViewerSorter;
import org.eclipse.jubula.client.ui.rcp.utils.UIIdentitiyElementComparer;
import org.eclipse.jubula.client.ui.rcp.utils.Utils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.dialogs.FilteredTree;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.views.properties.IPropertySheetPage;
/**
* @author BREDEX GmbH
* @created 21.10.2005
*/
public abstract class AbstractJBTreeView extends ViewPart implements
IProjectLoadedListener, IDataChangedListener, IEntityManagerProvider {
/** Default expansion for the tree */
public static final int DEFAULT_EXPANSION = 2;
/** number of columns = 1 */
protected static final int NUM_COLUMNS_1 = 1;
/** vertical spacing = 2 */
protected static final int VERTICAL_SPACING = 3;
/**
* <code>m_treeViewer</code>tree Viewer
*/
private TreeViewer m_treeViewer;
/**
* <code>m_treeFilterText</code>tree Viewer
*/
private Text m_treeFilterText;
/**
* This part's reference to the clipboard.
* Note that the part shares this clipboard with the entire operating
* system, and this instance is only for easier access to the clipboard.
* The clipboard does not exclusively belong to the part.
*/
private Clipboard m_clipboard;
/** flag wether the view is linked with the editor or not */
private boolean m_isLinkedWithEditor = false;
/** The partListener of this view */
private PartListener m_partListener = new PartListener();
/** The preference store to hold the existing preference values. */
private IPreferenceStore m_store = Plugin.getDefault().getPreferenceStore();
/**
* This listener updates the selection of the view based on the activated
* part.
*
* @author BREDEX GmbH
* @created 20.09.2006
*/
private final class PartListener extends AbstractPartListener {
/**
* {@inheritDoc}
*/
public void partActivated(IWorkbenchPart part) {
setSelectionToEditorNode(part);
super.partActivated(part);
}
}
/**
* Toggles "Link with Editor" functionality for this view. When linked,
* the selection of the view can be changed automatically based on the
* currently active editor.
*
* @author BREDEX GmbH
* @created Nov 8, 2006
*/
private final class ToggleLinkingAction extends Action {
/**
* Constructor
*/
public ToggleLinkingAction() {
super(Messages.TestCaseBrowserLinkWithEditor, IAction.AS_CHECK_BOX);
setImageDescriptor(IconConstants.LINK_WITH_EDITOR_DESCRIPTOR);
m_isLinkedWithEditor = Plugin.getDefault().getPreferenceStore()
.getBoolean(Constants.LINK_WITH_EDITOR_TCVIEW_KEY);
setChecked(m_isLinkedWithEditor);
}
/**
* {@inheritDoc}
*/
public void run() {
m_isLinkedWithEditor = isChecked();
Plugin.getDefault().getPreferenceStore().setValue(
Constants.LINK_WITH_EDITOR_TCVIEW_KEY,
m_isLinkedWithEditor);
if (Plugin.getActiveEditor() instanceof AbstractTestCaseEditor
&& m_isLinkedWithEditor) {
setSelectionToEditorNode(Plugin.getActiveEditor());
}
}
}
/**
* Sets the selection to the node of the current active editor if the
* linking is enabled
* @param part the current activated IWorkbenchPart
*/
private void setSelectionToEditorNode(IWorkbenchPart part) {
if (part != null) {
Object obj = part.getAdapter(AbstractTestCaseEditor.class);
AbstractTestCaseEditor tce = (AbstractTestCaseEditor)obj;
if (obj != null && m_isLinkedWithEditor && tce != null) {
final IPersistentObject editorWorkVersion =
tce.getEditorHelper().getEditSupport().getWorkVersion();
if (editorWorkVersion != null) {
UINodeBP.selectNodeInTree(editorWorkVersion.getId(),
getTreeViewer(), getEntityManager());
}
}
}
}
/**
*
*/
protected abstract void rebuildTree();
/**
* {@inheritDoc}
*/
public Object getAdapter(Class adapter) {
if (adapter.equals(AbstractJBTreeView.class)) {
return this;
} else if (adapter.equals(IPropertySheetPage.class)) {
return new JBPropertiesPage(false, null);
}
return super.getAdapter(adapter);
}
/**
*
* {@inheritDoc}
*/
public final void handleProjectLoaded() {
if (GeneralStorage.getInstance().getProject() == null) {
// project-loaded fired for clearing the current project
// do not rebuild the tree
return;
}
Plugin.startLongRunning();
Plugin.getDisplay().syncExec(new Runnable() {
public void run() {
try {
rebuildTree();
} catch (OperationCanceledException oce) {
getTreeViewer().setInput(null);
}
}
});
Plugin.stopLongRunning();
}
/**
* @return tree Viewer
*/
public TreeViewer getTreeViewer() {
return m_treeViewer;
}
/**
* @return selection
*/
public ISelection getSelection() {
return m_treeViewer.getSelection();
}
/**
* @param selection selection to set
*/
public void setSelection(ISelection selection) {
m_treeViewer.setSelection(selection, true);
}
/**
* @param treeViewer The treeViewer to set.
*/
public void setTreeViewer(TreeViewer treeViewer) {
m_treeViewer = treeViewer;
}
/** {@inheritDoc} */
public void createPartControl(Composite parent) {
m_clipboard = new Clipboard(parent.getDisplay());
final FilteredTree ft = new JBFilteredTree(parent, SWT.MULTI
| SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER,
new JBBrowserPatternFilter(), true);
setTreeViewer(ft.getViewer());
setTreeFilterText(ft.getFilterControl());
addTreeListener();
getTreeViewer().setUseHashlookup(true);
getTreeViewer().setSorter(new NodeNameViewerSorter());
getTreeViewer().setComparer(new UIIdentitiyElementComparer());
getSite().setSelectionProvider(getTreeViewer());
getTreeViewer().setAutoExpandLevel(DEFAULT_EXPANSION);
addFilterBackgroundColoring(ft);
final DataEventDispatcher ded = DataEventDispatcher.getInstance();
ded.addProjectLoadedListener(this, false);
ded.addDataChangedListener(this, true);
getViewSite().getActionBars().getToolBarManager().add(
new ToggleLinkingAction());
getViewSite().getWorkbenchWindow().getPartService().addPartListener(
m_partListener);
setFocus();
registerContextMenu();
}
/**
* Adds Filter Background Coloring functionality
* @param ft the Filtered Tree the functionality is supposed to be added to
*/
private void addFilterBackgroundColoring(final FilteredTree ft) {
ft.getFilterControl().addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
if (!getTreeFilterText().getText().isEmpty()
&& m_store.getBoolean(Constants.BACKGROUND_COLORING_KEY)) {
getTreeViewer().getControl().setBackground(
new Color(Display.getCurrent(),
Utils.intToRgb(m_store.getInt(
Constants.BACKGROUND_COLOR_KEY))));
} else {
getTreeViewer().getControl().setBackground(
Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
}
}
});
}
/**
* Register the context menu for the receiver so that commands may be added
* to it.
*/
protected void registerContextMenu() {
MenuManager contextMenu = new MenuManager();
createContextMenu(contextMenu);
contextMenu.add(new GroupMarker(
IWorkbenchActionConstants.MB_ADDITIONS));
Control control = getTreeViewer().getControl();
Menu menu = contextMenu.createContextMenu(control);
control.setMenu(menu);
getSite().registerContextMenu(contextMenu, getTreeViewer());
}
/**
* @param contextMenu the MenuManager to create the context menu for
*/
protected abstract void createContextMenu(IMenuManager contextMenu);
/**
* Adds DoubleClickListener to Treeview.
*/
protected abstract void addTreeListener();
/**
* {@inheritDoc}
*/
public void dispose() {
try {
m_clipboard.dispose();
getViewSite().getWorkbenchWindow().getPartService()
.removePartListener(m_partListener);
final DataEventDispatcher dispatcher =
DataEventDispatcher.getInstance();
// clear corresponding views
dispatcher.firePartClosed(this);
dispatcher.removeProjectLoadedListener(this);
} finally {
getSite().setSelectionProvider(null);
super.dispose();
}
}
/**
* @return a reference to the clipboard.
*/
public Clipboard getClipboard() {
return m_clipboard;
}
/**
* @param treeFilterText the treeFilterText to set
*/
public void setTreeFilterText(Text treeFilterText) {
m_treeFilterText = treeFilterText;
}
/**
* @return the treeFilterText
*/
public Text getTreeFilterText() {
return m_treeFilterText;
}
/**
* {@inheritDoc}
*/
public EntityManager getEntityManager() {
GeneralStorage gs = GeneralStorage.getInstance();
if (gs != null) {
return gs.getEntityManager();
}
return null;
}
/** {@inheritDoc} */
public void handleDataChanged(DataChangedEvent... events) {
DataChangedEvent previousEvent = null;
for (DataChangedEvent e : events) {
final DataState dataState = e.getDataState();
if (previousEvent != null
&& previousEvent.getDataState() == dataState
&& (dataState == DataState.StructureModified
|| dataState == DataState.Deleted)) {
continue;
}
handleDataChanged(e.getPo(), dataState, e.getUpdateState());
previousEvent = e;
}
}
/**
* handle a single data changed event
*
* @param po
* the changed po
* @param dataState
* the data state
* @param updateState
* the update state
*/
protected abstract void handleDataChanged(final IPersistentObject po,
final DataState dataState, final UpdateState updateState);
}