blob: f1fd0f9b88e4b1c2b41a95d24615f6a7128b6dc5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004-2008 Istvan Rath and Daniel Varro
* 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:
* Istvan Rath - initial API and implementation
*******************************************************************************/
package org.eclipse.viatra2.treeeditor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.IElementComparer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IPathEditorInput;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.dialogs.SaveAsDialog;
import org.eclipse.ui.ide.IGotoMarker;
import org.eclipse.ui.part.EditorPart;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.viatra2.core.IModelElement;
import org.eclipse.viatra2.core.IModelSpace;
import org.eclipse.viatra2.framework.FrameworkManager;
import org.eclipse.viatra2.framework.FrameworkManagerException;
import org.eclipse.viatra2.framework.IFramework;
import org.eclipse.viatra2.framework.properties.IViatraPropertyChangedListener;
import org.eclipse.viatra2.treeeditor.actions.ExportToVTMLAction;
import org.eclipse.viatra2.treeeditor.actions.LocalDeleteAction;
import org.eclipse.viatra2.treeeditor.actions.NavigateRelationAction;
import org.eclipse.viatra2.treeeditor.actions.NavigateRelationSourceAction;
import org.eclipse.viatra2.treeeditor.actions.NewEntityAction;
import org.eclipse.viatra2.treeeditor.actions.NewRelationAction;
import org.eclipse.viatra2.treeeditor.actions.RenameAction;
import org.eclipse.viatra2.treeeditor.actions.ViatraDeleteAction;
import org.eclipse.viatra2.treeeditor.actions.ViatraRedoAction;
import org.eclipse.viatra2.treeeditor.actions.ViatraTreeEditorSelectionAction;
import org.eclipse.viatra2.treeeditor.actions.ViatraUndoAction;
import org.eclipse.viatra2.treeeditor.commands.ViatraEditorCommandStack;
import org.eclipse.viatra2.treeeditor.menu.ViatraTreeEditorActionBarContributor;
import org.eclipse.viatra2.treeeditor.menu.ViatraTreeEditorMenuListener;
import org.eclipse.viatra2.treeeditor.properties.VPMPropertySheetPage;
import org.eclipse.viatra2.treeeditor.providers.IDirtyFlagChangedListener;
import org.eclipse.viatra2.treeeditor.providers.IMessageDialogProvider;
import org.eclipse.viatra2.treeeditor.providers.ViatraContentProvider;
import org.eclipse.viatra2.treeeditor.providers.ViatraEditorPropertyProvider;
import org.eclipse.viatra2.treeeditor.providers.ViatraLabelProvider;
import org.eclipse.viatra2.treeeditor.providers.ViatraRootProvider;
import org.eclipse.viatra2.treeeditor.providers.ViatraTreeMouseListener;
import org.eclipse.viatra2.treeeditor.providers.ViatraTreeviewSorter;
import org.eclipse.viatra2.treeeditor.resource.FrameworkEditorInput;
import org.eclipse.viatra2.treeeditor.transfer.ViatraEditorDragSourceListener;
import org.eclipse.viatra2.treeeditor.transfer.ViatraEditorDropTargetAdapter;
public class ViatraTreeEditor extends EditorPart implements
//ISelectionListener,
ISelectionChangedListener,
IDirtyFlagChangedListener, IMessageDialogProvider,
IViatraPropertyChangedListener {
/* (non-Javadoc)
* @see org.eclipse.ui.part.EditorPart#setInput(org.eclipse.ui.IEditorInput)
*/
@Override
protected void setInput(IEditorInput input)
{
if (getEditorInput() != null && getEditorInput() instanceof FileEditorInput)
{
IFile file = ((FileEditorInput) getEditorInput()).getFile();
file.getWorkspace().removeResourceChangeListener(getResourceTracker());
}
super.setInput(input);
manageInputChange();
if (getEditorInput() != null && getEditorInput() instanceof FileEditorInput)
{
IFile file = ((FileEditorInput) getEditorInput()).getFile();
file.getWorkspace().addResourceChangeListener(getResourceTracker());
}
}
/**
* Closes this editor.
* @param save true if the editor should save its contents before closing
*/
void closeEditor(final boolean save)
{
getSite().getShell().getDisplay().syncExec(new Runnable()
{
public void run()
{
getSite().getPage().closeEditor(ViatraTreeEditor.this, save);
}
});
}
/** the resource tracker instance */
private ResourceTracker resourceTracker;
/**
* Returns the resource tracker instance
* @return
*/
private ResourceTracker getResourceTracker()
{
if (resourceTracker == null)
{
resourceTracker = new ResourceTracker();
}
return resourceTracker;
}
/**
* This class listens to changes to the file system in the workspace, and
* makes changes accordingly.
* 1) An open, saved file gets deleted -> close the editor
* 2) An open file gets renamed or moved -> change the editor's input accordingly
*
* @author Gunnar Wagenknecht; modified by Istvan Rath
*/
private class ResourceTracker implements IResourceChangeListener, IResourceDeltaVisitor
{
/* (non-Javadoc)
* @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent)
*/
public void resourceChanged(IResourceChangeEvent event)
{
IResourceDelta delta = event.getDelta();
try
{
if (delta != null)
delta.accept(this);
}
catch (CoreException exception)
{
//Activator.getDefault().getLog().log(exception.getStatus());
exception.printStackTrace();
}
}
/* (non-Javadoc)
* @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse.core.resources.IResourceDelta)
*/
public boolean visit(IResourceDelta delta)
{
if (delta == null || !delta.getResource().equals(((IFileEditorInput) getEditorInput()).getFile()))
return true;
else
{
if (delta.getKind() == IResourceDelta.REMOVED)
{
if ((IResourceDelta.MOVED_TO & delta.getFlags()) == 0)
{
// if the file was deleted
// NOTE: The case where an open, unsaved file is deleted is being handled by the
// PartListener added to the Workbench in the initialize() method.
if (!isDirty())
closeEditor(false);
}
else
{
// else if it was moved or renamed
final IFile newFile = ResourcesPlugin.getWorkspace().getRoot().getFile(delta.getMovedToPath());
Display display = getSite().getShell().getDisplay();
display.syncExec(new Runnable()
{
public void run()
{
setInput(new FileEditorInput(newFile));
}
});
}
}
else if (delta.getKind() == IResourceDelta.CHANGED)
{
for (IMarkerDelta md : delta.getMarkerDeltas())
{
IMarker marker = md.getMarker();
if (iFramework!=null) // marker.exists()
{
try {
Map attrs = marker.getAttributes();
if (attrs!=null && attrs.containsKey(IMarker.LOCATION))
{
// marker is ready, we can process it.
String fqns = attrs.get(IMarker.LOCATION).toString();
// refresh elements in the tree viewer
String[] fqn = fqns.split(";");
for (final String _fqn : fqn)
{
Display.getDefault().syncExec(new Runnable(){
public void run() {
if (getTreeViewer()!=null)
{
getTreeViewer().refresh( iFramework.getTopmodel().getModelManager().getElementByName(_fqn) );
}
}
});
}
}
} catch (CoreException e) {
iFramework.getLogger().error("[ResourceTracker::visit()] "+e.getMessage());
//iFramework.getLogger().printStackTrace(e);
}
}
}
}
}
return false;
}
}
private TreeViewer treeViewer;
// private DrillDownAdapter drillDownAdapter;
// *********************
// LOCAL ACTIONS
private NewEntityAction iNewEntityAction;
private NewRelationAction iNewRelationAction;
private NavigateRelationAction iNavigateAction;
private NavigateRelationSourceAction iNavigateSourceAction;
//private RunAction iRunAction;
private ExportToVTMLAction iExportAction;
private RenameAction iRenameAction;
private LocalDeleteAction iLocalDeleteAction;
private Map<String,List<ViatraTreeEditorSelectionAction>> contributedActions;
public LocalDeleteAction getLocalDeleteAction()
{
return iLocalDeleteAction;
}
public RenameAction getRenameAction() {
return iRenameAction;
}
public ExportToVTMLAction getExportAction() {
return iExportAction;
}
public NewEntityAction getNewEntityAction() {
return iNewEntityAction;
}
public NewRelationAction getNewRelationAction() {
//iNewRelationAction.updateSelf();
return iNewRelationAction;
}
public NavigateRelationAction getNavigateRelationAction()
{
return iNavigateAction;
}
// public RunAction getRunAction() {
// return iRunAction;
// }
// GLOBAL ACTIONS
private ViatraDeleteAction iDeleteAction;
private ViatraUndoAction iUndoAction;
private ViatraRedoAction iRedoAction;
public ViatraDeleteAction getDeleteAction() {
return iDeleteAction;
}
public ViatraRedoAction getRedoAction() {
return iRedoAction;
}
public ViatraUndoAction getUndoAction() {
return iUndoAction;
}
// COMMANDSTACK
private final ViatraEditorCommandStack iCommandStack;
public ViatraEditorCommandStack getCommandStack() {
return iCommandStack;
}
// *********************
// MEMBERS
private boolean isDirty = false;
private FrameworkManager iFrameWorkManager;
private IFramework iFramework;
private String iShortFilename;
private String iFilename;
private IModelSpace iModelSpace;
// **********************
public IFramework getFramework() {
return iFramework;
}
public TreeViewer getTreeViewer() {
return treeViewer;
}
protected void setTreeViewer(TreeViewer viewer) {
this.treeViewer = viewer;
}
public ViatraTreeEditor() {
iCommandStack = new ViatraEditorCommandStack(this);
}
@Override
public void doSave(IProgressMonitor monitor)
{
IRunnableWithProgress runnable = new IRunnableWithProgress()
{
public void run(IProgressMonitor _monitor) throws InvocationTargetException, InterruptedException
{
try
{
iFramework.saveFile(iFilename);
//ResourcesPlugin.getWorkspace().getRoot().refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor());
// this is crazy...
// instead:
((FileEditorInput)ViatraTreeEditor.this.getEditorInput()).getFile().refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor());
}
catch (Exception e)
{
throw new InvocationTargetException(e);
}
}
};
runLongTransaction(runnable);
iFramework.getLogger().info("Saved " + iFilename);
iCommandStack.markSave();
isDirty = false;
updateActions();
firePropertyChange(PROP_DIRTY);
firePropertyChange(PROP_TITLE);
}
@Override
public void doSaveAs() {
SaveAsDialog dd = new SaveAsDialog(getEditorSite().getShell());
dd.setBlockOnOpen(true);
dd.setTitle("Select new file");
dd.setOriginalName(iShortFilename);
if (Window.OK == dd.open())
{
IFile ifile = ResourcesPlugin.getWorkspace().getRoot().getFile(dd.getResult());
iFilename = ifile.getLocation().toOSString();
iShortFilename = ifile.getLocation().lastSegment();
doSave(null);
setInput(new FileEditorInput(ifile));
manageInputChange();
}
}
@Override
public boolean isDirty() {
return isDirty || iCommandStack.isDirty();
}
public void setDirty() {
isDirty = true;
// updateActions();
Display.getDefault().asyncExec(new Runnable(){
public void run()
{
firePropertyChange(PROP_DIRTY);
}
});
}
@Override
public boolean isSaveAsAllowed() {
return true;
}
@Override
public void createPartControl(Composite parent) {
TreeViewer treeviewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
setTreeViewer(treeviewer);
getTreeViewer().addDropSupport(DND.DROP_COPY|DND.DROP_MOVE|DND.DROP_LINK,ViatraEditorDropTargetAdapter.getTransfers(),new ViatraEditorDropTargetAdapter(this));
getTreeViewer().addDragSupport(DND.DROP_COPY|DND.DROP_MOVE|DND.DROP_LINK,ViatraEditorDropTargetAdapter.getTransfers(),new ViatraEditorDragSourceListener(this));
// drillDownAdapter = new DrillDownAdapter(getTreeViewer());
// initialize cell editors
//TextCellEditor ce = new TextCellEditor(getTreeViewer().getTree(),SWT.BORDER);
//getTreeViewer().setCellEditors(new CellEditor[]{ce});
//getTreeViewer().setColumnProperties(new String[]{"localname"});
//getTreeViewer().setCellModifier(new ViatraTreeCellModifier());
// register double click listener for direct editing
getTreeViewer().getTree().addMouseListener(new ViatraTreeMouseListener(this, getTreeViewer().getTree()));
getTreeViewer().setUseHashlookup(true);
createActions();
contributeToActionBars();
initializeContextMenu();
getSite().setSelectionProvider(getTreeViewer());
initializeTreeViewer();
}
private void manageInputChange()
{
IEditorInput element = getEditorInput();
iShortFilename = element.getName();
iFilename = null;
if (element instanceof IPathEditorInput) {
// File from workspace
iFilename = ((IPathEditorInput) element).getPath().toOSString();
//iFramework = (IFramework) iFrameWorkManager.createFramework(iFilename);
}
else if (element instanceof FrameworkEditorInput) {
iFramework = ((FrameworkEditorInput)element).getFramework();
iFilename = iFramework.getCurrentFilename();
}
else {
showMessage("Invalid input received for Viatra Tree Editor");
return;
}
if (iFramework!=null) {
if (iFilename != null) {
iFramework.setCurrentFileName(iFilename);
} else {
iFramework.setCurrentFileName(iShortFilename);
}
}
firePropertyChange(PROP_TITLE);
}
public void runLongTransaction(final IRunnableWithProgress runnable)
{
final Display display = Display.getDefault();
display.syncExec(new Runnable() {
public void run() {
ProgressMonitorDialog d= new ProgressMonitorDialog(display.getActiveShell());
try {
d.run(true, false, runnable);
} catch (Exception e) {
e.printStackTrace();
showMessage(e.getMessage());
iFramework.getLogger().fatal("Error executing operation ("+e.getClass().getCanonicalName()+") ["+e.getMessage()+"]");
}
}
});
}
protected void initializeTreeViewer() {
iFrameWorkManager = FrameworkManager.getInstance();
// Load user's file into the modelspace
manageInputChange();
final IRunnableWithProgress runnable = new IRunnableWithProgress()
{
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException
{
if (iFramework==null && getEditorInput() instanceof IPathEditorInput)
{
try
{
monitor.beginTask("Loading VPM modelspace", 3);
monitor.worked(2);
iFramework = iFrameWorkManager.createFramework(iFilename);
monitor.done();
}
catch (FrameworkManagerException e)
{
e.printStackTrace();
showMessage(e.getMessage());
}
}
}
};
runLongTransaction(runnable);
// set-up phase
if (iFramework!=null)
{
iModelSpace = iFramework.getTopmodel();
getTreeViewer().addSelectionChangedListener(this);
getTreeViewer().setContentProvider(new ViatraContentProvider(getTreeViewer(), this));
getTreeViewer().setLabelProvider(new ViatraLabelProvider(this));
getTreeViewer().setSorter(new ViatraTreeviewSorter());
getTreeViewer().setComparer(new IElementComparer()
{
public boolean equals(Object a, Object b) {
if (a == null && b == null) return true;
if (a == null || b == null) return false;
if (a instanceof IModelElement && b instanceof IModelElement)
return a.equals(b);
if (a instanceof ViatraRootProvider && b instanceof ViatraRootProvider)
return (a == b);
return false;
}
public int hashCode(Object element) {
return element == null ? 0 : element.hashCode();
}
});
getTreeViewer().setInput(new ViatraRootProvider(iModelSpace.getModelManager().getRoot()));
firePropertyChange(PROP_TITLE);
// Add self as VPM properties listener
iFramework.getProperties().getProvider(ViatraEditorPropertyProvider.VIATRA_EDITOR_PROVIDER_ID).addListener(this);
}
}
@Override
public String getTitle() {
return iShortFilename;
}
@Override
public String getTitleToolTip() {
return iFilename;
}
@Override
public void dispose() {
//getSite().getWorkbenchWindow().getSelectionService().removeSelectionListener(this);
if (iFrameWorkManager != null && iFramework != null) {
iFramework.getProperties().getProvider(ViatraEditorPropertyProvider.VIATRA_EDITOR_PROVIDER_ID).removeListener(this);
try {
iFrameWorkManager.disposeFramework(iFramework.getId());
} catch (Exception e) {
showMessage(e.getMessage());
}
}
if (getEditorInput() != null && getEditorInput() instanceof FileEditorInput)
{
IFile file = ((FileEditorInput) getEditorInput()).getFile();
file.getWorkspace().removeResourceChangeListener(getResourceTracker());
}
super.dispose();
}
public void updateLabels()
{
if (treeViewer != null)
treeViewer.refresh(true);
}
VPMPropertySheetPage iPropsPage;
private VPMPropertySheetPage getPropsPage()
{
if (iPropsPage == null) iPropsPage = new VPMPropertySheetPage(this);
return iPropsPage;
}
IGotoMarker gotoMarker;
@Override
public Object getAdapter(Class type) {
if (type == org.eclipse.ui.views.properties.IPropertySheetPage.class) {
return getPropsPage();
}
if (type == IGotoMarker.class)
{
if (gotoMarker==null)
{
gotoMarker = new IGotoMarker(){
public void gotoMarker(IMarker marker)
{
if (marker.exists())
{
try
{
Map attrs = marker.getAttributes();
if (attrs!=null && attrs.containsKey(IMarker.LOCATION))
{
// marker is ready, we can process it.
String fqns = attrs.get(IMarker.LOCATION).toString();
// refresh elements in the tree viewer
String[] fqn = fqns.split(";");
for (final String _fqn : fqn)
{
Display.getDefault().asyncExec(new Runnable(){
public void run() {
getTreeViewer().reveal( iFramework.getTopmodel().getModelManager().getElementByName(_fqn) );
}
});
}
}
} catch (CoreException e) {
iFramework.getLogger().info("[gotoMarker()] "+e.getMessage());
}
}
}
};
}
return gotoMarker;
}
return super.getAdapter(type);
}
@Override
public void init(IEditorSite site, IEditorInput input) throws PartInitException {
setSite(site);
setInput(input);
}
protected void initializeContextMenu() {
MenuManager menuMgr = new MenuManager("ViatraTreeEditorPopupMenu");
menuMgr.setRemoveAllWhenShown(true);
ViatraTreeEditorMenuListener menuListener = new ViatraTreeEditorMenuListener(this);
menuMgr.addMenuListener(menuListener);
Menu menu = menuMgr.createContextMenu(getTreeViewer().getControl());
getTreeViewer().getControl().setMenu(menu);
}
protected void createActions() {
// locals
iLocalDeleteAction = new LocalDeleteAction(this);
iNewEntityAction = new NewEntityAction(this);
iNavigateAction = new NavigateRelationAction(this);
iNavigateSourceAction = new NavigateRelationSourceAction(this);
iNewRelationAction = new NewRelationAction(this);
iExportAction = new ExportToVTMLAction(this);
iRenameAction = new RenameAction(this);
// globals
if (getEditorSite().getActionBarContributor()!=null && getEditorSite().getActionBarContributor() instanceof ViatraTreeEditorActionBarContributor)
{
iDeleteAction = ((ViatraTreeEditorActionBarContributor)getEditorSite().getActionBarContributor()).getDeleteAction();
iUndoAction = ((ViatraTreeEditorActionBarContributor)getEditorSite().getActionBarContributor()).getUndoAction();
iRedoAction = ((ViatraTreeEditorActionBarContributor)getEditorSite().getActionBarContributor()).getRedoAction();
}
// contributed
contributedActions = // new LinkedList<ViatraTreeEditorSelectionAction>();
//contributedActions.addAll(
Plugin.getDefault().getContributedActions();
for (List<ViatraTreeEditorSelectionAction> cAs : contributedActions.values())
{
for (ViatraTreeEditorSelectionAction a : cAs)
{
a.setWorkbenchPart(this);
}
// perform an ordering
Collections.sort(cAs, new Comparator<ViatraTreeEditorSelectionAction>(){
public int compare(ViatraTreeEditorSelectionAction arg0,
ViatraTreeEditorSelectionAction arg1) {
return arg0.getOrderNumber().compareTo(arg1.getOrderNumber());
}
});
}
}
@Override
public void setFocus() {
getTreeViewer().getControl().setFocus();
// update global actions
updateActions();
}
public void updateActions() {
// update global actions
if (iDeleteAction!=null) iDeleteAction.updateSelf(this);
if (iUndoAction!=null) iUndoAction.updateSelf(this);
if (iRedoAction!=null) iRedoAction.updateSelf(this);
getEditorSite().getActionBars().getToolBarManager().update(true);
// update local actions (not really necessary)
iLocalDeleteAction.updateSelf();
iNewEntityAction.updateSelf();
iNewRelationAction.updateSelf();
iExportAction.updateSelf();
iNavigateAction.updateSelf();
iRenameAction.updateSelf();
// iRunAction.updateSelf();
// update contributed actions
for (List<ViatraTreeEditorSelectionAction> as : getContributedActions().values())
{
for (ViatraTreeEditorSelectionAction a : as)
{
a.updateSelf();
}
}
}
public void showMessage(final String message) {
Display.getDefault().syncExec(new Runnable(){
public void run() {
MessageDialog.openInformation(getSite().getShell(),"Viatra Tree Editor", message);
}
});
}
private void contributeToActionBars() {
IActionBars bars = getEditorSite().getActionBars();
registerGlobalActions(bars);
fillLocalPullDown(bars.getMenuManager());
}
private void fillLocalPullDown(IMenuManager manager) {
// TODO local pull down empty
}
private void registerGlobalActions(IActionBars bars) {
// register our global actions
if (iDeleteAction!=null) bars.setGlobalActionHandler(iDeleteAction.getId(),iDeleteAction);
if (iUndoAction!=null) bars.setGlobalActionHandler(iUndoAction.getId(),iUndoAction);
if (iRedoAction!=null) bars.setGlobalActionHandler(iRedoAction.getId(),iRedoAction);
}
public void propertyChanged(String providerID, String propertyID, String oldVal, String newVal) {
Display.getDefault().asyncExec(new Runnable(){
public void run() {
updateLabels();
}
});
}
/**
* @return the contributedActions
*/
public Map<String,List<ViatraTreeEditorSelectionAction>> getContributedActions() {
return contributedActions;
}
public void selectionChanged(SelectionChangedEvent event)
{
updateActions();
}
public IAction getNavigateRelationSourceAction() {
return iNavigateSourceAction;
}
//marker support
}