/* ******************************************************************************
* 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.editor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import org.eclipse.core.expressions.IEvaluationContext;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.URIUtil;
import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.ErrorSupportProvider;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.resource.FontDescriptor;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.jface.util.Util;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseTrackListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.ISaveablePart2;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWindowListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartConstants;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.contexts.IContextActivation;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.internal.util.BundleUtility;
import org.eclipse.ui.part.PageBook;
import org.eclipse.ui.progress.IProgressService;
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
import org.eclipse.ui.services.IEvaluationService;
import org.eclipse.ui.statushandlers.IStatusAdapterConstants;
import org.eclipse.ui.statushandlers.StatusAdapter;
import org.eclipse.ui.statushandlers.StatusManager;
import org.xmind.core.Core;
import org.xmind.core.CoreException;
import org.xmind.core.IFileEntry;
import org.xmind.core.IManifest;
import org.xmind.core.IRelationship;
import org.xmind.core.IRelationshipEnd;
import org.xmind.core.ISheet;
import org.xmind.core.ISheetComponent;
import org.xmind.core.ISheetSettings;
import org.xmind.core.ITopic;
import org.xmind.core.ITopicComponent;
import org.xmind.core.IWorkbook;
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.ICoreEventSource2;
import org.xmind.core.event.ICoreEventSupport;
import org.xmind.core.util.FileUtils;
import org.xmind.gef.EditDomain;
import org.xmind.gef.IEditDomainListener;
import org.xmind.gef.IGraphicalViewer;
import org.xmind.gef.command.Command;
import org.xmind.gef.command.CommandStackEvent;
import org.xmind.gef.command.CompoundCommand;
import org.xmind.gef.command.ICommandStack;
import org.xmind.gef.image.ResizeConstants;
import org.xmind.gef.tool.ITool;
import org.xmind.gef.ui.actions.IActionRegistry;
import org.xmind.gef.ui.actions.RedoAction;
import org.xmind.gef.ui.actions.UndoAction;
import org.xmind.gef.ui.editor.GraphicalEditor;
import org.xmind.gef.ui.editor.IEditable;
import org.xmind.gef.ui.editor.IEditingContext;
import org.xmind.gef.ui.editor.IGraphicalEditorPage;
import org.xmind.gef.ui.editor.IInteractiveMessage;
import org.xmind.ui.IWordContextProvider;
import org.xmind.ui.actions.MindMapActionFactory;
import org.xmind.ui.blackbox.BlackBox;
import org.xmind.ui.commands.ModifyFoldedCommand;
import org.xmind.ui.commands.MoveSheetCommand;
import org.xmind.ui.editor.EditorHistoryItem;
import org.xmind.ui.editor.IEditorHistory;
import org.xmind.ui.editor.PageTitleTabFolderRenderer;
import org.xmind.ui.internal.MindMapMessages;
import org.xmind.ui.internal.MindMapUIPlugin;
import org.xmind.ui.internal.MindMapWordContextProvider;
import org.xmind.ui.internal.actions.CopySheetAction;
import org.xmind.ui.internal.actions.CreateSheetAction;
import org.xmind.ui.internal.actions.DeleteOtherSheetsAction;
import org.xmind.ui.internal.actions.DeleteSheetAction;
import org.xmind.ui.internal.actions.DuplicateSheetAction;
import org.xmind.ui.internal.actions.PasteSheetAction;
import org.xmind.ui.internal.actions.ShowPropertiesAction;
import org.xmind.ui.internal.e4handlers.SaveWorkbookAsHandler;
import org.xmind.ui.internal.findreplace.IFindReplaceOperationProvider;
import org.xmind.ui.internal.mindmap.MindMapEditDomain;
import org.xmind.ui.internal.mindmap.MindMapState;
import org.xmind.ui.mindmap.IMindMap;
import org.xmind.ui.mindmap.IMindMapImages;
import org.xmind.ui.mindmap.IMindMapViewer;
import org.xmind.ui.mindmap.IWorkbookRef;
import org.xmind.ui.mindmap.IWorkbookRefListener;
import org.xmind.ui.mindmap.MindMap;
import org.xmind.ui.mindmap.MindMapImageExporter;
import org.xmind.ui.mindmap.MindMapUI;
import org.xmind.ui.prefs.PrefConstants;
import org.xmind.ui.resources.ColorUtils;
import org.xmind.ui.resources.FontUtils;
import org.xmind.ui.tabfolder.IPageMoveListener;
import org.xmind.ui.tabfolder.PageMoveHelper;
import org.xmind.ui.util.Logger;
import org.xmind.ui.wizards.ISaveContext;
public class MindMapEditor extends GraphicalEditor implements ISaveablePart2,
ICoreEventListener, IPageMoveListener, IPropertyChangeListener,
IMindMapPreviewGenerator, ISaveContext, IWorkbookRefListener {
private static class EditorStatus {
private static EditorStatus instance = null;
private int activeIndex;
private List<Double> zooms;
private List<Point> scrollPositions;
private List<String> indexPaths;
private List<List<String>> topicTypeChains;
private EditorStatus() {
}
public void saveStatus(IWorkbookRef workbookRef, int activeIndex,
IGraphicalEditorPage[] pages) {
init();
if (workbookRef != null) {
IWorkbook workbook = workbookRef.getWorkbook();
if (workbook != null && pages != null && (pages.length != 0)) {
this.activeIndex = activeIndex;
for (IGraphicalEditorPage page : pages) {
IGraphicalViewer viewer = page.getViewer();
if (zooms == null)
zooms = new ArrayList<Double>();
double zoom = viewer.getZoomManager().getScale();
zooms.add(zoom);
if (scrollPositions == null)
scrollPositions = new ArrayList<Point>();
Point scrollPosition = viewer.getScrollPosition();
scrollPositions.add(scrollPosition);
if (indexPaths == null)
indexPaths = new ArrayList<String>();
if (topicTypeChains == null)
topicTypeChains = new ArrayList<List<String>>();
Object focused = viewer.getFocused();
if (focused == null || !(focused instanceof ITopic)) {
indexPaths.add(""); //$NON-NLS-1$
topicTypeChains
.add(Collections.<String> emptyList());
} else {
List<String> typeChain = new ArrayList<String>();
String indexPath = getTopicIndexPath(
(ITopic) focused, "", typeChain); //$NON-NLS-1$
indexPaths.add(indexPath);
Collections.reverse(typeChain);
topicTypeChains.add(typeChain);
}
}
}
}
}
private void init() {
activeIndex = 0;
if (zooms != null)
zooms.clear();
if (scrollPositions != null)
scrollPositions.clear();
if (indexPaths != null)
indexPaths.clear();
if (topicTypeChains != null)
topicTypeChains.clear();
}
private String getTopicIndexPath(ITopic topic, String path,
List<String> typeChain) {
path = topic.getIndex() + "/" + path; //$NON-NLS-1$
typeChain.add(topic.getType());
if (topic.getParent() != null
&& topic.getParent() instanceof ITopic)
return getTopicIndexPath(topic.getParent(), path, typeChain);
return path;
}
public int getActiveIndex() {
return activeIndex;
}
public List<Double> getZooms() {
return zooms;
}
public List<Point> getScrollPositions() {
return scrollPositions;
}
public List<String> getIndexPaths() {
return indexPaths;
}
public List<List<String>> getTopicTypeChains() {
return topicTypeChains;
}
public static EditorStatus getInstance() {
if (instance == null) {
synchronized (EditorStatus.class) {
if (instance == null)
instance = new EditorStatus();
}
}
return instance;
}
}
private class MindMapEditorSelectionProvider
extends MultiPageSelectionProvider {
/*
* (non-Javadoc)
* @see
* org.xmind.ui.tabfolder.DelegatedSelectionProvider#setSelection(org
* .eclipse.jface.viewers.ISelection)
*/
@Override
public void setSelection(ISelection selection) {
if (selection instanceof IStructuredSelection) {
for (Object element : ((IStructuredSelection) selection)
.toList()) {
if (element instanceof ITopicComponent) {
setSelectionAndUnfold(element);
} else if (element instanceof IRelationship) {
IRelationship r = (IRelationship) element;
IRelationshipEnd e1 = r.getEnd1();
IRelationshipEnd e2 = r.getEnd2();
if (e1 instanceof ITopicComponent) {
setSelectionAndUnfold(e1);
}
if (e2 instanceof ITopicComponent) {
setSelectionAndUnfold(e2);
}
}
}
}
super.setSelection(selection);
}
}
private IWorkbookRef workbookRef = null;
private ICoreEventRegister workbookEventRegister = null;
private ICoreEventRegister globalEventRegister = null;
private MindMapPageTitleEditor pageTitleEditor = null;
private PageMoveHelper pageMoveHelper = null;
private MindMapFindReplaceOperationProvider findReplaceOperationProvider = null;
private Composite messageContainer = null;
private PageBook pageBook = null;
private Composite pageContainer = null;
private IEditingContext editingContext = new IEditingContext() {
@Override
public <T> T getAdapter(Class<T> adapter) {
MindMapEditor editor = MindMapEditor.this;
T result;
result = editor.getSite().getService(adapter);
if (result != null)
return result;
result = editor.getAdapter(adapter);
if (result != null)
return result;
result = Platform.getAdapterManager().getAdapter(editor, adapter);
if (result != null)
return result;
return null;
}
};
private IWordContextProvider wordContextProvider = null;
private boolean skipNextPreviewImage = false;
private IContextActivation contextActivation = null;
private IEditorHistory editorHistory = null;
private boolean passwordTried = false;
private IWindowListener windowListener;
private ISelectionListener selectionListener;
private boolean ignoreFileChanged = false;
private IEditorLayoutManager layoutManager = null;
private IContextActivation toolContextActivation = null;
private IContextService contextService = null;
public void init(IEditorSite site, IEditorInput input)
throws PartInitException {
this.editorHistory = site.getService(IEditorHistory.class);
this.workbookRef = createWorkbookRefFromInput(input);
if (this.workbookRef == null)
throw new PartInitException(
"Failed to obtain workbook reference from editor input '" //$NON-NLS-1$
+ input.toString() + "'"); //$NON-NLS-1$
super.init(site, input);
setMiniBarContributor(new MindMapMiniBarContributor());
}
private IWorkbookRef createWorkbookRefFromInput(IEditorInput input) {
IWorkbookRef workbookRef = input.getAdapter(IWorkbookRef.class);
if (workbookRef != null)
return workbookRef;
URI uri = input.getAdapter(URI.class);
if (uri != null) {
return MindMapUIPlugin.getDefault().getWorkbookRefFactory()
.createWorkbookRef(uri, null);
}
return null;
}
protected ISelectionProvider createSelectionProvider() {
return new MindMapEditorSelectionProvider();
}
protected ICommandStack createCommandStack() {
if (workbookRef != null)
return workbookRef.getCommandStack();
return super.createCommandStack();
}
protected void disposeCommandStack(ICommandStack commandStack) {
// No need to dispose command stack here, because the workbook reference
// manager will dispose unused command stacks automatically.
}
private void disposeData() {
if (workbookRef != null && workbookRef.getURI() != null) {
URI uri = workbookRef.getURI();
if (URIUtil.isFileURI(uri)) {
BlackBox.removeSavedMap(URIUtil.toFile(uri).getAbsolutePath());
}
}
final IWorkbookRef theWorkbookRef = this.workbookRef;
if (theWorkbookRef != null) {
theWorkbookRef.removePropertyChangeListener(this);
theWorkbookRef.removeWorkbookRefListener(this);
MindMapState.getInstance().saveState(theWorkbookRef, getPages());
if (theWorkbookRef.isDirty()) {
theWorkbookRef.discardChanges();
}
safeRun(null, false, new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor)
throws InvocationTargetException, InterruptedException {
theWorkbookRef.close(monitor);
}
});
IEditingContext activeContext = theWorkbookRef.getActiveContext();
if (activeContext == this.editingContext) {
theWorkbookRef.setActiveContext(null);
}
}
deactivateToolContext();
uninstallModelListener();
}
public void dispose() {
if (contextActivation != null) {
IContextService cs = getSite().getService(IContextService.class);
cs.deactivateContext(contextActivation);
}
disposeData();
super.dispose();
deactivateFileNotifier();
workbookEventRegister = null;
globalEventRegister = null;
pageTitleEditor = null;
pageMoveHelper = null;
findReplaceOperationProvider = null;
workbookRef = null;
pageBook = null;
pageContainer = null;
// release reference to the workbook reference object
this.workbookRef = null;
layoutManager = null;
}
@Override
public void createPartControl(Composite parent) {
super.createPartControl(parent);
Composite container = getContainer();
if (container instanceof CTabFolder) {
((CTabFolder) container).setRenderer(new PageTitleTabFolderRenderer(
(CTabFolder) container, this));
}
activateFileNotifier();
}
protected Composite createContainerParent(Composite parent) {
FormLayout formLayout = new FormLayout();
parent.setLayout(formLayout);
messageContainer = new Composite(parent, SWT.BORDER);
FormData messageFormData = new FormData();
//no correct size data to set form data
messageContainer.setLayoutData(messageFormData);
messageContainer.setVisible(false);
GridLayout messageLayout = new GridLayout(1, false);
messageLayout.marginWidth = 0;
messageLayout.marginHeight = 0;
messageLayout.horizontalSpacing = 0;
messageLayout.verticalSpacing = 0;
messageContainer.setLayout(messageLayout);
updateMessages(false);
pageBook = new PageBook(parent, SWT.NONE);
FormData pageBookData = new FormData();
pageBookData.left = new FormAttachment(0, 0);
pageBookData.top = new FormAttachment(0, 0);
pageBookData.bottom = new FormAttachment(100, 0);
pageBookData.right = new FormAttachment(100, 0);
pageBook.setLayoutData(pageBookData);
pageContainer = new Composite(pageBook, SWT.NONE);
layoutManager = new EditorLayoutManager(pageContainer);
layoutManager.setActiveLayout(new DefaultEditorLayout());
IContextService cs = getSite().getService(IContextService.class);
contextActivation = cs.activateContext(MindMapUI.CONTEXT_MINDMAP);
return pageContainer;
}
@Override
protected void createEditorContents() {
super.createEditorContents();
if (workbookRef != null) {
workbookRef.setActiveContext(editingContext);
workbookRef.addPropertyChangeListener(this);
workbookRef.addWorkbookRefListener(this);
}
// Make editor actions:
createActions(getActionRegistry());
// Update editor pane title:
updateNames();
// Add helpers to handle moving pages, editing page title, showing
// page popup preview, creating new page, etc.:
if (getContainer() instanceof CTabFolder) {
final CTabFolder tabFolder = (CTabFolder) getContainer();
pageMoveHelper = new PageMoveHelper(tabFolder);
pageMoveHelper.addListener(this);
pageTitleEditor = new MindMapPageTitleEditor(tabFolder, this);
// pageTitleEditor.addPageTitleChangedListener(this);
// pageTitleEditor.setContextId(getSite(),
// MindMapUI.CONTEXT_PAGETITLE_EDIT);
new MindMapEditorPagePopupPreviewHelper(this, tabFolder);
}
// Let 3rd-party plugins configure this editor:
MindMapEditorConfigurerManager.getInstance().configureEditor(this);
// Try loading workbook:
if (getWorkbook() != null) {
workbookLoaded();
} else if (workbookRef != null) {
final IWorkbookRef theWorkbookRef = workbookRef;
Display.getCurrent().asyncExec(new Runnable() {
@Override
public void run() {
loadWorkbook(theWorkbookRef, 0);
}
});
}
}
private void loadWorkbook(final IWorkbookRef workbookRef, int times) {
IEncryptable encryptable = workbookRef.getAdapter(IEncryptable.class);
if (encryptable != null && !encryptable.hasPassword()) {
/// make sure setPassword is called to prevent the default password dialog
encryptable.setPassword(null);
}
IWorkbenchSiteProgressService context = getSite()
.getService(IWorkbenchSiteProgressService.class);
Assert.isTrue(context != null);
try {
context.run(true, true, new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor)
throws InvocationTargetException, InterruptedException {
workbookRef.open(monitor);
}
});
} catch (final InvocationTargetException e) {
CoreException coreEx = getCoreException(e);
if (coreEx != null) {
int errType = coreEx.getType();
if (errType == Core.ERROR_WRONG_PASSWORD) {
// password error
String message = passwordTried
? MindMapMessages.MindMapEditor_passwordPrompt_message1
: MindMapMessages.MindMapEditor_passwordPrompt_message2;
openDecryptionDialog(workbookRef, message, times);
passwordTried = true;
return;
}
}
// failed
Throwable cause = e.getTargetException();
if (cause == null)
cause = e;
if (cause instanceof FileNotFoundException) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
MessageDialog.openWarning(
Display.getDefault().getActiveShell(),
MindMapMessages.MindMapEditor_Warning_FileNotFoundDialog_title,
MindMapMessages.WorkbookHistoryItem_FileMissingMessage);
}
});
asyncClose();
} else {
showError(cause,
workbookRef.getAdapter(ErrorSupportProvider.class));
}
return;
} catch (InterruptedException e) {
// canceled
asyncClose();
return;
}
workbookLoaded();
}
private void openDecryptionDialog(final IWorkbookRef workbookRef,
String message, int times) {
final int nextTime = times + 1;
final IEncryptable encryptable = workbookRef
.getAdapter(IEncryptable.class);
new DecryptionDialog(Display.getCurrent().getActiveShell(),
workbookRef.getName(), encryptable.getPasswordHint(), times) {
protected void okPressed() {
super.okPressed();
encryptable.setPassword(getPassword());
loadWorkbook(workbookRef, nextTime);
};
protected void handleShellCloseEvent() {
super.handleShellCloseEvent();
asyncClose();
};
protected void cancelPressed() {
super.cancelPressed();
asyncClose();
};
}.open();
}
private CoreException getCoreException(Throwable e) {
if (e == null)
return null;
if (e instanceof CoreException)
return (CoreException) e;
return getCoreException(e.getCause());
}
private void asyncClose() {
Display.getCurrent().asyncExec(new Runnable() {
@Override
public void run() {
closeEditor();
}
});
}
private void closeEditor() {
getSite().getPage().closeEditor(this, false);
}
private void showError(Throwable exception,
ErrorSupportProvider supportProvider) {
StatusAdapter statusAdapter = new StatusAdapter(new Status(
IStatus.ERROR, MindMapUIPlugin.PLUGIN_ID,
MindMapMessages.LoadWorkbookJob_errorDialog_title, exception));
statusAdapter.setProperty(IStatusAdapterConstants.TIMESTAMP_PROPERTY,
Long.valueOf(System.currentTimeMillis()));
ErrorDialog errorDialog = new ErrorDialog(
Display.getCurrent().getActiveShell(), statusAdapter,
supportProvider);
errorDialog.setCloseCallback(new Runnable() {
@Override
public void run() {
asyncClose();
}
});
errorDialog.open();
}
protected void createActions(IActionRegistry actionRegistry) {
UndoAction undoAction = new UndoAction(this);
actionRegistry.addAction(undoAction);
addCommandStackAction(undoAction);
RedoAction redoAction = new RedoAction(this);
actionRegistry.addAction(redoAction);
addCommandStackAction(redoAction);
CreateSheetAction createSheetAction = new CreateSheetAction(this);
actionRegistry.addAction(createSheetAction);
DeleteSheetAction deleteSheetAction = new DeleteSheetAction(this);
actionRegistry.addAction(deleteSheetAction);
DeleteOtherSheetsAction deleteOtherSheetAction = new DeleteOtherSheetsAction(
this);
actionRegistry.addAction(deleteOtherSheetAction);
DuplicateSheetAction duplicateSheetAction = new DuplicateSheetAction(
this);
actionRegistry.addAction(duplicateSheetAction);
CopySheetAction copySheetAction = new CopySheetAction(this);
actionRegistry.addAction(copySheetAction);
PasteSheetAction pasteSheetAction = new PasteSheetAction(this);
actionRegistry.addAction(pasteSheetAction);
ShowPropertiesAction showPropertiesAction = new ShowPropertiesAction(
getSite().getWorkbenchWindow());
actionRegistry.addAction(showPropertiesAction);
}
private void configurePage(IGraphicalEditorPage page) {
MindMapEditorConfigurerManager.getInstance().configurePage(page);
}
protected void createPages() {
if (getWorkbook() == null)
return;
for (ISheet sheet : getWorkbook().getSheets()) {
IGraphicalEditorPage page = createSheetPage(sheet, -1);
configurePage(page);
}
if (getPageCount() > 0) {
setActivePage(0);
}
}
protected IGraphicalEditorPage createSheetPage(ISheet sheet, int index) {
IGraphicalEditorPage page = new MindMapEditorPage();
page.init(this, sheet);
addPage(page);
if (index >= 0 && index < getPageCount()) {
movePageTo(findPage(page), index);
}
index = findPage(page);
if (getActivePage() != index) {
setActivePage(index);
}
page.updatePageTitle();
MindMapState.getInstance().loadState(getWorkbookRef(), page);
return page;
}
protected EditDomain createEditDomain(IGraphicalEditorPage page) {
MindMapEditDomain domain = new MindMapEditDomain();
domain.addEditDomainListener(new IEditDomainListener() {
@Override
public void activeToolChanged(ITool oldTool, ITool newTool) {
changeContext(newTool);
}
});
domain.setCommandStack(getCommandStack());
return domain;
}
protected void changeContext(ITool newTool) {
deactivateToolContext();
activateContext(newTool == null ? null : newTool.getContextId());
}
protected void changeContext(String contextId) {
deactivateToolContext();
activateContext(contextId);
}
private void activateContext(String contextId) {
if (contextId == null)
return;
contextService = getSite().getService(IContextService.class);
if (contextService != null) {
toolContextActivation = contextService.activateContext(contextId);
}
}
private void deactivateToolContext() {
if (contextService != null && toolContextActivation != null) {
contextService.deactivateContext(toolContextActivation);
}
contextService = null;
toolContextActivation = null;
}
private void updateMessages(boolean layout) {
for (Control messageItem : messageContainer.getChildren()) {
messageItem.dispose();
}
List<IInteractiveMessage> messages = workbookRef.getMessages();
if (messages != null && !messages.isEmpty()) {
for (IInteractiveMessage message : new ArrayList<IInteractiveMessage>(
messages)) {
Image icon;
Color lineColor;
Color textColor;
int type = message.getMessageType();
if (type == IInteractiveMessage.WARNING) {
///TODO use a dedicated icon
icon = null;
lineColor = (Color) JFaceResources.getResources()
.get(ColorUtils.toDescriptor("#fff6ae")); //$NON-NLS-1$
textColor = (Color) JFaceResources.getResources()
.get(ColorUtils.toDescriptor("#1e1e1e")); //$NON-NLS-1$
} else if (type == IInteractiveMessage.ERROR) {
///TODO use a dedicated icon
icon = null;
lineColor = (Color) JFaceResources.getResources()
.get(ColorUtils.toDescriptor("#fff6ae")); //$NON-NLS-1$
textColor = (Color) JFaceResources.getResources()
.get(ColorUtils.toDescriptor("#1e1e1e")); //$NON-NLS-1$
} else {
///TODO use a dedicated icon
icon = Display.getCurrent()
.getSystemImage(SWT.ICON_INFORMATION);
lineColor = (Color) JFaceResources.getResources()
.get(ColorUtils.toDescriptor("#fff6ae")); //$NON-NLS-1$
textColor = (Color) JFaceResources.getResources()
.get(ColorUtils.toDescriptor("#1e1e1e")); //$NON-NLS-1$
}
String text = message.getMessage();
if (text == null) {
text = ""; //$NON-NLS-1$
}
List<IAction> actions = message.getActions();
final Composite line = new Composite(messageContainer,
SWT.NONE);
line.setBackground(lineColor);
GridData lineData = new GridData(SWT.CENTER, SWT.FILL, true,
false);
lineData.widthHint = 500;
line.setLayoutData(lineData);
line.setLayout(new GridLayout(2, false));
Composite leftComposite = new Composite(line, SWT.NONE);
leftComposite.setBackground(line.getBackground());
GridData lineBodyData = new GridData(SWT.CENTER, SWT.FILL, true,
false);
leftComposite.setLayoutData(lineBodyData);
int numColumns = 0;
GridLayout leftCompositeLayout = new GridLayout(numColumns,
false);
leftCompositeLayout.marginLeft = 16;
leftCompositeLayout.marginHeight = 5;
leftCompositeLayout.horizontalSpacing = 3;
leftCompositeLayout.verticalSpacing = 0;
leftComposite.setLayout(leftCompositeLayout);
if (icon != null) {
numColumns++;
Label iconLabel = new Label(leftComposite, SWT.NONE);
iconLabel.setBackground(line.getBackground());
iconLabel.setImage(icon);
iconLabel.setLayoutData(
new GridData(SWT.CENTER, SWT.CENTER, false, true));
}
numColumns++;
Label textLabel = new Label(leftComposite,
SWT.WRAP | SWT.CENTER);
textLabel.setText(text);
textLabel.setBackground(line.getBackground());
textLabel.setForeground(textColor);
textLabel.setLayoutData(
new GridData(SWT.CENTER, SWT.CENTER, true, true));
Font textFont = textLabel.getFont();
if (textFont != null) {
FontData[] fontData = textFont.getFontData();
FontData[] newFontData = FontUtils.newHeight(fontData,
Util.isMac() ? 12 : 10);
textLabel.setFont((Font) JFaceResources.getResources()
.get(FontDescriptor.createFrom(newFontData)));
}
if (!actions.isEmpty()) {
numColumns++;
Composite actionBar = new Composite(leftComposite,
SWT.NONE);
actionBar.setBackground(line.getBackground());
actionBar.setLayoutData(
new GridData(SWT.FILL, SWT.FILL, false, true));
GridLayout actionLayout = new GridLayout(actions.size(),
false);
actionLayout.marginWidth = 0;
actionLayout.marginHeight = 0;
actionLayout.horizontalSpacing = 3;
actionLayout.verticalSpacing = 0;
actionBar.setLayout(actionLayout);
for (final IAction action : actions) {
final Button actionButton = new Button(actionBar,
SWT.PUSH);
actionButton.setBackground(actionBar.getBackground());
actionButton.setLayoutData(new GridData(SWT.FILL,
SWT.CENTER, false, true));
String actionText = action.getText();
if (actionText == null) {
actionButton.setText(actionText);
} else {
ImageDescriptor actionImageDescriptor = action
.getImageDescriptor();
if (actionImageDescriptor != null) {
final Image actionImage = actionImageDescriptor
.createImage(Display.getCurrent());
actionButton.addDisposeListener(
new DisposeListener() {
@Override
public void widgetDisposed(
DisposeEvent e) {
actionImage.dispose();
}
});
actionButton.setImage(actionImage);
}
}
actionButton.setToolTipText(action.getToolTipText());
actionButton.addListener(SWT.Selection, new Listener() {
@Override
public void handleEvent(Event event) {
action.runWithEvent(event);
}
});
}
}
leftCompositeLayout.numColumns = numColumns;
final Label closeImageLabel = new Label(line, SWT.NONE);
closeImageLabel.setBackground(line.getBackground());
closeImageLabel.setImage((Image) JFaceResources.getResources()
.get(MindMapUI.getImages().get("close.png", true))); //$NON-NLS-1$
closeImageLabel.setLayoutData(
new GridData(SWT.END, SWT.BEGINNING, false, false));
closeImageLabel.addMouseListener(new MouseAdapter() {
@Override
public void mouseDown(MouseEvent e) {
if (messageContainer != null
&& !messageContainer.isDisposed()) {
if (line != null && !line.isDisposed()) {
line.dispose();
}
Control[] children = messageContainer.getChildren();
if (children == null || children.length == 0) {
messageContainer.setVisible(false);
}
messageContainer.getParent().layout(true);
}
}
});
closeImageLabel.addMouseTrackListener(new MouseTrackListener() {
@Override
public void mouseHover(MouseEvent e) {
closeImageLabel.setCursor(Display.getDefault()
.getSystemCursor(SWT.CURSOR_HAND));
}
@Override
public void mouseExit(MouseEvent e) {
closeImageLabel.setCursor(null);
}
@Override
public void mouseEnter(MouseEvent e) {
closeImageLabel.setCursor(Display.getDefault()
.getSystemCursor(SWT.CURSOR_HAND));
}
});
}
org.eclipse.swt.graphics.Point size = messageContainer
.computeSize(SWT.DEFAULT, SWT.DEFAULT);
FormData messageFormData = new FormData();
messageFormData.left = new FormAttachment(50, -size.x / 2);
messageFormData.right = new FormAttachment(50, size.x / 2);
messageFormData.top = new FormAttachment(0, 0);
//can't set bottom
// messageFormData.bottom = new FormAttachment(100, -size.y);
messageContainer.setLayoutData(messageFormData);
messageContainer.setVisible(true);
}
if (layout) {
messageContainer.getParent().layout(true, true);
}
}
protected void updateNames() {
setPartName(getEditorInput().getName());
setTitleToolTip(getEditorInput().getToolTipText());
}
public IWorkbookRef getWorkbookRef() {
return workbookRef;
}
public IWorkbook getWorkbook() {
if (workbookRef == null)
return null;
return workbookRef.getWorkbook();
}
@SuppressWarnings("unchecked")
@Override
public <T> T getAdapter(Class<T> adapter) {
if (adapter == IEditorLayoutManager.class)
return (T) layoutManager;
return super.getAdapter(adapter);
}
@Override
protected <T> T getEditorAdapter(Class<T> adapter) {
if (workbookRef != null) {
T result = workbookRef.getAdapter(adapter);
if (result != null)
return result;
}
if (adapter == IWorkbookRef.class) {
return adapter.cast(getWorkbookRef());
} else if (adapter == IWorkbook.class) {
return adapter.cast(getWorkbook());
} else if (adapter == MindMapPageTitleEditor.class) {
return adapter.cast(pageTitleEditor);
} else if (adapter == PageMoveHelper.class) {
return adapter.cast(pageMoveHelper);
} else if (adapter == IFindReplaceOperationProvider.class) {
if (findReplaceOperationProvider == null) {
findReplaceOperationProvider = new MindMapFindReplaceOperationProvider(
this);
}
return adapter.cast(findReplaceOperationProvider);
} else if (adapter == IWordContextProvider.class) {
if (wordContextProvider == null) {
wordContextProvider = new MindMapWordContextProvider(this);
}
return adapter.cast(wordContextProvider);
} else if (adapter == IDialogPaneContainer.class) {
// return adapter.cast(backCover);
}
return super.getEditorAdapter(adapter);
}
protected void installModelListener() {
IWorkbook workbook = getWorkbook();
workbookEventRegister = new CoreEventRegister(workbook, this);
workbookEventRegister.register(Core.SheetAdd);
workbookEventRegister.register(Core.SheetRemove);
workbookEventRegister.register(Core.SheetMove);
workbookEventRegister.register(Core.PasswordChange);
workbookEventRegister.register(Core.WorkbookPreSaveOnce);
globalEventRegister = new CoreEventRegister(
workbook.getAdapter(ICoreEventSupport.class), this);
globalEventRegister.register(Core.SheetSettings);
}
protected void uninstallModelListener() {
if (workbookEventRegister != null) {
workbookEventRegister.unregisterAll();
workbookEventRegister = null;
}
if (globalEventRegister != null) {
globalEventRegister.unregisterAll();
globalEventRegister = null;
}
}
public void handleCoreEvent(final CoreEvent event) {
if (pageBook == null || pageBook.isDisposed() || workbookRef == null)
return;
pageBook.getDisplay().syncExec(new Runnable() {
public void run() {
String type = event.getType();
if (Core.WorkbookPreSaveOnce.equals(type)) {
firePropertyChange(IWorkbenchPartConstants.PROP_DIRTY);
firePropertyChange(PROP_INPUT);
} else if (Core.SheetAdd.equals(type)) {
ISheet sheet = (ISheet) event.getTarget();
int index = event.getIndex();
IGraphicalEditorPage page = createSheetPage(sheet, index);
configurePage(page);
} else if (Core.SheetRemove.equals(type)) {
ISheet sheet = (ISheet) event.getTarget();
IGraphicalEditorPage page = findPage(sheet);
if (page != null) {
removePage(page);
}
} else if (Core.SheetMove.equals(type)) {
int oldIndex = event.getIndex();
int newIndex = ((ISheet) event.getTarget()).getIndex();
movePageTo(oldIndex, newIndex);
} else if (Core.PasswordChange.equals(type)) {
IWorkbook workbook = getWorkbook();
if (workbook instanceof ICoreEventSource2) {
((ICoreEventSource2) workbook)
.registerOnceCoreEventListener(
Core.WorkbookPreSaveOnce,
ICoreEventListener.NULL);
}
}
//update sheet tab colors
if (Core.SheetSettings.equals(type)
&& ISheetSettings.ATTR_RGB.equals(event.getTarget())) {
updateSheetTabColors();
}
}
});
}
private void updateSheetTabColors() {
getContainer().redraw();
}
protected void saveAndRun(Command command) {
ICommandStack cs = getCommandStack();
if (cs != null)
cs.execute(command);
}
public void pageMoved(int fromIndex, int toIndex) {
IWorkbook workbook = getWorkbook();
MoveSheetCommand command = new MoveSheetCommand(workbook, fromIndex,
toIndex);
command.setLabel(""); //$NON-NLS-1$
saveAndRun(command);
}
// public void pageTitleChanged(int pageIndex, String newValue) {
// /// forbid changing sheet title to empty string
// /// preventing saving errors (e.g. cloud syncing)
// if (newValue == null || "".equals(newValue)) //$NON-NLS-1$
// return;
//
// IGraphicalEditorPage page = getPage(pageIndex);
// if (page != null) {
// Object pageInput = page.getInput();
// if (pageInput instanceof ISheet) {
// ModifyTitleTextCommand command = new ModifyTitleTextCommand(
// (ISheet) pageInput, newValue);
// command.setLabel(""); //$NON-NLS-1$
// saveAndRun(command);
// }
// }
// }
protected void createSheet() {
IAction action = getActionRegistry()
.getAction(MindMapActionFactory.NEW_SHEET.getId());
if (action != null && action.isEnabled()) {
action.run();
}
}
@Override
public void setFocus() {
// if (workbookRef != null) {
// workbookRef.setPrimaryReferrer(this);
// }
if (workbookRef != null) {
workbookRef.setActiveContext(editingContext);
}
// if (backCover != null && backCover.isOpen()) {
// backCover.setFocus();
// } else {
super.setFocus();
// }
}
public void openEncryptionDialog() {
if (pageBook == null || pageBook.isDisposed())
return;
final IWorkbookRef theWorkbookRef = workbookRef;
new EncryptionDialog(Display.getCurrent().getActiveShell()) {
@Override
protected boolean hasPassword() {
IEncryptable encryptable = theWorkbookRef
.getAdapter(IEncryptable.class);
return encryptable != null && encryptable.hasPassword();
}
@Override
protected boolean testsPassword(String password) {
IEncryptable encryptable = theWorkbookRef
.getAdapter(IEncryptable.class);
return encryptable != null
&& encryptable.testsPassword(password);
}
@Override
protected void okPressed() {
boolean verified = verify();
super.okPressed();
if (verified) {
IEncryptable encryptable = theWorkbookRef
.getAdapter(IEncryptable.class);
if (encryptable != null) {
encryptable.setPassword(getPassword());
encryptable.setPasswordHint(getHintMessage());
}
}
}
}.open();
}
public ISelectionProvider getSelectionProvider() {
return getSite().getSelectionProvider();
}
public void reveal() {
getSite().getPage().activate(this);
setFocus();
}
/**
* @param monitor
* @deprecated
*/
@Deprecated
public void postSave(final IProgressMonitor monitor) {
getSite().getShell().getDisplay().syncExec(new Runnable() {
public void run() {
postSave();
}
});
}
public void setSelection(ISelection selection, boolean reveal,
boolean forceFocus) {
ISelectionProvider selectionProvider = getSite().getSelectionProvider();
if (selectionProvider != null) {
selectionProvider.setSelection(selection);
}
if (forceFocus) {
getSite().getPage().activate(this);
Shell shell = getSite().getShell();
if (shell != null && !shell.isDisposed()) {
shell.setActive();
}
} else if (reveal) {
getSite().getPage().bringToTop(this);
}
}
public IGraphicalEditorPage findPage(Object input) {
if (input instanceof IMindMap) {
input = ((IMindMap) input).getSheet();
}
return super.findPage(input);
}
private void workbookLoaded() {
passwordTried = false;
if (pageBook == null || pageBook.isDisposed())
return;
// TODO
pageBook.showPage(pageContainer);
if (isEditorActive())
setFocus();
Assert.isTrue(getWorkbook() != null);
createPages();
if (isEditorActive()) {
setFocus();
}
installModelListener();
firePropertyChange(PROP_INPUT);
firePropertyChange(IWorkbenchPartConstants.PROP_DIRTY);
recordEditorHistory();
}
private boolean isEditorActive() {
return getSite().getPage().getActiveEditor() == this;
}
/*
* (non-Javadoc)
* @see
* org.xmind.gef.ui.editor.GraphicalEditor#findOwnedInput(org.eclipse.jface
* .viewers.ISelection)
*/
@Override
protected Object findOwnedInput(ISelection selection) {
if (selection instanceof IStructuredSelection) {
Object[] elements = ((IStructuredSelection) selection).toArray();
for (Object element : elements) {
if (element instanceof ISheetComponent)
return ((ISheetComponent) element).getOwnedSheet();
if (element instanceof ISheet)
return (ISheet) element;
}
}
return super.findOwnedInput(selection);
}
public void skipNextPreviewImage() {
this.skipNextPreviewImage = true;
}
private void setSelectionAndUnfold(Object element) {
List<Command> showElementsCommands = new ArrayList<Command>(1);
ITopic parent = ((ITopicComponent) element).getParent();
while (parent != null) {
if (parent.isFolded()) {
showElementsCommands
.add(new ModifyFoldedCommand(parent, false));
}
parent = parent.getParent();
}
if (!showElementsCommands.isEmpty()) {
Command command = new CompoundCommand(
showElementsCommands.get(0).getLabel(),
showElementsCommands);
saveAndRun(command);
}
}
@Override
public boolean isDirty() {
return workbookRef != null && workbookRef.isDirty();
}
@Override
public void doSave(IProgressMonitor monitor) {
if (workbookRef == null)
return;
if (!workbookRef.canSave()) {
doSaveAs();
return;
}
safeRun(monitor, true, new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor)
throws InvocationTargetException, InterruptedException {
workbookRef.save(monitor);
if (MindMapUIPlugin.getDefault().getPreferenceStore()
.getBoolean(PrefConstants.AUTO_BACKUP_ENABLE)) {
URI uri = workbookRef.getURI();
if (URIUtil.isFileURI(uri)) {
BlackBox.doBackup(
URIUtil.toFile(uri).getAbsolutePath());
}
}
postSave();
recordEditorHistory();
}
});
}
private void recordEditorHistory() {
if (workbookRef.getURI() == null || workbookRef.getName() == null)
return;
URI uri = workbookRef.getURI();
//only local file or seawind file can record it history.
if (!uri.getScheme().equalsIgnoreCase("file") //$NON-NLS-1$
&& !uri.getScheme().equalsIgnoreCase("seawind")) //$NON-NLS-1$
return;
InputStream input = null;
try {
try {
if (uri.getScheme().equalsIgnoreCase("file")) { //$NON-NLS-1$
input = getThumbnailStreamForLocal();
} else
input = getThumbnailStreamFor(workbookRef);
if (input == null)
return;
editorHistory.add(workbookRef.getURI(), new EditorHistoryItem(
workbookRef.getName(), System.currentTimeMillis()));
editorHistory.saveThumbnailData(workbookRef.getURI(), input);
} finally {
if (input != null)
input.close();
}
} catch (IOException e) {
MindMapUIPlugin.getDefault().getLog()
.log(new Status(IStatus.ERROR, MindMapUIPlugin.PLUGIN_ID,
"Failed to record preview image for editor history", //$NON-NLS-1$
e));
}
}
private InputStream getThumbnailStreamForLocal() throws IOException {
IManifest manifest = getWorkbook().getManifest();
if (manifest != null) {
IFileEntry thumbnailEntry = manifest
.getFileEntry("Thumbnails/thumbnail.png"); //$NON-NLS-1$
if (thumbnailEntry != null)
return thumbnailEntry.openInputStream();
}
return null;
}
private InputStream getThumbnailStreamFor(IWorkbookRef workbookRef) {
if (workbookRef == null)
return null;
List<ISheet> sheets = workbookRef.getWorkbook().getSheets();
if (sheets.isEmpty())
return null;
ISheet sheet = sheets.get(0);
try {
return workbookRef.getPreviewImageData(sheet.getId(), null);
} catch (IOException e) {
MindMapUIPlugin.log(e, String.format(
"Failed to load preview image for sheet 'workbooks/%s/sheets/%s'", //$NON-NLS-1$
sheet.getParent().toString(), sheet.getId()));
} catch (SWTException e) {
MindMapUIPlugin.log(e, String.format(
"Failed to load preview image for sheet 'workbooks/%s/sheets/%s'", //$NON-NLS-1$
sheet.getParent().toString(), sheet.getId()));
}
return null;
}
public void doSaveAs() {
doSaveAs(false);
}
public void doSaveAs(boolean onlyToLocal) {
final IWorkbookRef oldWorkbookRef = this.workbookRef;
if (oldWorkbookRef == null || oldWorkbookRef
.isInState(IWorkbookRef.CLOSED | IWorkbookRef.CLOSING))
throw new IllegalStateException(
"This mind map editor is already closed."); //$NON-NLS-1$
IProgressService runner = getSite().getService(IProgressService.class);
final IWorkbookRef newWorkbookRef;
try {
newWorkbookRef = SaveWorkbookAsHandler.saveWorkbookAs(this,
oldWorkbookRef, runner, null, onlyToLocal);
if (newWorkbookRef == null)
// canceled
return;
if (newWorkbookRef.equals(oldWorkbookRef)) {
// saved to old location
postSave();
recordEditorHistory();
return;
}
try {
runner.run(true, true, new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor)
throws InvocationTargetException,
InterruptedException {
newWorkbookRef.open(monitor);
newWorkbookRef.save(monitor);
}
});
} catch (InterruptedException e) {
// canceled
return;
}
} catch (Exception e) {
StatusManager.getManager().handle(new Status(IStatus.ERROR,
MindMapUIPlugin.PLUGIN_ID, e.getMessage(), e),
StatusManager.SHOW);
return;
}
// TODO save editor state before changing editor input
EditorStatus editorStatus = EditorStatus.getInstance();
editorStatus.saveStatus(oldWorkbookRef, getActivePage(), getPages());
disposeData();
while (getPageCount() > 0) {
removePage(0);
}
this.workbookRef = newWorkbookRef;
if (newWorkbookRef != null) {
newWorkbookRef.addPropertyChangeListener(this);
newWorkbookRef.addWorkbookRefListener(this);
}
setInput(MindMapUI.getEditorInputFactory()
.createEditorInput(newWorkbookRef));
setCommandStack(newWorkbookRef.getCommandStack());
updateNames();
createPages();
installModelListener();
firePropertyChange(PROP_INPUT);
postSave();
// TODO restore editor state after changing editor input
setActivePage(editorStatus.getActiveIndex());
IGraphicalEditorPage[] pages = getPages();
for (int index = 0; index < pages.length; index++) {
IGraphicalViewer viewer = pages[index].getViewer();
viewer.getProperties().set(
IMindMapViewer.VIEWER_SELECT_CENTRALTOPIC, Boolean.FALSE);
Double scale = editorStatus.getZooms().get(index);
if (scale != null)
viewer.getZoomManager().setScale(scale);
String indexPath = index < editorStatus.getIndexPaths().size()
? editorStatus.getIndexPaths().get(index) : ""; //$NON-NLS-1$
List<String> topicTypeChain = index < editorStatus
.getTopicTypeChains().size()
? editorStatus.getTopicTypeChains().get(index)
: Collections.<String> emptyList();
if (indexPath != null) {
if ("".equals(indexPath)) //$NON-NLS-1$
viewer.setSelection(StructuredSelection.EMPTY, true);
else {
Object input = viewer.getInput();
if (input instanceof IMindMap) {
ITopic topic = ((IMindMap) input).getCentralTopic();
String[] indexes = indexPath.split("/"); //$NON-NLS-1$
for (int i = 1; i < indexes.length; i++) {
String type = i < topicTypeChain.size()
? topicTypeChain.get(i) : ITopic.ATTACHED;
if (topic.getChildren(type).size() <= Integer
.parseInt(indexes[i])) {
continue;
}
topic = topic.getChildren(type)
.get(Integer.parseInt(indexes[i]));
}
viewer.setSelection(new StructuredSelection(topic),
true);
}
}
}
Point scrollPosition = editorStatus.getScrollPositions().get(index);
if (scrollPosition != null)
viewer.scrollTo(scrollPosition);
}
recordEditorHistory();
//Force update IEclipseContext
IEclipseContext partContext = getSite()
.getService(IEclipseContext.class);
partContext.deactivate();
partContext.activateBranch();
}
private void reload() {
IWorkbookRef oldWorkbookRef = this.workbookRef;
if (oldWorkbookRef == null || oldWorkbookRef
.isInState(IWorkbookRef.CLOSED | IWorkbookRef.CLOSING)) {
throw new IllegalStateException(
"This mind map editor is already closed."); //$NON-NLS-1$
}
// save editor state before changing editor input
EditorStatus editorStatus = EditorStatus.getInstance();
editorStatus.saveStatus(oldWorkbookRef, getActivePage(), getPages());
IEditingContext context = oldWorkbookRef.getActiveContext();
disposeData();
while (getPageCount() > 0) {
removePage(0);
}
final IWorkbookRef newWorkbookRef = MindMapUIPlugin.getDefault()
.getWorkbookRefFactory()
.createWorkbookRef(oldWorkbookRef.getURI(), null);
if (newWorkbookRef == null) {
return;
}
try {
IProgressService runner = getSite()
.getService(IProgressService.class);
runner.run(true, true, new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor)
throws InvocationTargetException, InterruptedException {
newWorkbookRef.open(monitor);
}
});
} catch (InvocationTargetException e) {
e.printStackTrace();
return;
} catch (InterruptedException e) {
e.printStackTrace();
return;
}
this.workbookRef = newWorkbookRef;
if (newWorkbookRef != null) {
newWorkbookRef.setActiveContext(context);
newWorkbookRef.addPropertyChangeListener(this);
newWorkbookRef.addWorkbookRefListener(this);
}
setInput(MindMapUI.getEditorInputFactory()
.createEditorInput(newWorkbookRef));
setCommandStack(newWorkbookRef.getCommandStack());
updateNames();
createPages();
installModelListener();
firePropertyChange(PROP_INPUT);
firePropertyChange(IWorkbenchPartConstants.PROP_DIRTY);
// restore editor state after changing editor input
setActivePage(editorStatus.getActiveIndex());
IGraphicalEditorPage[] pages = getPages();
for (int index = 0; index < pages.length; index++) {
IGraphicalViewer viewer = pages[index].getViewer();
viewer.getProperties().set(
IMindMapViewer.VIEWER_SELECT_CENTRALTOPIC, Boolean.FALSE);
Double scale = editorStatus.getZooms().size() > index
? editorStatus.getZooms().get(index) : null;
if (scale != null)
viewer.getZoomManager().setScale(scale);
String indexPath = editorStatus.getIndexPaths().size() > index
? editorStatus.getIndexPaths().get(index) : ""; //$NON-NLS-1$
List<String> topicTypeChain = editorStatus.getTopicTypeChains()
.size() > index
? editorStatus.getTopicTypeChains().get(index)
: Collections.<String> emptyList();
if (indexPath != null) {
if ("".equals(indexPath)) //$NON-NLS-1$
viewer.setSelection(StructuredSelection.EMPTY, true);
else {
Object input = viewer.getInput();
if (input instanceof IMindMap) {
ITopic topic = ((IMindMap) input).getCentralTopic();
String[] indexes = indexPath.split("/"); //$NON-NLS-1$
for (int i = 1; i < indexes.length; i++) {
String type = i < topicTypeChain.size()
? topicTypeChain.get(i) : ITopic.ATTACHED;
if (topic.getChildren(type).size() <= Integer
.parseInt(indexes[i])) {
continue;
}
topic = topic.getChildren(type)
.get(Integer.parseInt(indexes[i]));
}
viewer.setSelection(new StructuredSelection(topic),
true);
}
}
}
Point scrollPosition = editorStatus.getScrollPositions()
.size() > index
? editorStatus.getScrollPositions().get(index)
: null;
if (scrollPosition != null)
viewer.scrollTo(scrollPosition);
}
}
private boolean safeRun(final IProgressMonitor monitor,
final boolean promptError, final IRunnableWithProgress runnable) {
final boolean[] successful = new boolean[1];
successful[0] = false;
SafeRunner.run(new SafeRunnable() {
@Override
public void run() throws Exception {
if (monitor != null) {
runnable.run(monitor);
} else {
IWorkbenchSiteProgressService context = getSite()
.getService(IWorkbenchSiteProgressService.class);
Assert.isTrue(context != null);
context.run(true, true, runnable);
}
successful[0] = true;
}
@Override
public void handleException(Throwable e) {
if (e instanceof InterruptedException)
// canceled, no error
return;
if (e instanceof InvocationTargetException) {
Throwable cause = ((InvocationTargetException) e)
.getTargetException();
if (cause != null)
e = cause;
}
if (!promptError) {
// log only
Logger.log(e);
return;
}
super.handleException(e);
}
});
return successful[0];
}
@Override
public boolean isSaveAsAllowed() {
return getWorkbook() != null;
}
public int promptToSaveOnClose() {
//TODO
// if (workbookRef != null && workbookRef.canSave()) {
// NullProgressMonitor monitor = new NullProgressMonitor();
// doSave(monitor);
// if (monitor.isCanceled())
// return CANCEL;
// return NO;
// }
return DEFAULT;
}
@Override
public void propertyChange(PropertyChangeEvent event) {
if (event.getSource() == workbookRef) {
workbookRefPropertyChange(event);
}
}
protected void workbookRefPropertyChange(PropertyChangeEvent event) {
if (IEditable.PROP_NAME.equals(event.getProperty())
|| IEditable.PROP_DESCRIPTION.equals(event.getProperty())) {
runInUI(new Runnable() {
@Override
public void run() {
updateNames();
}
});
} else if (IEditable.PROP_DIRTY.equals(event.getProperty())) {
runInUI(new Runnable() {
@Override
public void run() {
firePropertyChange(IWorkbenchPartConstants.PROP_DIRTY);
}
});
} else if (IEditable.PROP_MESSAGES.equals(event.getProperty())) {
runInUI(new Runnable() {
@Override
public void run() {
updateMessages(true);
}
});
}
}
private void runInUI(final Runnable runnable) {
final Control control = pageContainer;
if (control == null || control.isDisposed())
return;
final Display display = control.getDisplay();
if (display == null || display.isDisposed())
return;
display.asyncExec(runnable);
}
@Override
public void handleCommandStackEvent(CommandStackEvent event) {
// override to do nothing
}
/*
* (non-Javadoc)
* @see org.xmind.ui.internal.editor.IMindMapPreviewGenerator#
* generateMindMapPreview(org.xmind.ui.mindmap.IWorkbookRef,
* java.io.OutputStream, org.xmind.ui.internal.editor.MindMapPreviewOptions)
*/
@Override
public Properties generateMindMapPreview(IWorkbookRef workbookRef,
final ISheet sheet, final OutputStream output,
MindMapPreviewOptions options) throws IOException {
Assert.isLegal(output != null);
final Properties properties = new Properties();
if (sheet == null
|| MindMapUIPlugin.getDefault().getPreferenceStore()
.getBoolean(PrefConstants.PREVIEW_SKIPPED)
|| skipNextPreviewImage) {
URL url = BundleUtility.find(MindMapUI.PLUGIN_ID,
IMindMapImages.DEFAULT_THUMBNAIL);
if (url != null) {
InputStream input = url.openStream();
try {
FileUtils.transfer(input, output, false);
} finally {
input.close();
}
}
skipNextPreviewImage = false;
return properties;
}
IEncryptable encryptable = workbookRef.getAdapter(IEncryptable.class);
if (encryptable != null && encryptable.hasPassword()) {
URL url = BundleUtility.find(MindMapUI.PLUGIN_ID,
IMindMapImages.ENCRYPTED_THUMBNAIL);
if (url != null) {
InputStream input = url.openStream();
try {
FileUtils.transfer(input, output, false);
} finally {
input.close();
}
}
return properties;
}
Shell parentShell = getSite().getShell();
final Display display = parentShell.getDisplay();
final MindMapImageExporter exporter = new MindMapImageExporter(display);
final Exception[] error = new Exception[1];
display.syncExec(new Runnable() {
public void run() {
IGraphicalEditorPage page = findPage(sheet);
if (page != null) {
IGraphicalViewer sourceViewer = page.getViewer();
IMindMap map = (IMindMap) sourceViewer
.getAdapter(IMindMap.class);
if (map == null || map.getCentralTopic()
.equals(map.getSheet().getRootTopic())) {
exporter.setSourceViewer(sourceViewer, null, null,
new Insets(MindMapUI.DEFAULT_EXPORT_MARGIN));
} else {
exporter.setSource(new MindMap(sheet), null,
new Insets(MindMapUI.DEFAULT_EXPORT_MARGIN));
}
} else {
exporter.setSource(new MindMap(sheet), null,
new Insets(MindMapUI.DEFAULT_EXPORT_MARGIN));
}
exporter.setResize(ResizeConstants.RESIZE_MAXPIXELS, 1280,
1024);
exporter.setTargetStream(output);
try {
exporter.export();
} catch (SWTException e) {
error[0] = e;
return;
}
org.eclipse.draw2d.geometry.Point origin = exporter
.calcRelativeOrigin();
properties.put(PREVIEW_ORIGIN_X, String.valueOf(origin.x));
properties.put(PREVIEW_ORIGIN_Y, String.valueOf(origin.y));
properties.put(PREVIEW_BACKGROUND,
exporter.getBackgroundColor());
}
});
if (error[0] != null) {
throw new IOException(error[0]);
}
return properties;
}
/*
* (non-Javadoc)
* @see
* org.xmind.ui.wizards.ISaveContext#getContextVariable(java.lang.Class)
*/
@Override
public <T> T getContextVariable(Class<T> key) {
return getSite().getService(key);
}
/*
* (non-Javadoc)
* @see
* org.xmind.ui.wizards.ISaveContext#getContextVariable(java.lang.String)
*/
@Override
public Object getContextVariable(String key) {
IEvaluationService service = getSite()
.getService(IEvaluationService.class);
Assert.isNotNull(service);
Object variable = service.getCurrentState().getVariable(key);
return variable == IEvaluationContext.UNDEFINED_VARIABLE ? null
: variable;
}
private void activateFileNotifier() {
getEditorSite().getWorkbenchWindow().getWorkbench()
.addWindowListener(getWindowListener());
getEditorSite().getPage().addSelectionListener(getEditorSite().getId(),
getSelectionListener());
}
private void deactivateFileNotifier() {
getEditorSite().getWorkbenchWindow().getWorkbench()
.removeWindowListener(getWindowListener());
getEditorSite().getPage().removeSelectionListener(
getEditorSite().getId(), getSelectionListener());
}
private IWindowListener getWindowListener() {
if (windowListener == null) {
windowListener = new IWindowListener() {
@Override
public void windowOpened(IWorkbenchWindow window) {
}
@Override
public void windowDeactivated(IWorkbenchWindow window) {
}
@Override
public void windowClosed(IWorkbenchWindow window) {
}
@Override
public void windowActivated(IWorkbenchWindow window) {
IEditorPart activeEditor = getEditorSite().getPage()
.getActiveEditor();
if (activeEditor == MindMapEditor.this) {
if (workbookRef != null) {
workbookRef.activateNotifier();
}
}
}
};
}
return windowListener;
}
private ISelectionListener getSelectionListener() {
if (selectionListener == null) {
selectionListener = new ISelectionListener() {
@Override
public void selectionChanged(IWorkbenchPart part,
ISelection selection) {
if (workbookRef != null) {
workbookRef.activateNotifier();
}
}
};
}
return selectionListener;
}
@Override
public void fileChanged(final String title, final String message,
final String[] buttons) {
if (workbookRef.getState() != IWorkbookRef.NORMAL) {
return;
}
if (ignoreFileChanged) {
return;
}
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
deactivateFileNotifier();
getEditorSite().getPage().activate(MindMapEditor.this);
if (!isDirty()) {
reload();
} else {
MessageDialog dialog = new MessageDialog(null, title, null,
NLS.bind(
MindMapMessages.MindMapEditor_fileChangedDialog_message_prefix
+ message,
workbookRef.getName()),
MessageDialog.CONFIRM, buttons, 0);
int code = dialog.open();
if (code == 0) {
reload();
} else if (code == 1 || code == -1) {
ignoreFileChanged = true;
}
}
activateFileNotifier();
}
});
}
@Override
public void fileRemoved(final String title, final String message,
final String[] buttons, boolean forceQuit) {
if (workbookRef.getState() != IWorkbookRef.NORMAL) {
return;
}
if (forceQuit) {
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
closeEditor();
}
});
return;
}
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
deactivateFileNotifier();
getEditorSite().getPage().activate(MindMapEditor.this);
if (!isDirty()) {
closeEditor();
} else {
MessageDialog dialog = new MessageDialog(null, title, null,
NLS.bind(
MindMapMessages.MindMapEditor_fileRemovedDialog_message_prefix
+ message,
workbookRef.getName()),
MessageDialog.CONFIRM, buttons, 0);
int code = dialog.open();
if (code == 0) {
doSaveAs();
} else if (code == 1 || code == -1) {
closeEditor();
}
activateFileNotifier();
}
}
});
}
}