/*******************************************************************************
* Copyright (c) 2007 Exadel, Inc. and Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is 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:
* Exadel, Inc. and Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.common.model.ui.views.navigator;
import java.util.Properties;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.commands.ActionHandler;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IPartListener;
import org.eclipse.ui.ISaveablePart;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.actions.ActionContext;
import org.eclipse.ui.actions.BuildAction;
import org.eclipse.ui.actions.CloseResourceAction;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.ide.IDEActionFactory;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.ISetSelectionTarget;
import org.eclipse.ui.part.IShowInTarget;
import org.eclipse.ui.part.ShowInContext;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.views.framelist.FrameList;
import org.eclipse.ui.views.navigator.IResourceNavigator;
import org.eclipse.ui.views.navigator.ResourceComparator;
import org.eclipse.ui.views.navigator.ResourceNavigatorActionGroup;
import org.eclipse.ui.views.navigator.ResourcePatternFilter;
import org.eclipse.ui.views.navigator.ResourceSorter;
import org.jboss.tools.common.meta.action.XActionInvoker;
import org.jboss.tools.common.model.XFilteredTree;
import org.jboss.tools.common.model.XJob;
import org.jboss.tools.common.model.XModelException;
import org.jboss.tools.common.model.XModelObject;
import org.jboss.tools.common.model.XJob.XRunnable;
import org.jboss.tools.common.model.event.XModelTreeEvent;
import org.jboss.tools.common.model.filesystems.XFileObject;
import org.jboss.tools.common.model.impl.trees.FileSystemsTree;
import org.jboss.tools.common.model.plugin.ModelPlugin;
import org.jboss.tools.common.model.project.IModelNature;
import org.jboss.tools.common.model.ui.ModelUIPlugin;
import org.jboss.tools.common.model.ui.action.ModelContributionManager;
import org.jboss.tools.common.model.ui.dnd.ControlDragDrop;
import org.jboss.tools.common.model.ui.editor.IModelObjectEditorInput;
import org.jboss.tools.common.model.ui.navigator.NavigatorLabelProvider;
import org.jboss.tools.common.model.ui.navigator.NavigatorStatusLineProvider;
import org.jboss.tools.common.model.ui.navigator.TreeViewerDragDropProvider;
import org.jboss.tools.common.model.ui.navigator.TreeViewerMenuInvoker;
import org.jboss.tools.common.model.ui.navigator.TreeViewerModelListenerImpl;
import org.jboss.tools.common.model.ui.select.XModelObjectSelectionProvider;
import org.jboss.tools.common.model.util.EclipseResourceUtil;
import org.jboss.tools.common.model.util.ModelFeatureFactory;
public class NavigatorViewPart extends ViewPart implements ISaveablePart, ISetSelectionTarget, IResourceNavigator , IShowInTarget //, ISelectionProvider
{
public static final String VIEW_ID = "org.jboss.tools.common.model.ui.navigator.NavigatorViewPart"; //$NON-NLS-1$
private TreeViewer viewer;
private XModelObjectSelectionProvider selectionProvider = new XModelObjectSelectionProvider();
private TreeViewerDragDropProvider dndProvider = new TreeViewerDragDropProvider();
private ControlDragDrop dnd = new ControlDragDrop();
private CloseResourceAction closeProjectAction;
private BuildAction buildProjectAction;
private BuildAction rebuildProjectAction;
protected NavigatorContentProvider contentProvider;
private IMemento memento = null;
private NavigatorStatusLineProvider statusLineProvider = new NavigatorStatusLineProvider();
private ActivationListener fActivationListener= new ActivationListener();
boolean useModelMenu = true;
public NavigatorViewPart() {
selectionProvider.addSelectionChangedListener(new SL());
}
public void setFocus() {
getViewer().getTree().setFocus();
}
public TreeViewer getViewer() {
return viewer;
}
public void createPartControl(Composite parent) {
createViewer(parent);
viewer.setInput(getInitialInput());
selectionProvider.addHost("viewer", viewer, true); //$NON-NLS-1$
getSite().setSelectionProvider(selectionProvider);
if (memento != null) {
restoreLinkingEnabled();
}
initActionBars();
dndProvider.setViewer(viewer);
dnd.setProvider(dndProvider);
dnd.enable();
initContextMenu();
activateF3();
getSite().getPage().addPartListener(partListener);
if (memento != null)
restoreState(memento);
memento = null;
}
private void activateF3() {
IHandlerService h = (IHandlerService)getViewSite().getActionBars().getServiceLocator().getService(IHandlerService.class);
IAction action = new Action(){
public boolean isEnabled() {
return true;
}
public void run() {
ISelection s = viewer.getSelection();
if(s.isEmpty() || !(s instanceof StructuredSelection)) return;
StructuredSelection ss = (StructuredSelection)s;
Object o = ss.getFirstElement();
if(!(o instanceof XModelObject)) return;
XModelObject object = (XModelObject)o;
if(XActionInvoker.getAction("Open", object) == null) return; //$NON-NLS-1$
XActionInvoker.invoke("Open", object, null); //$NON-NLS-1$
}
};
h.activateHandler("org.eclipse.jdt.ui.edit.text.java.open.editor", new ActionHandler(action)); //$NON-NLS-1$
}
private IAction createActionInstance(String name) {
return (IAction)ModelFeatureFactory.getInstance().createFeatureInstance(name);
}
protected String[] getActionClasses() {
String[] actions = new String[]{
};
return actions;
}
protected void initActionBars() {
IActionBars bars = getViewSite().getActionBars();
String[] actions = getActionClasses();
for (int i = 0; i < actions.length; i++) {
IAction action = createActionInstance(actions[i]);
if(action != null) bars.getToolBarManager().add(action);
}
closeProjectAction = new CloseResourceAction(getViewer().getTree().getShell());
getSite().getSelectionProvider().addSelectionChangedListener(closeProjectAction);
getViewSite().getActionBars().setGlobalActionHandler(
IDEActionFactory.CLOSE_PROJECT.getId(),
closeProjectAction
);
buildProjectAction = new BuildAction(getViewer().getTree().getShell(), IncrementalProjectBuilder.INCREMENTAL_BUILD);
getSite().getSelectionProvider().addSelectionChangedListener(buildProjectAction);
getViewSite().getActionBars().setGlobalActionHandler(
IDEActionFactory.BUILD_PROJECT.getId(),
buildProjectAction
);
rebuildProjectAction = new BuildAction(getViewer().getTree().getShell(), IncrementalProjectBuilder.FULL_BUILD);
getSite().getSelectionProvider().addSelectionChangedListener(rebuildProjectAction);
getViewSite().getActionBars().setGlobalActionHandler(
IDEActionFactory.BUILD_PROJECT.getId(),
rebuildProjectAction
);
makeActions();
getActionGroup().fillActionBars(getViewSite().getActionBars());
updateActionBars((IStructuredSelection) viewer.getSelection());
}
public void dispose() {
if (getSite()!=null&&getSite().getSelectionProvider()!=null) {
getSite().getSelectionProvider().removeSelectionChangedListener(closeProjectAction);
getSite().getSelectionProvider().removeSelectionChangedListener(buildProjectAction);
getSite().getSelectionProvider().removeSelectionChangedListener(rebuildProjectAction);
}
if(getSite()!=null) {
getSite().getWorkbenchWindow().getShell().removeShellListener(fActivationListener);
}
super.dispose();
}
protected void createViewer(Composite parent) {
viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
viewer.setUseHashlookup(true);
initContentProvider(viewer);
initLabelProvider(viewer);
// initFilters(viewer);
initListeners(viewer);
}
protected void initLabelProvider(TreeViewer treeViewer) {
treeViewer.setLabelProvider(new NavigatorLabelProvider());
}
protected void initContentProvider(TreeViewer treeViewer) {
NavigatorContentProvider c = new NavigatorContentProvider();
ML listener = new ML();
listener.setViewer(treeViewer);
c.setListener(listener);
contentProvider = c;
treeViewer.setContentProvider(contentProvider);
}
protected void initListeners(TreeViewer treeViewer) {
treeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
handleSelectionChanged(event);
}
});
//@S_CHECK@
listener = createMenuInvoker();
listener.setViewer(viewer);
if(useModelMenu) {
viewer.getTree().addMouseListener(listener);
}
}
protected TreeViewerMenuInvoker createMenuInvoker() {
return new NavigatorMenuInvoker();
}
public XModelObject getSelectedModelObject() {
if(getViewer() == null || getViewer().getTree() == null || getViewer().getTree().isDisposed()) return null;
TreeItem[] ti = getViewer().getTree().getSelection();
if(ti == null || ti.length == 0) return null;
return getModelObjectForWidget(ti[0]);
}
public XModelObject getModelObjectForWidget(Widget widget) {
if(!(widget instanceof TreeItem)) return null;
TreeItem item = (TreeItem)widget;
Object itemData = item.getData();
return (!(itemData instanceof XModelObject)) ? null : (XModelObject)itemData;
}
protected IAdaptable getInitialInput() {
IAdaptable input = getSite().getPage().getInput();
if (input != null) {
IResource resource = null;
if (input instanceof IResource) {
resource = (IResource) input;
} else {
resource = (IResource) input.getAdapter(IResource.class);
}
if (resource != null) {
switch (resource.getType()) {
case IResource.FILE :
return resource.getParent();
case IResource.FOLDER :
case IResource.PROJECT :
case IResource.ROOT :
return (IContainer) resource;
default :
// Unknown resource type. Fall through.
break;
}
}
}
return ModelUIPlugin.getWorkspace().getRoot();
}
public Object getAdapter(Class adapter)
{
//ModelUIPlugin.log("getAdapter(" + adapter.getName() + ")");
return super.getAdapter(adapter);
}
public void doSave(IProgressMonitor monitor) {
XModelObject o = getSelectedModelObject();
if(o == null) return;
while(o != null && o.getFileType() == XFileObject.NONE) o = o.getParent();
if(o == null || o.getFileType() != XFileObject.FILE) return;
XActionInvoker.invoke("SaveActions.Save", o, null); //$NON-NLS-1$
firePropertyChange(IEditorPart.PROP_DIRTY);
}
public void doSaveAs() {}
public boolean isDirty() {
XModelObject o = getSelectedModelObject();
if(o == null) return false;
while(o != null && o.getFileType() == XFileObject.NONE) o = o.getParent();
if(o == null || o.getFileType() != XFileObject.FILE) return false;
return o.isModified();
}
public boolean isSaveAsAllowed() {
return false;
}
public boolean isSaveOnCloseNeeded() {
return false;
}
class SL implements ISelectionChangedListener {
public void selectionChanged(SelectionChangedEvent event) {
firePropertyChange(IEditorPart.PROP_DIRTY);
}
}
class ML extends TreeViewerModelListenerImpl {
public void nodeChanged(XModelTreeEvent event) {
super.nodeChanged(event);
firePropertyChange(IEditorPart.PROP_DIRTY);
}
}
public void selectReveal(ISelection selection)
{
if (selection instanceof IStructuredSelection)
{
Object object = ((IStructuredSelection)selection).getFirstElement();
if (object instanceof IProject)
{
XModelObject root = contentProvider.getRootByProject((IProject)object);
if(root != null) getSite().getSelectionProvider().setSelection(
new StructuredSelection(root)
);
}
}
}
public void init(IViewSite site, IMemento _memento) throws PartInitException {
init(site);
this.memento = _memento;
site.getWorkbenchWindow().getShell().addShellListener(fActivationListener);
}
public void saveState(IMemento _memento) {
XModelObject o = getSelectedModelObject();
if(o != null) _memento.putString("selection", getNodePath(o)); //$NON-NLS-1$
saveLinkingEnabled(_memento);
}
public void restoreState(IMemento _memento) {
String selection = _memento.getString("selection"); //$NON-NLS-1$
XModelObject o = findModelObject(selection);
if(o != null) viewer.setSelection(new StructuredSelection(o));
restoreLinkingEnabled();
}
private String getNodePath(XModelObject o) {
IProject p = (IProject)o.getModel().getProperties().get("project"); //$NON-NLS-1$
return p.getName() + ":" + o.getPath(); //$NON-NLS-1$
}
private XModelObject findModelObject(String nodepath) {
if(nodepath == null || nodepath.length() == 0) return null;
int i = nodepath.indexOf(":"); //$NON-NLS-1$
IProject p = ModelUIPlugin.getWorkspace().getRoot().getProject(nodepath.substring(0, i));
return EclipseResourceUtil.getObjectByPath(p, nodepath.substring(i + 1));
}
// see ResourceNavigator
protected void handleSelectionChanged(SelectionChangedEvent event) {
IStructuredSelection sel = (IStructuredSelection) event.getSelection();
updateStatusLine(sel);
updateActionBars(sel);
linkToEditor(sel);
}
protected void updateStatusLine(IStructuredSelection selection) {
String msg = statusLineProvider.getStatusLineMessage(selection);
getViewSite().getActionBars().getStatusLineManager().setMessage(msg);
}
//// IResourceNavigator
public ResourcePatternFilter getPatternFilter() {
return new ResourcePatternFilter();
}
IWorkingSet workingSet = null;
public IWorkingSet getWorkingSet() {
return workingSet;
}
public void setWorkingSet(IWorkingSet workingSet) {
this.workingSet = workingSet;
}
protected ResourceSorter resourceSorter = null;
public ResourceSorter getSorter() {
return resourceSorter;
}
public void setSorter(ResourceSorter sorter) {
resourceSorter = sorter;
}
String[] filtersPreference = new String[0];
public void setFiltersPreference(String[] patterns) {
filtersPreference = patterns;
}
public FrameList getFrameList() {
return null;
}
protected boolean isLinkingEnabled = false;
public boolean isLinkingEnabled() {
return isLinkingEnabled;
}
public void setLinkingEnabled(boolean enabled) {
isLinkingEnabled = enabled;
if (enabled) {
IEditorPart editor = getSite().getPage().getActiveEditor();
if (editor != null && editor != this) {
editorActivated(editor);
}
}
}
protected void makeActions() {
setActionGroup(new ModelNavigatorActionGroup(this));
}
ResourceNavigatorActionGroup actionGroup;
protected ResourceNavigatorActionGroup getActionGroup() {
return actionGroup;
}
protected void setActionGroup(ResourceNavigatorActionGroup actionGroup) {
this.actionGroup = actionGroup;
}
protected void updateActionBars(IStructuredSelection selection) {
ResourceNavigatorActionGroup group = getActionGroup();
if (group != null) {
group.setContext(new ActionContext(selection));
group.updateActionBars();
}
}
// MenuManager
ModelContributionManager menuMgr;
TreeViewerMenuInvoker listener;
protected void initContextMenu() {
menuMgr = new ModelContributionManager(getSite().getShell(), listener);
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
fillContextMenu(manager);
}
});
TreeViewer treeViewer = getViewer();
Menu menu = menuMgr.createContextMenu(treeViewer.getTree());
treeViewer.getTree().setMenu(menu);
getSite().registerContextMenu(menuMgr, treeViewer);
listener.setStandardInvoker(menuMgr);
}
public void callMenu() {
fillContextMenu(menuMgr);
Menu menu = menuMgr.createContextMenu(viewer.getTree());
menu.setVisible(true);
}
protected void fillContextMenu(IMenuManager menu) {
// IStructuredSelection selection =
// (IStructuredSelection) getViewer().getSelection();
// if(menu instanceof ModelContributionManager) {
// ((ModelContributionManager)menu).setSelection(selection);
// }
menu.update(true);
}
// linking
public TreeViewer getTreeViewer() {
return (TreeViewer)getViewer();
}
private IPartListener partListener = new IPartListener() {
public void partActivated(IWorkbenchPart part) {
if (part instanceof IEditorPart && part != NavigatorViewPart.this)
editorActivated((IEditorPart) part);
}
public void partBroughtToTop(IWorkbenchPart part) {
}
public void partClosed(IWorkbenchPart part) {
}
public void partDeactivated(IWorkbenchPart part) {
}
public void partOpened(IWorkbenchPart part) {
}
};
private void saveLinkingEnabled(IMemento _memento) {
_memento.putInteger("LinkModelProjectsToEditor", isLinkingEnabled ? 1 : 0); //$NON-NLS-1$
}
private void restoreLinkingEnabled() {
Integer val = memento.getInteger("LinkModelProjectsToEditor");//IWorkbenchPreferenceConstants.LINK_NAVIGATOR_TO_EDITOR); //$NON-NLS-1$
if (val != null) {
isLinkingEnabled = val.intValue() != 0;
}
}
protected void editorActivated(IEditorPart editor) {
if (!isLinkingEnabled()) {
return;
}
IEditorInput input = editor.getEditorInput();
XModelObject o = null;
if(input instanceof IModelObjectEditorInput) {
o = ((IModelObjectEditorInput)input).getXModelObject();
} else if (input instanceof IFileEditorInput) {
IFileEditorInput fileInput = (IFileEditorInput) input;
IFile file = fileInput.getFile();
if(file == null) return;
o = getObjectByResource(file);
}
if(o == null) return;
ISelection newSelection = new StructuredSelection(o);
if (!getTreeViewer().getSelection().equals(o)) {
getTreeViewer().setSelection(newSelection);
}
}
/**
* Returns model object associated with file in tree.
* Navigator may display model object that is not
* the model object representing the file. E.g. see
* bean objects in jsf
* @param file
* @return
*/
protected XModelObject getObjectByResource(IFile file) {
XModelObject o = EclipseResourceUtil.getObjectByResource(file);
if(o == null || contentProvider == null) return o;
XFilteredTree t = contentProvider.getFilteredTree(o);
if(!(t instanceof FileSystemsTree)) return o;
FileSystemsTree fst = (FileSystemsTree)t;
return fst.getRepresentation(o);
}
protected void linkToEditor(IStructuredSelection selection) {
if (!isLinkingEnabled()) {
return;
}
Object obj = selection.getFirstElement();
if (obj instanceof IAdaptable && selection.size() == 1) {
IFile file = (IFile) ((IAdaptable)obj).getAdapter(IFile.class);
if(file == null && obj instanceof XModelObject) {
XModelObject o = (XModelObject)obj;
Properties p = new Properties();
p.setProperty("onlySelectIfOpen", "true"); //$NON-NLS-1$ //$NON-NLS-2$
if(XActionInvoker.getAction("Open", o) != null) { //$NON-NLS-1$
XActionInvoker.invoke("Open", o, p); //$NON-NLS-1$
}
return;
}
IWorkbenchPage page = getSite().getPage();
//Using internal WorkbenchPage. Must change.
IEditorPart editor = page.findEditor(new FileEditorInput(file));
if(editor != null) {
page.bringToTop(editor);
return;
}
}
}
boolean isHandlingActivation = false;
class ActivationListener extends ShellAdapter {
public void shellActivated(ShellEvent event) {
if(isHandlingActivation) return;
event.widget.getDisplay().asyncExec(new Runnable() {
public void run() {
XJob.addRunnable(new ActivationXRunnable());
}
});
}
};
private void handleActivation() throws XModelException {
if(isHandlingActivation) return;
isHandlingActivation = true;
IProject[] ps = null;
ps = ModelUIPlugin.getWorkspace().getRoot().getProjects();
if(ps == null) return;
for (int i = 0; i < ps.length; i++) {
IModelNature n = EclipseResourceUtil.getModelNature(ps[i]);
if(n != null) n.getModel().update();
}
isHandlingActivation = false;
}
class ActivationXRunnable implements XRunnable {
public String getId() {
return "Activation"; //$NON-NLS-1$
}
public void run() {
try {
handleActivation();
} catch (XModelException e) {
ModelPlugin.getPluginLog().logError(e);
}
}
}
public ResourceComparator getComparator() {
return null; // TODO-3.3: does the contract allow you to not obey the get/set of comparator ?!
}
public void setComparator(ResourceComparator comparator) {
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.part.IShowInTarget#show(org.eclipse.ui.part.ShowInContext)
*/
public boolean show(ShowInContext context) {
Object input = context.getInput();
XModelObject o = null;
if (input instanceof IModelObjectEditorInput) {
o = ((IModelObjectEditorInput) input).getXModelObject();
} else if (input instanceof IFileEditorInput) {
IFileEditorInput fileInput = (IFileEditorInput) input;
IFile file = fileInput.getFile();
if (file == null)
return false;
o = getObjectByResource(file);
}
if (o == null)
return false;
ISelection newSelection = new StructuredSelection(o);
if (!getTreeViewer().getSelection().equals(o)) {
getTreeViewer().setSelection(newSelection);
}
return true;
}
}