/* ****************************************************************************** * 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.properties; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; 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.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Text; import org.xmind.core.Core; import org.xmind.core.INumbering; import org.xmind.core.ITopic; import org.xmind.core.event.CoreEvent; import org.xmind.core.event.ICoreEventRegister; import org.xmind.gef.Request; import org.xmind.gef.draw2d.graphics.GraphicsUtils; import org.xmind.ui.internal.MindMapMessages; import org.xmind.ui.internal.MindMapUIPlugin; import org.xmind.ui.mindmap.INumberFormatDescriptor; import org.xmind.ui.mindmap.INumberSeparatorDescriptor; import org.xmind.ui.mindmap.MindMapUI; import org.xmind.ui.properties.MindMapPropertySectionPartBase; import org.xmind.ui.util.MindMapUtils; import org.xmind.ui.viewers.MComboViewer; public class NumberingPropertySectionPart extends MindMapPropertySectionPartBase { private static final Object INHERIT = new Object(); private class NumberFormatLabelProvider extends LabelProvider { public String getText(Object element) { if (element instanceof INumberFormatDescriptor) { INumberFormatDescriptor desc = (INumberFormatDescriptor) element; String name = desc.getName(); String description = desc.getDescription(); if (description == null || "".equals(description)) //$NON-NLS-1$ return name; return NLS.bind("{0} ({1})", name, description); //$NON-NLS-1$ } return super.getText(element); } } private class NumberSeparatorLabelProvider extends LabelProvider { public String getText(Object element) { if (element instanceof INumberSeparatorDescriptor) { INumberSeparatorDescriptor desc = (INumberSeparatorDescriptor) element; String name = desc.getName(); String description = desc.getDescription(); if (description == null || "".equals(description)) //$NON-NLS-1$ return name; return NLS.bind("{0} ({1})", name, description); //$NON-NLS-1$ } return super.getText(element); } } private class NumberDepthLabelProvider extends LabelProvider { @Override public String getText(Object element) { if (INHERIT.equals(element)) return MindMapMessages.NumberingProperty_NumberDepthLabelProvider_Inherit_text; if (element instanceof String) { String depth = (String) element; return NLS.bind("{0} {1}", depth, //$NON-NLS-1$ MindMapMessages.NumberingProperty_NumberDepthLabelProvider_Levels_text); } return super.getText(element); } } private class NumberFormatSelectionChangedListener implements ISelectionChangedListener { public void selectionChanged(SelectionChangedEvent event) { if (isRefreshing()) return; Object o = ((IStructuredSelection) event.getSelection()) .getFirstElement(); if (o instanceof INumberFormatDescriptor) { MindMapUIPlugin.getDefault().getUsageDataCollector() .increase("NumberingTypeCount:" //$NON-NLS-1$ + ((INumberFormatDescriptor) o).getId()); changeNumberFormat(((INumberFormatDescriptor) o).getId()); } } } private class SeparatorFormatSelectionChangedListener implements ISelectionChangedListener { public void selectionChanged(SelectionChangedEvent event) { if (isRefreshing()) return; Object o = ((IStructuredSelection) event.getSelection()) .getFirstElement(); if (o instanceof INumberSeparatorDescriptor) { changeNumberSeparator(((INumberSeparatorDescriptor) o).getId()); } } } private class NumberDepthSelectionChangedListener implements ISelectionChangedListener { @Override public void selectionChanged(SelectionChangedEvent event) { if (isRefreshing()) return; Object o = ((IStructuredSelection) event.getSelection()) .getFirstElement(); if (INHERIT == o) { changeNumberDepth(null); } else if (o instanceof String) { MindMapUIPlugin.getDefault().getUsageDataCollector() .increase("NumberDepthCount" + o); //$NON-NLS-1$ changeNumberDepth((String) o); } } } private MComboViewer formatViewer; private Button tieredCheck; private MComboViewer depthViewer; private MComboViewer separatorViewer; private Text prefixInput; private Text suffixInput; private Text numberLabel; protected void createContent(Composite parent) { Composite line1 = createLine(parent); line1.setLayout(generateGridLayout(1)); createNumberingFormatLine(line1); Composite line2 = createLine(parent); line2.setLayout(generateGridLayout(1)); createTieredCheckLine(line2); Composite line3 = createLine(parent); line3.setLayout(generateGridLayout(2)); createNumberingDepthLine(line3); Composite line4 = createLine(parent); line4.setLayout(generateGridLayout(2)); createNumberingSeparatorLine(line4); Composite line5 = createLine(parent); line5.setLayout(generateGridLayout(3)); createPrefixAndSuffixLine(line5); prefixInput.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); numberLabel .setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true)); suffixInput.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); } private GridLayout generateGridLayout(int cols) { GridLayout gridLayout = new GridLayout(cols, false); gridLayout.marginWidth = 0; gridLayout.marginHeight = 0; gridLayout.horizontalSpacing = 3; gridLayout.verticalSpacing = 3; return gridLayout; } private Composite createLine(Composite parent) { Composite line = new Composite(parent, SWT.NONE); line.setLayoutData( new GridData(GridData.FILL, GridData.FILL, true, false)); return line; } private void createNumberingFormatLine(Composite parent) { formatViewer = new MComboViewer(parent, MComboViewer.NORMAL); formatViewer.getControl().setLayoutData( new GridData(GridData.FILL, GridData.FILL, true, false)); formatViewer.setContentProvider(new ArrayContentProvider()); formatViewer.setLabelProvider(new NumberFormatLabelProvider()); List<INumberFormatDescriptor> descriptors = MindMapUI .getNumberFormatManager().getDescriptors(); List<Object> list = new ArrayList<Object>(descriptors.size() + 1); Object separator = new Object(); INumberFormatDescriptor defaultDescriptor = MindMapUI .getNumberFormatManager() .getDescriptor(MindMapUI.DEFAULT_NUMBER_FORMAT); for (INumberFormatDescriptor desc : descriptors) { if (desc != null && defaultDescriptor != null && desc != defaultDescriptor) { list.add(desc); } } if (defaultDescriptor != null) { list.add(separator); list.add(defaultDescriptor); } formatViewer.setSeparatorImitation(separator); formatViewer.setInput(list); formatViewer.addSelectionChangedListener( new NumberFormatSelectionChangedListener()); } private void createNumberingSeparatorLine(Composite parent) { Label separatorLabel = new Label(parent, SWT.NONE); separatorLabel.setText(PropertyMessages.Separator_label); separatorViewer = new MComboViewer(parent, MComboViewer.NORMAL); separatorViewer.getControl() .setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); separatorViewer.setContentProvider(new ArrayContentProvider()); separatorViewer.setLabelProvider(new NumberSeparatorLabelProvider()); List<INumberSeparatorDescriptor> descriptions = MindMapUI .getNumberSeparatorManager().getDescriptors(); List<Object> list = new ArrayList<Object>(descriptions.size() + 1); Object separator = new Object(); INumberSeparatorDescriptor defautDescriptor = MindMapUI .getNumberSeparatorManager() .getDescriptor(MindMapUI.DEFAULT_NUMBER_SEPARATOR); if (defautDescriptor != null) { list.add(defautDescriptor); list.add(separator); } for (INumberSeparatorDescriptor desc : descriptions) { if (desc != null && defautDescriptor != null && desc != defautDescriptor) { list.add(desc); } } separatorViewer.setSeparatorImitation(separator); separatorViewer.setInput(list); separatorViewer.addSelectionChangedListener( new SeparatorFormatSelectionChangedListener()); } private void createPrefixAndSuffixLine(Composite parent) { prefixInput = new Text(parent, SWT.SINGLE | SWT.BORDER | SWT.CENTER); prefixInput.setLayoutData( new GridData(GridData.FILL, GridData.CENTER, true, false)); prefixInput.setToolTipText(PropertyMessages.Prefix_toolTip); Listener eventHandler = new Listener() { public void handleEvent(Event event) { if (event.type == SWT.FocusIn) { if (event.widget == prefixInput) prefixInput.selectAll(); else suffixInput.selectAll(); } else { if (event.widget == prefixInput) changePrefix(prefixInput.getText()); else changeSuffix(suffixInput.getText()); } } }; prefixInput.addListener(SWT.DefaultSelection, eventHandler); prefixInput.addListener(SWT.FocusOut, eventHandler); prefixInput.addListener(SWT.FocusIn, eventHandler); numberLabel = new Text(parent, SWT.SINGLE | SWT.BORDER | SWT.READ_ONLY | SWT.CENTER); numberLabel.setLayoutData( new GridData(GridData.FILL, GridData.CENTER, false, false)); numberLabel.setEditable(false); numberLabel.setBackground(numberLabel.getDisplay() .getSystemColor(SWT.COLOR_LIST_BACKGROUND)); suffixInput = new Text(parent, SWT.SINGLE | SWT.BORDER | SWT.CENTER); suffixInput.setLayoutData( new GridData(GridData.FILL, GridData.CENTER, true, false)); suffixInput.setToolTipText(PropertyMessages.Suffix_toolTip); suffixInput.addListener(SWT.DefaultSelection, eventHandler); suffixInput.addListener(SWT.FocusOut, eventHandler); suffixInput.addListener(SWT.FocusIn, eventHandler); } private void createTieredCheckLine(Composite parent) { tieredCheck = new Button(parent, SWT.CHECK); tieredCheck.setText(MindMapMessages.NumberingProperty_TieredCheck_text); tieredCheck.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { changePrepending(tieredCheck.getSelection()); } }); } private void createNumberingDepthLine(Composite parent) { Label label = new Label(parent, SWT.NONE); label.setText(PropertyMessages.Depth_label); depthViewer = new MComboViewer(parent, MComboViewer.NORMAL); depthViewer.getControl() .setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); depthViewer.setContentProvider(new ArrayContentProvider()); depthViewer.setLabelProvider(new NumberDepthLabelProvider()); @SuppressWarnings("nls") String[] values = new String[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" }; List<Object> input = new ArrayList<Object>(values.length + 1); input.addAll(Arrays.asList(values)); Object sep = new Object(); input.add(sep); input.add(INHERIT); depthViewer.setSeparatorImitation(sep); depthViewer.setInput(input); depthViewer.addSelectionChangedListener( new NumberDepthSelectionChangedListener()); } public void setFocus() { if (formatViewer != null && !formatViewer.getControl().isDisposed()) { formatViewer.getControl().setFocus(); } } public void dispose() { super.dispose(); formatViewer = null; prefixInput = null; numberLabel = null; suffixInput = null; separatorViewer = null; depthViewer = null; tieredCheck = null; } protected void doRefresh() { Object o = ((IStructuredSelection) getCurrentSelection()) .getFirstElement(); if (o instanceof ITopic) { ITopic topic = (ITopic) o; ITopic parent = topic.getParent(); if (parent == null) parent = topic; INumbering numbering; if (ITopic.ATTACHED.equals(topic.getType())) { numbering = parent.getNumbering(); } else { numbering = null; } boolean hasFormat = false; if (formatViewer != null && !formatViewer.getControl().isDisposed()) { String format = numbering == null ? null : numbering.getComputedFormat(); if (format == null) { format = MindMapUI.DEFAULT_NUMBER_FORMAT; } else if (parent.getNumbering().getNumberFormat() == null && !topic.getNumbering().isInherited(0)) { format = MindMapUI.DEFAULT_NUMBER_FORMAT; } else { hasFormat = !MindMapUI.DEFAULT_NUMBER_FORMAT.equals(format); } INumberFormatDescriptor descriptor = MindMapUI .getNumberFormatManager().getDescriptor(format); formatViewer.setSelection( descriptor == null ? StructuredSelection.EMPTY : new StructuredSelection(descriptor)); } if (depthViewer != null && !depthViewer.getControl().isDisposed()) { Object select = INHERIT; if (numbering != null) { if (numbering.getDepth() != null) select = numbering.getDepth(); else if (numbering.getNumberFormat() != null && !numbering.isInherited(1)) select = "3"; //$NON-NLS-1$ depthViewer.setSelection(new StructuredSelection(select)); if (MindMapUI.DEFAULT_NUMBER_FORMAT .equals(numbering.getNumberFormat())) { depthViewer.setEnabled(false); } else { depthViewer .setEnabled(numbering.getNumberFormat() != null || topic.getNumbering().isInherited(0)); } } } if (separatorViewer != null && !separatorViewer.getControl().isDisposed()) { String separator = numbering == null ? null : numbering.getComputedSeparator(); if (separator == null) separator = MindMapUI.DEFAULT_NUMBER_SEPARATOR; INumberSeparatorDescriptor descriptor = MindMapUI .getNumberSeparatorManager().getDescriptor(separator); separatorViewer.setSelection( descriptor == null ? StructuredSelection.EMPTY : new StructuredSelection(descriptor)); } if (tieredCheck != null) { tieredCheck.setSelection( numbering != null && numbering.prependsParentNumbers()); } if (prefixInput != null && !prefixInput.isDisposed()) { String prefix = numbering == null ? null : numbering.getPrefix(); prefixInput.setText(prefix == null ? "" : prefix); //$NON-NLS-1$ } if (suffixInput != null && !suffixInput.isDisposed()) { String suffix = numbering == null ? null : numbering.getSuffix(); suffixInput.setText(suffix == null ? "" : suffix); //$NON-NLS-1$ } if (numberLabel != null && !numberLabel.isDisposed()) { String number; number = MindMapUtils.getNumberingText(topic, hasFormat ? null : MindMapUI.PREVIEW_NUMBER_FORMAT, hasFormat ? null : MindMapUI.DEFAULT_NUMBER_SEPARATOR); if (number == null || "".equals(number)) { //$NON-NLS-1$ numberLabel.setText(" "); //$NON-NLS-1$ } else { number = GraphicsUtils.getNormal().constrain(number, 100, JFaceResources.getDefaultFont(), GraphicsUtils.TRAIL); numberLabel.setText(number); } if (hasFormat) { numberLabel.setForeground(numberLabel.getDisplay() .getSystemColor(SWT.COLOR_LIST_FOREGROUND)); } else { numberLabel.setForeground(numberLabel.getDisplay() .getSystemColor(SWT.COLOR_DARK_GRAY)); } } } } protected void registerEventListener(Object source, ICoreEventRegister register) { if (source instanceof ITopic) { ITopic parent = ((ITopic) source).getParent(); if (parent == null) parent = (ITopic) source; register.setNextSourceFrom(parent); register.register(Core.TopicAdd); register.register(Core.TopicRemove); INumbering numbering = parent.getNumbering(); register.setNextSourceFrom(numbering); register.register(Core.NumberFormat); register.register(Core.NumberingPrefix); register.register(Core.NumberingSuffix); register.register(Core.NumberPrepending); register.register(Core.NumberingSeparator); register.register(Core.NumberingDepth); } } public void handleCoreEvent(CoreEvent event) { String type = event.getType(); if (Core.TopicAdd.equals(type) || Core.TopicRemove.equals(type)) { if (!ITopic.ATTACHED.equals(event.getData())) return; } super.handleCoreEvent(event); } private void changeNumberFormat(String formatId) { if (formatId != null) { Object o = ((IStructuredSelection) getCurrentSelection()) .getFirstElement(); if (o instanceof ITopic) { ITopic topic = ((ITopic) o).getParent(); if (topic == null) topic = (ITopic) o; // if (formatId.equals(topic.getNumbering().getParentFormat())) if (formatId.equals(topic.getNumbering().getNumberFormat())) formatId = null; } } sendRequest(fillTargets(new Request(MindMapUI.REQ_MODIFY_NUMBERING)) .setParameter(MindMapUI.PARAM_NUMBERING_FORMAT, formatId)); } private void changeNumberSeparator(String separatorId) { if (separatorId != null) { Object o = ((IStructuredSelection) getCurrentSelection()) .getFirstElement(); if (o instanceof ITopic) { ITopic topic = ((ITopic) o).getParent(); if (topic == null) topic = (ITopic) o; if (separatorId.equals(topic.getNumbering().getSeparator())) separatorId = null; } } sendRequest(fillTargets(new Request(MindMapUI.REQ_MODIFY_NUMBERING)) .setParameter(MindMapUI.PARAM_NUMBERING_SEPARATOR, separatorId)); } private void changeNumberDepth(String depth) { sendRequest(fillTargets(new Request(MindMapUI.REQ_MODIFY_NUMBERING)) .setParameter(MindMapUI.PARAM_NUMBERING_DEPTH, depth)); } private void changePrepending(boolean prepend) { sendRequest(fillTargets(new Request(MindMapUI.REQ_MODIFY_NUMBERING)) .setParameter(MindMapUI.PARAM_NUMBERING_PREPENDING, Boolean.valueOf(prepend))); } private void changePrefix(String newPrefix) { sendRequest(fillTargets(new Request(MindMapUI.REQ_MODIFY_NUMBERING) .setParameter(MindMapUI.PARAM_NUMBERING_PREFIX, newPrefix))); } private void changeSuffix(String newSuffix) { sendRequest(fillTargets(new Request(MindMapUI.REQ_MODIFY_NUMBERING) .setParameter(MindMapUI.PARAM_NUMBERING_SUFFIX, newSuffix))); } }