/* ******************************************************************************
* Copyright (c) 2006-2012 XMind Ltd. and others.
*
* This file is a part of XMind 3. XMind releases 3 and
* above are dual-licensed under the Eclipse Public License (EPL),
* which is available at http://www.eclipse.org/legal/epl-v10.html
* and the GNU Lesser General Public License (LGPL),
* which is available at http://www.gnu.org/licenses/lgpl.html
* See http://www.xmind.net/license.html for details.
*
* Contributors:
* XMind Ltd. - initial API and implementation
*******************************************************************************/
package org.xmind.ui.internal.views;
import static org.xmind.ui.mindmap.MindMapUI.REQ_ADD_MARKER;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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.action.ToolBarManager;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
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.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.part.IContributedContentsView;
import org.eclipse.ui.part.ViewPart;
import org.xmind.core.Core;
import org.xmind.core.event.CoreEvent;
import org.xmind.core.event.CoreEventRegister;
import org.xmind.core.event.ICoreEventListener;
import org.xmind.core.event.ICoreEventRegister;
import org.xmind.core.event.ICoreEventSource;
import org.xmind.core.marker.IMarker;
import org.xmind.core.marker.IMarkerGroup;
import org.xmind.core.marker.IMarkerSheet;
import org.xmind.gef.EditDomain;
import org.xmind.gef.IViewer;
import org.xmind.gef.Request;
import org.xmind.gef.ui.editor.IGraphicalEditor;
import org.xmind.gef.ui.editor.IGraphicalEditorPage;
import org.xmind.ui.forms.WidgetFactory;
import org.xmind.ui.internal.MindMapMessages;
import org.xmind.ui.internal.dnd.MindMapElementTransfer;
import org.xmind.ui.internal.prefs.MarkerManagerPrefPage;
import org.xmind.ui.internal.wizards.MarkerExportWizard;
import org.xmind.ui.internal.wizards.MarkerImportWizard;
import org.xmind.ui.mindmap.IMindMapImages;
import org.xmind.ui.mindmap.MindMapUI;
import org.xmind.ui.util.MarkerImageDescriptor;
public class MarkerView extends ViewPart implements IContributedContentsView {
private class ShowMarkerManagerAction extends Action {
public ShowMarkerManagerAction() {
super(MindMapMessages.ShowMarkerManager_text);
setToolTipText(MindMapMessages.ShowMarkerManager_toolTip);
setImageDescriptor(MindMapUI.getImages().get(
IMindMapImages.ADD_MARKER, true));
}
public void run() {
PreferencesUtil.createPreferenceDialogOn(null,
MarkerManagerPrefPage.ID, null, null).open();
}
}
private class ImportMarkerAction extends Action {
public ImportMarkerAction() {
super(MindMapMessages.ImportMarkers_text);
setToolTipText(MindMapMessages.ImportMarkers_toolTip);
setImageDescriptor(MindMapUI.getImages().get(IMindMapImages.IMPORT,
true));
}
public void run() {
MarkerImportWizard wizard = new MarkerImportWizard(false);
wizard.init(PlatformUI.getWorkbench(), getCurrentSelection());
WizardDialog dialog = new WizardDialog(getSite().getShell(), wizard);
dialog.create();
dialog.open();
}
}
private class ExportMarkerAction extends Action {
public ExportMarkerAction() {
super(MindMapMessages.ExportMarkers_text);
setToolTipText(MindMapMessages.ExportMarkers_toolTip);
setImageDescriptor(MindMapUI.getImages().get(IMindMapImages.EXPORT,
true));
}
public void run() {
MarkerExportWizard wizard = new MarkerExportWizard();
wizard.init(PlatformUI.getWorkbench(), getCurrentSelection());
WizardDialog dialog = new WizardDialog(getSite().getShell(), wizard);
dialog.create();
dialog.open();
}
}
protected class MarkerAction extends Action {
private IMarker marker;
public MarkerAction(IMarker marker) {
super();
this.marker = marker;
setImageDescriptor(MarkerImageDescriptor.createFromMarker(marker,
32, 32));
setToolTipText(marker.getName());
}
public IMarker getMarker() {
return marker;
}
public void run() {
IViewer viewer = getCurrentViewer();
if (viewer != null) {
EditDomain domain = viewer.getEditDomain();
if (domain != null) {
Request req = new Request(REQ_ADD_MARKER).setViewer(viewer)
.setDomain(domain).setParameter(
MindMapUI.PARAM_MARKER_ID, marker.getId());
domain.handleRequest(req);
MindMapUI.getResourceManager().getRecentMarkerGroup()
.addMarker(marker);
}
}
}
private IViewer getCurrentViewer() {
IWorkbenchPage page = getSite().getPage();
if (page != null) {
IEditorPart editor = page.getActiveEditor();
if (editor != null && editor instanceof IGraphicalEditor) {
IGraphicalEditor ge = (IGraphicalEditor) editor;
IGraphicalEditorPage gp = ge.getActivePageInstance();
if (gp != null) {
return gp.getViewer();
}
}
}
return null;
}
}
private static interface ISectionPart {
Control createControl(Composite parent);
Control getControl();
void refresh();
void dispose();
}
protected class MarkerGroupPart implements ISectionPart, ICoreEventListener {
private IMarkerGroup group;
private boolean hasTitle;
private ToolBarManager toolbar = null;
private Control control = null;
private ICoreEventRegister eventRegister = null;
public MarkerGroupPart(IMarkerGroup group) {
this(group, true);
}
public MarkerGroupPart(IMarkerGroup group, boolean hasTitle) {
this.group = group;
this.hasTitle = hasTitle;
}
public IMarkerGroup getMarkerGroup() {
return group;
}
public Control createControl(Composite parent) {
if (control == null) {
if (toolbar == null) {
toolbar = new ToolBarManager(SWT.RIGHT | SWT.FLAT
| SWT.WRAP);
}
Composite c = factory.createComposite(parent);
GridLayout layout = new GridLayout(1, true);
layout.marginHeight = 2;
layout.marginWidth = 2;
c.setLayout(layout);
if (hasTitle) {
factory.createLabel(c, group.getName());
layout.verticalSpacing = 0;
} else {
layout.verticalSpacing = 2;
}
ToolBar tb = toolbar.createControl(c);
GridData data = new GridData(GridData.FILL_HORIZONTAL);
data.widthHint = 250;
tb.setLayoutData(data);
addDragSource(tb);
control = c;
refresh();
installListeners();
control.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
dispose();
}
});
}
return control;
}
private void addDragSource(final ToolBar toolbar) {
final DragSource dragSource = new DragSource(toolbar, DND.DROP_COPY);
dragSource.setTransfer(new Transfer[] { MindMapElementTransfer
.getInstance() });
dragSource.addDragListener(new DragSourceListener() {
ToolItem sourceItem;
public void dragStart(DragSourceEvent event) {
sourceItem = toolbar.getItem(new Point(event.x, event.y));
if (sourceItem == null)
event.doit = false;
else {
event.image = sourceItem.getImage();
}
}
public void dragSetData(DragSourceEvent event) {
if (sourceItem == null)
return;
int index = toolbar.indexOf(sourceItem);
IMarker marker = group.getMarkers().get(index);
event.data = new Object[] { marker };
}
public void dragFinished(DragSourceEvent event) {
}
});
toolbar.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
dragSource.dispose();
}
});
}
private void installListeners() {
if (group instanceof ICoreEventSource) {
eventRegister = new CoreEventRegister((ICoreEventSource) group,
this);
eventRegister.register(Core.MarkerAdd);
eventRegister.register(Core.MarkerRemove);
}
}
private void uninstallListeners() {
if (eventRegister != null)
eventRegister.unregisterAll();
}
public Control getControl() {
return control;
}
public void refresh() {
if (toolbar == null || control == null || control.isDisposed())
return;
toolbar.removeAll();
for (IMarker marker : group.getMarkers()) {
toolbar.add(new MarkerAction(marker));
}
toolbar.update(false);
ToolBar tb = toolbar.getControl();
GridData data = (GridData) tb.getLayoutData();
data.exclude = toolbar.isEmpty();
form.reflow(true);
}
public void dispose() {
uninstallListeners();
if (toolbar != null) {
toolbar.dispose();
toolbar = null;
}
if (control != null) {
control.dispose();
control = null;
}
}
public void handleCoreEvent(CoreEvent event) {
String type = event.getType();
if (Core.MarkerAdd.equals(type) || Core.MarkerRemove.equals(type)) {
refresh();
}
}
}
protected class MarkerSheetPart implements ISectionPart, ICoreEventListener {
private IMarkerSheet sheet;
private Composite composite;
private List<MarkerGroupPart> groupParts = new ArrayList<MarkerGroupPart>();
private ICoreEventRegister eventRegister = null;
public MarkerSheetPart(IMarkerSheet sheet) {
this.sheet = sheet;
}
public Control getControl() {
return composite;
}
public Control createControl(Composite parent) {
if (composite == null) {
composite = createComposite(parent);
refresh();
installListeners();
composite.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
dispose();
}
});
}
return composite;
}
private Composite createComposite(Composite parent) {
Composite composite = factory.createComposite(parent);
GridLayout layout = new GridLayout(1, true);
layout.marginHeight = 1;
layout.marginWidth = 1;
layout.verticalSpacing = 7;
composite.setLayout(layout);
return composite;
}
public void refresh() {
if (composite == null || composite.isDisposed())
return;
composite.setRedraw(false);
List<IMarkerGroup> newGroups = sheet.getMarkerGroups();
int i;
for (i = 0; i < newGroups.size(); i++) {
IMarkerGroup group = newGroups.get(i);
if (i < groupParts.size()) {
MarkerGroupPart part = groupParts.get(i);
IMarkerGroup g = part.getMarkerGroup();
if (group.equals(g)) {
continue;
}
}
MarkerGroupPart part = groupToPart.get(group);
if (part != null) {
reorderChild(part, i);
} else {
part = createChild(group);
addChild(part, i);
}
}
Object[] toTrim = groupParts.toArray();
for (; i < toTrim.length; i++) {
removeChild((MarkerGroupPart) toTrim[i]);
}
composite.setRedraw(true);
form.reflow(true);
}
public List<MarkerGroupPart> getGroupParts() {
return groupParts;
}
private void reorderChild(MarkerGroupPart part, int index) {
Control c = part.getControl();
if (c == null) {
c = part.createControl(composite);
c.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
}
groupParts.remove(part);
groupParts.add(index, part);
if (index == 0) {
c.moveAbove(null);
} else {
MarkerGroupPart g = groupParts.get(index - 1);
c.moveAbove(g.getControl());
}
}
private MarkerGroupPart createChild(IMarkerGroup group) {
MarkerGroupPart part = new MarkerGroupPart(group, true);
groupToPart.put(group, part);
return part;
}
private void addChild(MarkerGroupPart part, int index) {
groupParts.add(index, part);
Control c = part.createControl(composite);
c.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
}
private void removeChild(MarkerGroupPart part) {
groupParts.remove(part);
groupToPart.remove(part.getMarkerGroup());
part.dispose();
}
private void installListeners() {
if (sheet instanceof ICoreEventSource) {
eventRegister = new CoreEventRegister((ICoreEventSource) sheet,
this);
eventRegister.register(Core.MarkerGroupAdd);
eventRegister.register(Core.MarkerGroupRemove);
}
}
private void uninstallListeners() {
if (eventRegister != null)
eventRegister.unregisterAll();
}
public void dispose() {
uninstallListeners();
if (composite != null) {
composite.dispose();
composite = null;
}
for (Object o : groupParts.toArray()) {
MarkerGroupPart groupPart = (MarkerGroupPart) o;
groupToPart.remove(groupPart.getMarkerGroup());
groupPart.dispose();
}
groupParts.clear();
}
public void handleCoreEvent(CoreEvent event) {
String type = event.getType();
if (Core.MarkerGroupAdd.equals(type)
|| Core.MarkerGroupRemove.equals(type)) {
refresh();
}
}
}
private WidgetFactory factory;
private ScrolledForm form;
private MarkerGroupPart recentPart;
private MarkerSheetPart systemPart;
private MarkerSheetPart userPart;
private Map<IMarkerGroup, MarkerGroupPart> groupToPart = new HashMap<IMarkerGroup, MarkerGroupPart>();
private IAction showMarkerManagerAction;
private IAction importMarkerAction;
private IAction exportMarkerAction;
public void createPartControl(Composite parent) {
factory = new WidgetFactory(parent.getDisplay());
form = createForm(parent, factory);
form.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
if (factory != null) {
factory.dispose();
factory = null;
}
}
});
Composite composite = form.getBody();
composite.setLayout(new GridLayout(1, true));
createRecentSection(composite, factory);
createSystemSection(composite, factory);
createUserSection(composite, factory);
form.reflow(true);
showMarkerManagerAction = new ShowMarkerManagerAction();
importMarkerAction = new ImportMarkerAction();
exportMarkerAction = new ExportMarkerAction();
IMenuManager menu = getViewSite().getActionBars().getMenuManager();
menu.add(showMarkerManagerAction);
menu.add(new Separator());
menu.add(importMarkerAction);
menu.add(exportMarkerAction);
menu.add(new Separator());
menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
IToolBarManager toolBar = getViewSite().getActionBars()
.getToolBarManager();
toolBar.add(showMarkerManagerAction);
toolBar.add(new Separator());
toolBar.add(importMarkerAction);
toolBar.add(exportMarkerAction);
toolBar.add(new Separator());
toolBar.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
private ScrolledForm createForm(Composite parent, WidgetFactory factory) {
return factory.createScrolledForm(parent);
}
public Object getAdapter(Class adapter) {
if (adapter == IContributedContentsView.class) {
return this;
}
return super.getAdapter(adapter);
}
private void createUserSection(Composite composite, WidgetFactory factory) {
userPart = new MarkerSheetPart(MindMapUI.getResourceManager()
.getUserMarkerSheet());
createSection(composite, MindMapMessages.MarkerView_UserMarkers_label,
userPart, factory);
}
private void createSystemSection(Composite composite, WidgetFactory factory) {
systemPart = new MarkerSheetPart(MindMapUI.getResourceManager()
.getSystemMarkerSheet());
createSection(composite, MindMapMessages.MarkerView_XMindMarkers_label,
systemPart, factory);
}
private void createRecentSection(Composite composite, WidgetFactory factory) {
recentPart = new MarkerGroupPart(MindMapUI.getResourceManager()
.getRecentMarkerGroup(), false);
createSection(composite, MindMapMessages.MarkerView_RecentlyUsed_label,
recentPart, factory);
}
private void createSection(Composite parent, String title,
final ISectionPart part, WidgetFactory factory) {
Section section = factory.createSection(parent, Section.TITLE_BAR
| Section.TWISTIE | Section.EXPANDED | SWT.BORDER);
section.setText(title);
section.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
Control c = part.createControl(section);
section.setClient(c);
}
public void setFocus() {
if (form != null)
form.setFocus();
}
public IWorkbenchPart getContributingPart() {
return getSite().getPage().getActiveEditor();
}
public void dispose() {
super.dispose();
factory = null;
form = null;
recentPart = null;
systemPart = null;
userPart = null;
groupToPart.clear();
}
private IStructuredSelection getCurrentSelection() {
ISelection selection = getSite().getPage().getSelection();
if (selection instanceof IStructuredSelection)
return (IStructuredSelection) selection;
return StructuredSelection.EMPTY;
}
}