/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.modeling.ui.preferences; import java.text.DecimalFormat; import java.text.ParseException; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.preference.BooleanFieldEditor; import org.eclipse.jface.preference.FieldEditor; import org.eclipse.jface.preference.FieldEditorPreferencePage; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPreferencePage; import org.eclipse.ui.preferences.ScopedPreferenceStore; import org.osgi.service.prefs.BackingStoreException; import org.simantics.modeling.ui.Activator; import org.simantics.ui.workbench.preferences.NumberFieldEditor; import org.simantics.utils.page.MarginUtils.Margin; import org.simantics.utils.page.MarginUtils.Margins; import org.simantics.utils.page.PageDesc; import org.simantics.utils.page.PageOrientation; import org.simantics.utils.ui.ErrorLogger; public class DiagramPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage { public DiagramPreferencePage() { super(GRID); } @Override public void init(IWorkbench workbench) { } @Override protected IPreferenceStore doGetPreferenceStore() { return new ScopedPreferenceStore(InstanceScope.INSTANCE, Activator.PLUGIN_ID); } @Override protected void createFieldEditors() { Group group = new Group(getFieldEditorParent(), SWT.NONE); group.setText("Grid Snapping"); GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(group); NumberFieldEditor gridSizeField = new NumberFieldEditor(DiagramPreferences.P_SNAP_GRID_SIZE, "Grid size (mm)", group); // 1um - 1m grid size allowed gridSizeField.setValidRange(1e-3, 1e3); addField(gridSizeField); GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(false).extendedMargins(12, 12, 12, 12).spacing(5, 4).applyTo(group); PageDescFieldEditor pageDescField = new PageDescFieldEditor(getFieldEditorParent()); addField(pageDescField); Group displayGroup = new Group(getFieldEditorParent(), SWT.NONE); displayGroup.setText("Display"); GridDataFactory.fillDefaults().grab(true, false).span(1, 1).applyTo(displayGroup); BooleanFieldEditor displayPage = new BooleanFieldEditor(DiagramPreferences.P_DISPLAY_PAGE_SIZE, "Show page borders", BooleanFieldEditor.SEPARATE_LABEL, displayGroup); addField(displayPage); BooleanFieldEditor displayMargins = new BooleanFieldEditor(DiagramPreferences.P_DISPLAY_MARGINS, "Show margins", BooleanFieldEditor.SEPARATE_LABEL, displayGroup); addField(displayMargins); GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(false).extendedMargins(12, 12, 12, 12).spacing(5, 4).applyTo(displayGroup); } static class PageDescFieldEditor extends FieldEditor { PageDesc desc; PageDesc previousDesc; Group group; Button portrait; Button landscape; Combo combo; Text topMargin; Text leftMargin; Text rightMargin; Text bottomMargin; Canvas pageCanvas; Listener marginListener = new Listener() { @Override public void handleEvent(Event event) { if (event.type == SWT.Modify) { Text txt = (Text) event.widget; String s = txt.getText(); double value = 0; boolean invalid = false; try { value = DecimalFormat.getInstance().parse(s).doubleValue(); } catch (ParseException e) { invalid = true; } if (invalid) { txt.setBackground(txt.getDisplay().getSystemColor(SWT.COLOR_RED)); } else { txt.setBackground(null); int mask = txt == topMargin ? Margins.TOP : txt == leftMargin ? Margins.LEFT : txt == rightMargin ? Margins.RIGHT : txt == bottomMargin ? Margins.BOTTOM : 0; Margin m = new Margin(0, 0, value); desc = desc.withMargins(desc.getMargins().withSide(mask, m)); applyValuesToWidgets(false); } } else if (event.type == SWT.FocusIn) { Text txt = (Text) event.widget; txt.selectAll(); } } }; int[] marginEvents = { SWT.Modify, SWT.FocusIn }; private void addMarginListeners() { for (int et : marginEvents) { topMargin.addListener(et, marginListener); leftMargin.addListener(et, marginListener); rightMargin.addListener(et, marginListener); bottomMargin.addListener(et, marginListener); } } private void removeMarginListeners() { for (int et : marginEvents) { topMargin.removeListener(et, marginListener); leftMargin.removeListener(et, marginListener); rightMargin.removeListener(et, marginListener); bottomMargin.removeListener(et, marginListener); } } public PageDescFieldEditor(Composite parent) { DiagramPreferences prefs = DiagramPreferenceUtil.getPreferences(); desc = prefs.get(DiagramPreferences.P_DEFAULT_PAGE_SIZE); previousDesc = desc; createControl(parent); } @Override protected void adjustForNumColumns(int numColumns) { if (group != null) { ((GridData) group.getLayoutData()).horizontalSpan = numColumns; } } @Override protected void doFillIntoGrid(Composite parent, int numColumns) { group = getGroupControl(parent); GridDataFactory.fillDefaults().grab(true, false).span(numColumns, 1).applyTo(group); } /** * Returns the change button for this field editor. * @param parent The Composite to create the receiver in. * * @return the change button */ protected Group getGroupControl(Composite parent) { if (group == null) { group = new Group(parent, SWT.NONE); group.setText("Page Defaults"); group.setToolTipText("The default settings for diagram pages."); group.setFont(parent.getFont()); group.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent event) { group = null; } }); GridLayoutFactory.fillDefaults().numColumns(3).equalWidth(false).extendedMargins(12, 12, 12, 12).spacing(5, 4).applyTo(group); createChoosers(group); } else { checkParent(group, parent); } return group; } protected void createChoosers(Composite parent) { //parent.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_BLUE)); Label label = new Label(parent, 0); label.setText("Size:"); combo = new Combo(parent, 0); combo.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { PageDesc pd = (PageDesc) combo.getData(combo.getItem(combo.getSelectionIndex())); if (pd != null) { desc = desc.withSizeFrom(pd).withText(pd.getText()); applyValuesToWidgets(); } } }); Composite marginComposite = new Composite(parent, 0); //marginComposite.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_RED)); GridDataFactory.fillDefaults().grab(true, true).grab(true, true).align(SWT.CENTER, SWT.CENTER).span(1, 2).applyTo(marginComposite); GridLayoutFactory.fillDefaults().numColumns(3).margins(5, 5).spacing(3, 3).applyTo(marginComposite); label = new Label(marginComposite, 0); label.setText("Margins (mm)"); GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.TOP).span(3, 1).applyTo(label); label = new Label(marginComposite, 0); GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.TOP).span(3, 1).applyTo(label); new Label(marginComposite, 0); topMargin = new Text(marginComposite, SWT.BORDER | SWT.CENTER); GridDataFactory.fillDefaults().hint(50, SWT.DEFAULT).grab(true, false).applyTo(topMargin); new Label(marginComposite, 0); leftMargin = new Text(marginComposite, SWT.BORDER | SWT.RIGHT); GridDataFactory.swtDefaults().hint(50, SWT.DEFAULT).grab(true, false).applyTo(leftMargin); pageCanvas = new Canvas(marginComposite, 0); GridDataFactory.swtDefaults().hint(SWT.DEFAULT, SWT.DEFAULT).grab(true, true).applyTo(pageCanvas); pageCanvas.addPaintListener(new PaintListener() { @Override public void paintControl(PaintEvent e) { GC gc = e.gc; Point size = pageCanvas.getSize(); double w = desc.getOrientedWidth(); double h = desc.getOrientedHeight(); Margins margins = desc.getMargins(); int top = (int) Math.round(size.y * margins.top.diagramAbsolute / h); int bottom = (int) Math.round(size.y * margins.bottom.diagramAbsolute / h); int left = (int) Math.round(size.x * margins.left.diagramAbsolute / w); int right = (int) Math.round(size.x * margins.right.diagramAbsolute / w); gc.setBackground(gc.getDevice().getSystemColor(SWT.COLOR_GRAY)); gc.fillRectangle(0, 0, size.x, size.y); if ((top+bottom) < size.y && (left+right) < size.x) { gc.drawLine(left, 0, left, size.y-1); gc.drawLine(size.x-1-right, 0, size.x-1-right, size.y-1); gc.drawLine(0, top, size.x-1, top); gc.drawLine(0, size.y-1-bottom, size.x-1, size.y-1-bottom); gc.setBackground(gc.getDevice().getSystemColor(SWT.COLOR_WHITE)); gc.fillRectangle(left+1, top+1, size.x-2-right-left, size.y-2-top-bottom); } } }); rightMargin = new Text(marginComposite, SWT.BORDER | SWT.LEFT); GridDataFactory.swtDefaults().hint(50, SWT.DEFAULT).grab(true, false).applyTo(rightMargin); new Label(marginComposite, 0); bottomMargin = new Text(marginComposite, SWT.BORDER | SWT.CENTER); GridDataFactory.fillDefaults().hint(50, SWT.DEFAULT).grab(true, false).applyTo(bottomMargin); new Label(marginComposite, 0); addMarginListeners(); label = new Label(parent, 0); label.setText("Orientation:"); Composite comp = new Composite(parent, 0); GridDataFactory.fillDefaults().span(1, 1).align(SWT.LEFT, SWT.CENTER).applyTo(comp); GridLayoutFactory.fillDefaults().numColumns(1).applyTo(comp); portrait = new Button(comp, SWT.RADIO); landscape = new Button(comp, SWT.RADIO); portrait.setText("Portrait"); landscape.setText("Landscape"); Listener orientationListener = new Listener() { @Override public void handleEvent(Event event) { if (portrait.getSelection()) desc = desc.withOrientation(PageOrientation.Portrait); else desc = desc.withOrientation(PageOrientation.Landscape); applyValuesToWidgets(); } }; portrait.addListener(SWT.Selection, orientationListener); landscape.addListener(SWT.Selection, orientationListener); PageDesc[] pds = PageDesc.getPredefinedDescriptions(); for (int i = 0; i < pds.length; ++i) { PageDesc pd = pds[i]; combo.add(pd.getText()); combo.setData(pd.getText(), pd); } applyValuesToWidgets(); } @Override protected void doLoad() { if (group != null) { DiagramPreferences prefs = DiagramPreferenceUtil.getPreferences(); desc = prefs.get(DiagramPreferences.P_DEFAULT_PAGE_SIZE); previousDesc = desc; applyValuesToWidgets(); } } private void applyValuesToWidgets() { applyValuesToWidgets(true); } private void applyValuesToWidgets(boolean applyMargins) { PageOrientation orit = desc.getOrientation(); portrait.setSelection( orit == PageOrientation.Portrait ); landscape.setSelection( orit == PageOrientation.Landscape ); String name = desc.getText(); int selectedIndex = combo.getSelectionIndex(); for (int i = 0; i < combo.getItemCount(); ++i) { String item = combo.getItem(i); if (name.equals(item)) { if (selectedIndex != i) { combo.select(i); } break; } } if (applyMargins) { boolean marginEnabled = !desc.isInfinite(); topMargin.setEnabled(marginEnabled); leftMargin.setEnabled(marginEnabled); rightMargin.setEnabled(marginEnabled); bottomMargin.setEnabled(marginEnabled); if (marginEnabled) { removeMarginListeners(); Margins margins = desc.getMargins(); topMargin.setText(DecimalFormat.getNumberInstance().format(margins.top.diagramAbsolute)); leftMargin.setText(DecimalFormat.getNumberInstance().format(margins.left.diagramAbsolute)); rightMargin.setText(DecimalFormat.getNumberInstance().format(margins.right.diagramAbsolute)); bottomMargin.setText(DecimalFormat.getNumberInstance().format(margins.bottom.diagramAbsolute)); addMarginListeners(); } } layout(desc); } void layout(PageDesc desc) { double max = Math.max(desc.getOrientedWidth(), desc.getOrientedHeight()); double min = Math.min(desc.getOrientedWidth(), desc.getOrientedHeight()); double ratio = min / max; int larger = 100; int smaller = (int) Math.round(ratio*larger); boolean vertical = desc.getOrientedWidth() < desc.getOrientedHeight(); GridData gd = (GridData) pageCanvas.getLayoutData(); gd.widthHint = vertical ? smaller : larger; gd.heightHint = vertical ? larger : smaller; group.getParent().layout(true, true); pageCanvas.redraw(); } @Override protected void doLoadDefault() { if (group != null) { DiagramPreferences prefs = DiagramPreferenceUtil.getDefaultPreferences(); desc = prefs.get(DiagramPreferences.P_DEFAULT_PAGE_SIZE); previousDesc = desc; applyValuesToWidgets(); } // This is a workaround for a problem of not having a single preference backing this CommonsFieldEditor setPresentsDefaultValue(false); } @Override protected void doStore() { try { DiagramPreferenceUtil.flushPreferences(DiagramPreferenceUtil.getPreferences().withValue(DiagramPreferences.P_DEFAULT_PAGE_SIZE, desc)); } catch (BackingStoreException e) { ErrorLogger.defaultLogError("Could not store diagram preferences", e); } } @Override public int getNumberOfControls() { return 1; } } }