/* ****************************************************************************** * 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.outline; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.TreeEditor; 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.TextTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.FocusAdapter; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; 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.Listener; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.IWorkbenchActionConstants; import org.xmind.core.IWorkbook; import org.xmind.gef.EditDomain; import org.xmind.gef.GEF; import org.xmind.gef.IViewer; import org.xmind.gef.Request; import org.xmind.gef.dnd.IDndClient; import org.xmind.gef.part.IPart; import org.xmind.gef.tree.ITreeViewer; import org.xmind.gef.tree.TreeRootPart; import org.xmind.gef.tree.TreeSelectTool; import org.xmind.gef.tree.TreeViewer; import org.xmind.gef.ui.editor.IGraphicalEditor; import org.xmind.gef.ui.outline.GraphicalOutlinePage; import org.xmind.ui.internal.MindMapMessages; import org.xmind.ui.internal.dnd.MindMapElementTransfer; import org.xmind.ui.internal.editpolicies.ModifiablePolicy; import org.xmind.ui.mindmap.IMindMapImages; import org.xmind.ui.mindmap.MindMapUI; public class MindMapOutlinePage extends GraphicalOutlinePage { private class ShowWorkbookAction extends Action { public ShowWorkbookAction() { super(MindMapMessages.ShowWorkbook_text, AS_RADIO_BUTTON); setId("org.xmind.ui.showWorkbook"); //$NON-NLS-1$ setToolTipText(MindMapMessages.ShowWorkbook_toolTip); setImageDescriptor( MindMapUI.getImages().get(IMindMapImages.WORKBOOK, true)); setDisabledImageDescriptor( MindMapUI.getImages().get(IMindMapImages.WORKBOOK, false)); } public void run() { setShowCurrentPageViewer(false); } } private class ShowCurrentSheetAction extends Action { public ShowCurrentSheetAction() { super(MindMapMessages.ShowSheet_text, AS_RADIO_BUTTON); setId("org.xmind.ui.showCurrentSheet"); //$NON-NLS-1$ setToolTipText(MindMapMessages.ShowSheet_toolTip); setImageDescriptor( MindMapUI.getImages().get(IMindMapImages.SHEET, true)); setDisabledImageDescriptor( MindMapUI.getImages().get(IMindMapImages.SHEET, false)); } public void run() { setShowCurrentPageViewer(true); } } private int controlStyle; private EditDomain domain; IAction showWorkbookAction; IAction showCurrentSheetAction; public MindMapOutlinePage(IGraphicalEditor parentEditor, int controlStyle) { super(parentEditor); this.controlStyle = controlStyle; this.domain = new EditDomain(); domain.installTool(GEF.TOOL_SELECT, new TreeSelectTool()); domain.setCommandStack(parentEditor.getCommandStack()); domain.installEditPolicy(MindMapUI.POLICY_MODIFIABLE, new ModifiablePolicy()); } public void createControl(Composite parent) { showWorkbookAction = new ShowWorkbookAction(); showCurrentSheetAction = new ShowCurrentSheetAction(); IMenuManager menu = getSite().getActionBars().getMenuManager(); menu.add(showWorkbookAction); menu.add(showCurrentSheetAction); menu.add(new Separator()); menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); // IToolBarManager toolBar = getSite().getActionBars().getToolBarManager(); // toolBar.add(showWorkbookAction); // toolBar.add(showCurrentSheetAction); // toolBar.add(new Separator()); // toolBar.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); showWorkbookAction.setChecked(!isShowCurrentPageViewer()); showCurrentSheetAction.setChecked(isShowCurrentPageViewer()); super.createControl(parent); } protected TreeViewer createEditorTreeViewer() { MindMapTreeViewer viewer = new MindMapTreeViewer(); viewer.getProperties().set(ITreeViewer.PROP_HEADER_VISIBLE, false); return viewer; } protected Control createEditorTreeViewerControl(ITreeViewer viewer, Composite parent) { Control control = ((TreeViewer) viewer).createControl(parent, controlStyle); hookViewerControl(viewer, control); return control; } protected Object createEditorTreeViewerInput( IGraphicalEditor parentEditor) { return parentEditor.getAdapter(IWorkbook.class); } protected ITreeViewer createPageTreeViewer() { MindMapTreeViewer viewer = new MindMapTreeViewer(); viewer.getProperties().set(ITreeViewer.PROP_HEADER_VISIBLE, false); return viewer; } protected Control createPageTreeViewerControl(ITreeViewer viewer, Composite parent) { Control control = ((TreeViewer) viewer).createControl(parent, controlStyle); hookViewerControl(viewer, control); return control; } protected Object createPageTreeViewerInput(Object pageInput) { return pageInput; } protected void configureTreeViewer(ITreeViewer viewer) { super.configureTreeViewer(viewer); viewer.setEditDomain(domain); viewer.setPartFactory(MindMapUI.getMindMapTreePartFactory()); viewer.setRootPart(new TreeRootPart()); } protected void hookViewerControl(final IViewer viewer, final Control control) { final DragSource dragSource = new DragSource(control, DND.DROP_COPY | DND.DROP_MOVE); dragSource.setTransfer( new Transfer[] { MindMapElementTransfer.getInstance(), TextTransfer.getInstance() }); dragSource.addDragListener(new DragSourceListener() { Object[] elements; String text; public void dragStart(DragSourceEvent event) { elements = getElements(); if (elements == null || elements.length == 0) event.doit = false; else text = createText(elements); } private Object[] getElements() { if (control instanceof Tree) { TreeItem[] selection = ((Tree) control).getSelection(); if (selection.length > 0) { Object[] elements = new Object[selection.length]; for (int i = 0; i < selection.length; i++) { TreeItem item = selection[i]; Object data = item.getData(); if (data instanceof IPart) { data = ((IPart) data).getModel(); } elements[i] = data; } return elements; } } return null; } public void dragSetData(DragSourceEvent event) { if (MindMapElementTransfer.getInstance() .isSupportedType(event.dataType)) { event.data = elements; } else if (TextTransfer.getInstance() .isSupportedType(event.dataType)) { event.data = text; } } private String createText(Object[] elements) { IDndClient textClient = MindMapUI.getMindMapDndSupport() .getDndClient(MindMapUI.DND_TEXT); if (textClient == null) return null; Object data = textClient.toTransferData(elements, viewer); return data instanceof String ? (String) data : null; } public void dragFinished(DragSourceEvent event) { } }); control.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { dragSource.dispose(); } }); control.addListener(SWT.MouseDoubleClick, new Listener() { public void handleEvent(Event event) { handleDoubleClick(event, viewer, control); event.doit = false; } }); } protected void handleDoubleClick(Event event, IViewer viewer, Control control) { startEditing(viewer, control); } private void startEditing(IViewer viewer, Control control) { Tree tree = (Tree) control; TreeItem[] selection = tree.getSelection(); if (selection.length == 0) return; final TreeItem item = selection[0]; if (!(item.getData() instanceof TopicTreePart)) { return; } TreeEditor editor = new TreeEditor(tree) { @Override public void layout() { super.layout(); Control editor = getEditor(); if (editor == null || editor.isDisposed()) return; Rectangle bounds = editor.getBounds(); Point prefSize = editor.computeSize(SWT.DEFAULT, SWT.DEFAULT); if (prefSize.y > bounds.height) { bounds.y += (bounds.height - prefSize.y - 1) / 2; bounds.height = prefSize.y; } editor.setBounds(bounds); } }; editor.horizontalAlignment = SWT.LEFT; editor.grabHorizontal = true; editor.minimumWidth = 50; final Text text = new Text(tree, SWT.SINGLE | SWT.BORDER); text.setCursor(Display.getCurrent().getSystemCursor(SWT.CURSOR_IBEAM)); editor.setEditor(text, item); final String oldValue = item.getText(); text.setText(oldValue); text.setFocus(); text.selectAll(); text.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { item.setText(text.getText()); modifyTreeItem(item); // This async process fixes a bug on Leopard: // Whole workbench crashes e.display.asyncExec(new Runnable() { public void run() { text.dispose(); } }); } }); text.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { switch (e.character) { case SWT.ESC: item.setText(oldValue); // This async process fixes a bug on Leopard: // Whole workbench crashes e.display.asyncExec(new Runnable() { public void run() { text.dispose(); } }); break; case SWT.CR: item.setText(text.getText()); modifyTreeItem(item); // This async process fixes a bug on Leopard: // Whole workbench crashes e.display.asyncExec(new Runnable() { public void run() { text.dispose(); } }); break; } } }); } protected void modifyTreeItem(TreeItem item) { Object o = item.getData(); if (o instanceof IPart) { IPart part = (IPart) o; part.handleRequest(new Request(GEF.REQ_MODIFY) .setViewer(part.getSite().getViewer()) .setParameter(GEF.PARAM_TEXT, item.getText()) .setPrimaryTarget(part), GEF.ROLE_MODIFIABLE); } } }