package org.xmind.ui.internal.properties;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.Assert;
import org.eclipse.e4.core.commands.ECommandService;
import org.eclipse.e4.core.commands.EHandlerService;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.workbench.modeling.EModelService;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.jface.resource.ResourceManager;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Rectangle;
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.ui.IActionBars;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.events.IHyperlinkListener;
import org.eclipse.ui.forms.widgets.Hyperlink;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.internal.E4PartWrapper;
import org.eclipse.ui.internal.e4.compatibility.CompatibilityPart;
import org.eclipse.ui.part.IContributedContentsView;
import org.eclipse.ui.part.IPageSite;
import org.eclipse.ui.part.PageBook;
import org.eclipse.ui.services.IServiceLocator;
import org.xmind.core.style.IStyled;
import org.xmind.gef.ui.editor.IGraphicalEditor;
import org.xmind.gef.ui.editor.IGraphicalEditorPage;
import org.xmind.gef.ui.properties.IPropertyPartContainer;
import org.xmind.gef.ui.properties.IPropertySectionPart;
import org.xmind.ui.commands.CommandMessages;
import org.xmind.ui.commands.ModifyStyleCommand;
import org.xmind.ui.forms.WidgetFactory;
import org.xmind.ui.internal.MindMapMessages;
import org.xmind.ui.internal.e4models.IModelConstants;
import org.xmind.ui.internal.e4models.ViewModelFolderRenderer;
import org.xmind.ui.internal.e4models.ViewModelPart;
import org.xmind.ui.mindmap.ICategoryAnalyzation;
import org.xmind.ui.mindmap.ICategoryManager;
import org.xmind.ui.mindmap.MindMapUI;
import org.xmind.ui.resources.ColorUtils;
public class PropertiesPart extends ViewModelPart
implements ISelectionChangedListener, IPropertyPartContainer,
IContributedContentsView {
private static class SectionRecord {
String id;
IPropertySectionPart section;
Section control;
boolean visible;
public SectionRecord(String id, IPropertySectionPart section) {
this.id = id;
this.section = section;
}
}
private static final int DEFAULT_SECTION_WIDTH = 200;
private IGraphicalEditor sourceEditor;
private static PropertySectionContributorManager manager = PropertySectionContributorManager
.getInstance();
private List<SectionRecord> sections = new ArrayList<SectionRecord>();
private CTabItem ti;
private String modeLabel;
private Composite composite;
private PageBook viewerStack;
private Control defaultPage;
private Composite contentComposite;
private WidgetFactory widgetFactory;
private ScrolledForm form;
private String title;
private Hyperlink resetStyleControl;
private ResourceManager resources;
protected void init() {
super.init();
EModelService modelService = getAdapter(EModelService.class);
MApplication application = getAdapter(MApplication.class);
ArrayList<String> tags = new ArrayList<String>();
tags.add(IModelConstants.TAG_EDITOR);
tags.add(IModelConstants.TAG_ACTIVE);
List<MPart> editors = modelService.findElements(application,
IModelConstants.PART_ID_COMPATIBILITY_EDITOR, MPart.class,
tags);
if (editors != null && !editors.isEmpty()) {
MPart editor = editors.get(0);
handlePartActivated(editor);
}
initContent();
}
private void initContent() {
for (SectionRecord rec : sections) {
rec.section.init(this, getContributedEditor());
}
if (sourceEditor != null) {
sourceEditor.getSite().getSelectionProvider()
.addSelectionChangedListener(this);
final ISelection selection = sourceEditor.getSite()
.getSelectionProvider().getSelection();
if (selection != null && !selection.isEmpty()) {
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
selectionChanged(new SelectionChangedEvent(
sourceEditor.getSite().getSelectionProvider(),
selection));
}
});
}
}
}
protected void createContent(Composite parent) {
CTabFolder ctf = new CTabFolder(parent, SWT.BORDER);
ctf.setRenderer(new ViewModelFolderRenderer(ctf));
ctf.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
ti = new CTabItem(ctf, SWT.NONE);
MPart partModel = getAdapter(MPart.class);
modeLabel = partModel.getLocalizedLabel();
// ti.setToolTipText(getToolTip(partModel.getLocalizedTooltip()));
ti.setText(modeLabel);
ctf.setSelection(ti);
Composite contentContainer = new Composite(ctf, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginWidth = 0;
layout.marginHeight = 0;
layout.horizontalSpacing = 0;
layout.verticalSpacing = 0;
contentContainer.setLayout(layout);
ti.setControl(contentContainer);
Control content = doCreateContent(contentContainer);
content.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
addTopRight(ctf, true);
adjustViewMenuBar(true);
}
protected Control doCreateContent(Composite parent) {
resources = new LocalResourceManager(JFaceResources.getResources(),
parent);
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginWidth = 0;
layout.marginHeight = 0;
layout.verticalSpacing = 0;
layout.horizontalSpacing = 0;
composite.setLayout(layout);
composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
viewerStack = new PageBook(composite, SWT.NONE);
viewerStack.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
defaultPage = createDefaultPage(viewerStack);
contentComposite = new Composite(viewerStack, SWT.NONE);
GridLayout contantLayout = new GridLayout();
contantLayout.marginWidth = 0;
contantLayout.marginHeight = 0;
contantLayout.verticalSpacing = 0;
contantLayout.horizontalSpacing = 0;
contentComposite.setLayout(contantLayout);
contentComposite
.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
this.widgetFactory = new WidgetFactory(contentComposite.getDisplay());
form = widgetFactory.createScrolledForm(contentComposite);
form.setLayoutData(new GridData(GridData.FILL_BOTH));
form.setMinWidth(DEFAULT_SECTION_WIDTH);
form.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
if (widgetFactory != null) {
widgetFactory.dispose();
widgetFactory = null;
}
}
});
createSectionControls(form, form.getBody());
Composite internalComposite = new Composite(form.getBody(), SWT.NONE);
internalComposite.setBackground(form.getBody().getBackground());
internalComposite.setLayout(new GridLayout(1, false));
internalComposite
.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, true));
createExtendSectionControls(widgetFactory, internalComposite);
form.reflow(true);
viewerStack.showPage(
sourceEditor == null ? defaultPage : contentComposite);
this.composite = composite;
return composite;
}
private Composite createDefaultPage(Composite parent) {
Composite page = new Composite(parent, SWT.NONE);
GridLayout gridLayout = new GridLayout(1, false);
gridLayout.marginWidth = 0;
gridLayout.marginHeight = 0;
page.setLayout(gridLayout);
Label label = new Label(page, SWT.LEFT | SWT.WRAP);
label.setText(MindMapMessages.PropertiesPart_DefaultPage_message);
label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
return page;
}
@SuppressWarnings("restriction")
protected boolean postConfiguration(IWorkbenchPart workbenchPart,
MPart part) {
super.postConfiguration(workbenchPart, part);
IWorkbenchPartSite site = workbenchPart.getSite();
IGraphicalEditor editor = getContributedEditor();
if (site instanceof IViewSite && editor != null) {
IActionBars sourceActionBars = editor.getEditorSite()
.getActionBars();
IActionBars targetActionBars = ((IViewSite) site).getActionBars();
if (sourceActionBars == null || targetActionBars == null)
return false;
IServiceLocator serviceLocator = targetActionBars
.getServiceLocator();
if (serviceLocator == null)
return false;
IEclipseContext eclipseContext = serviceLocator
.getService(IEclipseContext.class);
eclipseContext.set(ECommandService.class,
serviceLocator.getService(ECommandService.class));
eclipseContext.set(EHandlerService.class,
serviceLocator.getService(EHandlerService.class));
retargetAction(sourceActionBars, targetActionBars,
ActionFactory.UNDO.getId());
retargetAction(sourceActionBars, targetActionBars,
ActionFactory.REDO.getId());
return true;
}
return false;
}
private void retargetAction(IActionBars sourceActionBars,
IActionBars targetActionBars, String actionId) {
IAction handler = sourceActionBars.getGlobalActionHandler(actionId);
if (handler != null) {
targetActionBars.setGlobalActionHandler(actionId, handler);
}
}
private void setEditor(IGraphicalEditor editor) {
if (this.sourceEditor == editor)
return;
if (this.sourceEditor != null)
this.sourceEditor.getSite().getSelectionProvider()
.removeSelectionChangedListener(this);
this.sourceEditor = editor;
if (viewerStack != null && !viewerStack.isDisposed()) {
if (sourceEditor != null) {
if (contentComposite != null
&& !contentComposite.isDisposed()) {
initContent();
viewerStack.showPage(contentComposite);
}
} else {
if (defaultPage != null && !defaultPage.isDisposed())
viewerStack.showPage(defaultPage);
}
}
}
public IGraphicalEditor getContributedEditor() {
return sourceEditor;
}
private void addSection(String id, IPropertySectionPart section) {
Assert.isNotNull(id);
Assert.isNotNull(section);
removeSection(id);
SectionRecord rec = new SectionRecord(id, section);
sections.add(rec);
section.init(this, sourceEditor);
if (form != null && !form.isDisposed()) {
createSectionControl(form.getBody(), rec);
}
}
private void removeSection(String id) {
SectionRecord rec = getRec(id);
if (rec == null)
return;
if (sections.remove(rec)) {
rec.section.dispose();
if (rec.control != null && !rec.control.isDisposed()) {
rec.control.dispose();
}
}
}
private List<String> getSectionIds() {
ArrayList<String> list = new ArrayList<String>(sections.size());
for (SectionRecord rec : sections) {
list.add(rec.id);
}
return list;
}
private List<String> getVisibleSectionIds() {
ArrayList<String> list = new ArrayList<String>(sections.size());
for (SectionRecord rec : sections) {
if (rec.visible)
list.add(rec.id);
}
return list;
}
private void setSectionVisible(String id, boolean visible) {
SectionRecord rec = getRec(id);
if (rec == null || rec.visible == visible)
return;
rec.visible = visible;
if (rec.control != null && !rec.control.isDisposed()) {
GridData gd = (GridData) rec.control.getLayoutData();
gd.exclude = !visible;
rec.control.setVisible(visible);
}
}
private void reflow() {
if (form != null && !form.isDisposed()) {
form.reflow(true);
form.getParent().layout();
}
}
private void moveSectionFirst(SectionRecord rec) {
if (rec.control != null && !rec.control.isDisposed()) {
rec.control.moveAbove(null);
rec.control.getParent().layout();
}
}
private void moveSectionAfter(String id, String lastId) {
SectionRecord rec = getRec(id);
if (rec == null)
return;
SectionRecord lastRec = getRec(lastId);
if (lastRec == null) {
moveSectionFirst(rec);
} else {
if (rec.control != null && !rec.control.isDisposed()
&& lastRec.control != null
&& !lastRec.control.isDisposed()) {
rec.control.moveBelow(lastRec.control);
rec.control.getParent().layout();
}
}
}
private SectionRecord getRec(String id) {
if (id == null)
return null;
for (SectionRecord rec : sections) {
if (id.equals(rec.id))
return rec;
}
return null;
}
private void createExtendSectionControls(WidgetFactory widgetFactory,
Composite parent) {
createResetStyleControl(widgetFactory, parent);
}
private void createResetStyleControl(WidgetFactory widgetFactory,
Composite parent) {
resetStyleControl = widgetFactory.createHyperlink(parent,
MindMapMessages.MindMapPropertySheetPage_ResetStyle_text,
SWT.NONE);
resetStyleControl.setUnderlined(false);
resetStyleControl.setLayoutData(
new GridData(SWT.BEGINNING, SWT.CENTER, true, false));
resetStyleControl.addHyperlinkListener(new IHyperlinkListener() {
public void linkExited(HyperlinkEvent e) {
resetStyleControl.setUnderlined(false);
}
public void linkEntered(HyperlinkEvent e) {
resetStyleControl.setUnderlined(true);
}
public void linkActivated(HyperlinkEvent e) {
resetStyles();
}
});
resetStyleControl.setFont((Font) resources.get(
JFaceResources.getDefaultFontDescriptor().increaseHeight(-1)));
resetStyleControl.setForeground(
(Color) resources.get(ColorUtils.toDescriptor("#0082F9"))); //$NON-NLS-1$
}
private boolean shouldHasResetStyleControl(ISelection selection) {
if (!(selection instanceof StructuredSelection))
return false;
boolean result = true;
Object[] resetedStyleds = ((StructuredSelection) selection).toArray();
if (resetedStyleds != null) {
for (Object styled : resetedStyleds) {
if (!(styled instanceof IStyled)) {
result = false;
}
}
}
return result;
}
private void resetStyles() {
IGraphicalEditor editor = getContributedEditor();
if (editor == null)
return;
IGraphicalEditorPage activePageInstance = editor
.getActivePageInstance();
if (activePageInstance == null)
return;
ISelectionProvider selectionProvider = activePageInstance
.getSelectionProvider();
if (selectionProvider == null)
return;
ISelection selection = selectionProvider.getSelection();
if (!(selection instanceof StructuredSelection))
return;
Object[] resetedStyleds = ((StructuredSelection) selection).toArray();
if (resetedStyleds != null) {
for (Object styled : resetedStyleds) {
if (styled instanceof IStyled) {
IStyled resetedStyled = (IStyled) styled;
ModifyStyleCommand modifyStyleCommand = new ModifyStyleCommand(
resetedStyled, (String) null);
modifyStyleCommand
.setLabel(CommandMessages.Command_ModifyStyle);
editor.getCommandStack().execute(modifyStyleCommand);
}
}
}
}
private void createSectionControls(final ScrolledForm form,
final Composite formBody) {
GridLayout layout = new GridLayout(1, true);
formBody.setLayout(layout);
for (SectionRecord rec : sections) {
createSectionControl(formBody, rec);
}
form.addControlListener(new ControlListener() {
public void controlResized(ControlEvent e) {
relayout(form, formBody);
}
public void controlMoved(ControlEvent e) {
}
});
}
private void relayout(ScrolledForm form, Composite formBody) {
Rectangle area = form.getClientArea();
GridLayout layout = (GridLayout) formBody.getLayout();
int newNumColumns = Math.max(1, area.width / DEFAULT_SECTION_WIDTH);
boolean change = newNumColumns != layout.numColumns
&& newNumColumns >= 0
&& newNumColumns <= formBody.getChildren().length;
if (change) {
layout.numColumns = newNumColumns;
formBody.layout();
}
}
private void createSectionControl(Composite parent, SectionRecord rec) {
rec.control = widgetFactory.createSection(parent,
Section.TITLE_BAR | SWT.BORDER);
Composite client = widgetFactory.createComposite(rec.control,
SWT.NO_FOCUS | SWT.WRAP);
rec.control.setClient(client);
GridData data = new GridData(GridData.FILL_HORIZONTAL);
data.verticalAlignment = GridData.BEGINNING;
data.widthHint = DEFAULT_SECTION_WIDTH;
rec.control.setLayoutData(data);
rec.section.createControl(client);
rec.visible = true;
updateSectionTitle(rec);
}
public void updateSectionTitle(IPropertySectionPart section) {
SectionRecord rec = findRecord(section);
if (rec != null) {
updateSectionTitle(rec);
}
}
private SectionRecord findRecord(IPropertySectionPart section) {
for (SectionRecord rec : sections) {
if (rec.section == section)
return rec;
}
return null;
}
private void updateSectionTitle(SectionRecord rec) {
if (rec.control == null || rec.control.isDisposed())
return;
String title = rec.section.getTitle();
if (title == null) {
title = ""; //$NON-NLS-1$
}
rec.control.setText(title);
}
public Control getControl() {
return composite;
}
public void selectionChanged(SelectionChangedEvent event) {
ISelection selection = event.getSelection();
selectionChanged(selection);
if (composite != null && !composite.isDisposed())
composite.setRedraw(false);
setSelectionToSections(selection);
if (form != null && !form.isDisposed()) {
refresh();
}
if (composite != null && !composite.isDisposed())
composite.setRedraw(true);
}
private void selectionChanged(ISelection selection) {
if (getControl() != null && !getControl().isDisposed())
getControl().setRedraw(false);
if (resetStyleControl != null && !resetStyleControl.isDisposed()) {
boolean resetStyleControlVisible = shouldHasResetStyleControl(
selection);
GridData gd = (GridData) resetStyleControl.getLayoutData();
gd.exclude = !resetStyleControlVisible;
resetStyleControl.setVisible(resetStyleControlVisible);
}
if (selection instanceof IStructuredSelection) {
IStructuredSelection ss = (IStructuredSelection) selection;
List<String> newVisibleSectionIds = manager
.getApplicableSectionIds(ss.toArray());
List<String> oldVisibleSectionIds = getVisibleSectionIds();
if (!equalsList(oldVisibleSectionIds, newVisibleSectionIds)) {
List<String> oldSectionIds = getSectionIds();
List<String> toAdd = new ArrayList<String>(
newVisibleSectionIds);
toAdd.removeAll(oldSectionIds);
for (String id : toAdd) {
addSection(id, newVisibleSectionIds, oldSectionIds);
oldSectionIds = getSectionIds();
}
List<String> toHide = new ArrayList<String>(oldSectionIds);
toHide.removeAll(newVisibleSectionIds);
for (String id : oldSectionIds) {
setSectionVisible(id, !toHide.contains(id));
}
reflow();
}
ti.setText(calcTitle(ss.toArray()) + " " + modeLabel); //$NON-NLS-1$
} else {
ti.setText(modeLabel);
}
if (getControl() != null && !getControl().isDisposed())
getControl().setRedraw(true);
}
private void addSection(String id, List<String> newVisibleSectionIds,
List<String> oldSectionIds) {
addSection(id, manager.createSection(id));
String aboveId = findAboveId(id, oldSectionIds, newVisibleSectionIds);
moveSectionAfter(id, aboveId);
}
private String findAboveId(String id, List<String> oldSectionIds,
List<String> newSectionIds) {
int index = newSectionIds.indexOf(id);
for (int i = index - 1; i >= 0; i--) {
String aboveId = newSectionIds.get(i);
if (oldSectionIds.contains(aboveId))
return aboveId;
}
return null;
}
private static boolean equalsList(List<String> list1, List<String> list2) {
if (list1.size() != list2.size())
return false;
for (int i = 0; i < list1.size(); i++) {
String s1 = list1.get(i);
String s2 = list2.get(i);
if (!s1.equals(s2))
return false;
}
return true;
}
private String calcTitle(Object[] objects) {
if (objects == null || objects.length == 0)
return null;
String category = getCategoryName(objects);
return category;
}
private String getCategoryName(Object[] objects) {
ICategoryManager typeManager = MindMapUI.getCategoryManager();
ICategoryAnalyzation result = typeManager.analyze(objects);
return typeManager.getCategoryName(result.getMainCategory());
}
private void setSelectionToSections(ISelection selection) {
for (SectionRecord rec : sections) {
if (rec.visible) {
rec.section.setSelection(selection);
updateSectionTitle(rec);
}
}
}
public String getTitle() {
return title;
}
public void refresh() {
for (SectionRecord rec : sections) {
if (rec.visible) {
rec.section.refresh();
}
}
if (form != null && !form.isDisposed()) {
form.reflow(true);
}
}
public void dispose() {
if (sourceEditor != null) {
sourceEditor.getSite().getSelectionProvider()
.removeSelectionChangedListener(this);
}
for (SectionRecord rec : sections) {
rec.section.dispose();
rec.visible = false;
rec.control = null;
}
if (composite != null) {
composite.dispose();
composite = null;
}
form = null;
title = null;
super.dispose();
}
@Override
protected void handlePartActivated(MPart part) {
super.handlePartActivated(part);
Object partObject = part.getObject();
if (partObject instanceof CompatibilityPart) {
IWorkbenchPart editorPart = ((CompatibilityPart) partObject)
.getPart();
if (editorPart instanceof IGraphicalEditor) {
setEditor((IGraphicalEditor) editorPart);
}
MPart partModel = getAdapter(MPart.class);
Object wp = partModel.getTransientData()
.get(E4PartWrapper.E4_WRAPPER_KEY);
if (wp instanceof E4PartWrapper) {
postConfiguration((IWorkbenchPart) wp, partModel);
}
} else if (sourceEditor == null) {
IWorkbenchWindow window = getAdapter(IWorkbenchWindow.class);
IEditorPart editorPart = window.getActivePage().getActiveEditor();
if (editorPart instanceof IGraphicalEditor) {
setEditor((IGraphicalEditor) editorPart);
}
}
}
public IPageSite getContainerSite() {
return null;
}
public IWorkbenchPart getContributingPart() {
return sourceEditor;
}
}