-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.modeling.ui.pdf;\r
-\r
-import java.io.File;\r
-import java.lang.reflect.InvocationTargetException;\r
-import java.util.ArrayDeque;\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.Deque;\r
-import java.util.HashSet;\r
-import java.util.List;\r
-import java.util.Set;\r
-import java.util.regex.Matcher;\r
-import java.util.regex.Pattern;\r
-\r
-import org.eclipse.core.runtime.IPath;\r
-import org.eclipse.core.runtime.IProgressMonitor;\r
-import org.eclipse.core.runtime.Path;\r
-import org.eclipse.core.runtime.SubMonitor;\r
-import org.eclipse.jface.layout.GridDataFactory;\r
-import org.eclipse.jface.operation.IRunnableWithProgress;\r
-import org.eclipse.jface.resource.JFaceResources;\r
-import org.eclipse.jface.resource.LocalResourceManager;\r
-import org.eclipse.jface.viewers.CellLabelProvider;\r
-import org.eclipse.jface.viewers.CheckStateChangedEvent;\r
-import org.eclipse.jface.viewers.CheckboxTreeViewer;\r
-import org.eclipse.jface.viewers.ICheckStateListener;\r
-import org.eclipse.jface.viewers.ICheckStateProvider;\r
-import org.eclipse.jface.viewers.ITreeContentProvider;\r
-import org.eclipse.jface.viewers.StructuredSelection;\r
-import org.eclipse.jface.viewers.TreeViewer;\r
-import org.eclipse.jface.viewers.Viewer;\r
-import org.eclipse.jface.viewers.ViewerCell;\r
-import org.eclipse.jface.viewers.ViewerComparator;\r
-import org.eclipse.jface.viewers.ViewerFilter;\r
-import org.eclipse.jface.wizard.WizardPage;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.custom.CCombo;\r
-import org.eclipse.swt.events.DisposeEvent;\r
-import org.eclipse.swt.events.DisposeListener;\r
-import org.eclipse.swt.events.ModifyEvent;\r
-import org.eclipse.swt.events.ModifyListener;\r
-import org.eclipse.swt.events.SelectionAdapter;\r
-import org.eclipse.swt.events.SelectionEvent;\r
-import org.eclipse.swt.events.SelectionListener;\r
-import org.eclipse.swt.graphics.Color;\r
-import org.eclipse.swt.layout.GridData;\r
-import org.eclipse.swt.layout.GridLayout;\r
-import org.eclipse.swt.layout.RowLayout;\r
-import org.eclipse.swt.widgets.Button;\r
-import org.eclipse.swt.widgets.Combo;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Display;\r
-import org.eclipse.swt.widgets.FileDialog;\r
-import org.eclipse.swt.widgets.Label;\r
-import org.eclipse.swt.widgets.Text;\r
-import org.eclipse.swt.widgets.TreeItem;\r
-import org.simantics.browsing.ui.common.views.DefaultFilterStrategy;\r
-import org.simantics.browsing.ui.common.views.IFilterStrategy;\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.common.NamedResource;\r
-import org.simantics.db.common.request.ReadRequest;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.modeling.requests.Node;\r
-import org.simantics.utils.FileUtils;\r
-import org.simantics.utils.strings.AlphanumComparator;\r
-import org.simantics.utils.ui.ISelectionUtils;\r
-\r
-public class PDFExportPage extends WizardPage {\r
-\r
- protected Display display;\r
-\r
- protected PDFExportPlan exportModel;\r
-\r
- protected IFilterStrategy filterStrategy = new DefaultFilterStrategy();\r
-\r
- protected Combo modelSelector;\r
- protected SelectionListener modelSelectorListener;\r
-\r
- protected Text filter;\r
-\r
- protected Matcher matcher = null;\r
-\r
- protected CheckboxTreeViewer tree;\r
-\r
- protected CCombo exportLocation;\r
- protected ModifyListener exportLocationListener;\r
-\r
- protected Set<Node> selectedNodes;\r
-\r
- protected LocalResourceManager resourceManager;\r
- protected Color noDiagramColor;\r
- \r
- protected Label toFileLabel;\r
-\r
- protected boolean exportLocationTouchedByUser = false;\r
-\r
- ICheckStateProvider checkStateProvider = new ICheckStateProvider() {\r
- @Override\r
- public boolean isChecked(Object element) {\r
- Node node = (Node) element;\r
-\r
- // Primarily checked if any children are selected.\r
- Collection<Node> children = node.getChildren();\r
- if (!children.isEmpty()) {\r
- for (Node child : node.getChildren())\r
- if (isChecked(child))\r
- return true;\r
-\r
- // No children are checked, not checked.\r
- return false;\r
- }\r
-\r
- // Otherwise checked only if selected.\r
- return selectedNodes.contains(node);\r
- }\r
- @Override\r
- public boolean isGrayed(Object element) {\r
- Node node = (Node) element;\r
-\r
- // Grayed if there are children but not all of them are selected.\r
- Collection<Node> children = node.getChildren();\r
- if (!children.isEmpty()) {\r
- for (Node child : children)\r
- if (!selectedNodes.contains(child))\r
- return true;\r
- }\r
-\r
- // Grayed if the node itself contains no diagram.\r
- if (node.getDiagramResource() == null)\r
- return true;\r
-\r
- // Otherwise never grayed.\r
- return false;\r
- }\r
- };\r
-\r
- protected PDFExportPage(PDFExportPlan model) {\r
- super("Export Diagrams to PDF", "Define Exported Items", null);\r
- this.exportModel = model;\r
- this.selectedNodes = exportModel.selectedNodeSet;\r
- }\r
-\r
- @Override\r
- public void createControl(Composite parent) {\r
- this.display = parent.getDisplay();\r
-\r
- Composite container = new Composite(parent, SWT.NONE);\r
- {\r
- GridLayout layout = new GridLayout();\r
- layout.horizontalSpacing = 20;\r
- layout.verticalSpacing = 10;\r
- layout.numColumns = 3;\r
- container.setLayout(layout);\r
- }\r
- resourceManager = new LocalResourceManager(JFaceResources.getResources());\r
- container.addDisposeListener(new DisposeListener() {\r
- @Override\r
- public void widgetDisposed(DisposeEvent e) {\r
- resourceManager.dispose();\r
- }\r
- });\r
- noDiagramColor = container.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY);\r
-\r
- Label modelSelectorLabel = new Label(container, SWT.NONE);\r
- modelSelectorLabel.setText("Model Selector:");\r
- GridDataFactory.fillDefaults().span(1, 1).applyTo(modelSelectorLabel);\r
- modelSelector = new Combo(container, SWT.BORDER | SWT.READ_ONLY);\r
- GridDataFactory.fillDefaults().span(2, 1).applyTo(modelSelector);\r
- modelSelectorListener = new SelectionAdapter() {\r
- @Override\r
- public void widgetSelected(SelectionEvent e) {\r
- NamedResource data = (NamedResource) modelSelector.getData(String.valueOf(modelSelector.getSelectionIndex()));\r
- scheduleInitializeData(data);\r
- }\r
- };\r
-\r
- // Fill model selector combo\r
- for (int i = 0; i < exportModel.selectableModels.size(); ++i) {\r
- NamedResource nr = exportModel.selectableModels.get(i);\r
- modelSelector.add(nr.getName());\r
- modelSelector.setData("" + i, nr);\r
- }\r
-\r
- modelSelector.addSelectionListener(modelSelectorListener);\r
-\r
-// Label label = new Label(container, SWT.NONE);\r
-// label.setText("Diagrams to Export:");\r
-// GridDataFactory.fillDefaults().span(3, 1).applyTo(label);\r
-\r
- Label filterLabel = new Label(container, SWT.NONE);\r
- filterLabel.setText("Fi<er:");\r
- GridDataFactory.fillDefaults().span(1, 1).applyTo(filterLabel);\r
- filter = new Text(container, SWT.BORDER);\r
- GridDataFactory.fillDefaults().span(2, 1).applyTo(filter);\r
- filter.addModifyListener(new ModifyListener() {\r
- @Override\r
- public void modifyText(ModifyEvent e) {\r
- resetFilterString(filter.getText());\r
- }\r
- });\r
-\r
- tree = new CheckboxTreeViewer(container, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION);\r
- {\r
- tree.setUseHashlookup(true);\r
- GridDataFactory.fillDefaults().grab(true, true).span(3, 1).applyTo(tree.getControl());\r
- tree.getControl().setToolTipText("Selects the diagram to include in the exported document.");\r
- tree.setAutoExpandLevel(TreeViewer.ALL_LEVELS);\r
- tree.addCheckStateListener(new ICheckStateListener(){\r
- void addOrRemoveSelection(Node node, boolean add) {\r
- if (add)\r
- selectedNodes.add(node);\r
- else\r
- selectedNodes.remove(node);\r
- }\r
- void addOrRemoveSelectionRec(Node node, boolean add) {\r
- addOrRemoveSelection(node, add);\r
- for (Node child : node.getChildren())\r
- addOrRemoveSelectionRec(child, add);\r
- }\r
- @Override\r
- public void checkStateChanged(CheckStateChangedEvent event) {\r
- final boolean checked = event.getChecked();\r
- Node checkedNode = (Node) event.getElement();\r
-\r
- Set<Node> nodes = new HashSet<Node>();\r
- Set<Node> selection = ISelectionUtils.filterSetSelection(tree.getSelection(), Node.class);\r
- if (selection.contains(checkedNode))\r
- nodes.addAll(selection);\r
- else\r
- tree.setSelection(StructuredSelection.EMPTY);\r
- nodes.add(checkedNode);\r
-\r
- for (Node node : nodes) {\r
- addOrRemoveSelectionRec(node, checked);\r
-\r
-// tree.setSubtreeChecked(node, checked);\r
-// The checked node is always either checked or not checked, never grayed.\r
-// tree.setGrayed(node, checkStateProvider.isGrayed(node));\r
-\r
-// Node parent = node.getParent();\r
-// if (parent != null) {\r
-// tree.setChecked(parent, checkStateProvider.isChecked(parent));\r
-// tree.setGrayed(parent, checkStateProvider.isGrayed(parent));\r
-// }\r
- }\r
-\r
- refreshAndExpandTree();\r
- validatePage();\r
- }\r
- });\r
-\r
- tree.setContentProvider(new ITreeContentProvider(){\r
- @Override\r
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {\r
- }\r
- @Override\r
- public void dispose() {\r
- }\r
- @Override\r
- public Object[] getElements(Object inputElement) {\r
- return exportModel.nodes.roots.toArray();\r
- }\r
- @Override\r
- public boolean hasChildren(Object element) {\r
- Node n = (Node) element;\r
- if (n.getChildren().isEmpty()) return false;\r
- for (Node c : n.getChildren()) if (hasDiagram(c)) return true; \r
- return false;\r
- \r
- }\r
- @Override\r
- public Object getParent(Object element) {\r
- Node n = (Node) element;\r
- return n.getParent();\r
- }\r
- @Override\r
- public Object[] getChildren(Object parentElement) {\r
- Node n = (Node) parentElement;\r
- List<Object> result = new ArrayList<Object>( n.getChildren().size() );\r
- for (Node c : n.getChildren()) \r
- if (hasDiagram(c)) \r
- result.add(c);\r
- return result.toArray();\r
- }\r
- \r
- boolean hasDiagram(Node n)\r
- { \r
- if (n.getDiagramResource()!=null) return true;\r
- for (Node c : n.getChildren()) if (hasDiagram(c)) return true;\r
- return false;\r
- }\r
- });\r
- tree.setLabelProvider(new CellLabelProvider() {\r
- @Override\r
- public void update(ViewerCell cell) {\r
- Object e = cell.getElement();\r
- if (e instanceof Node) {\r
- Node n = (Node) e;\r
- String name = DiagramPrinter.formDiagramName(n, false);\r
- cell.setText(name);\r
-\r
- if (n.getDiagramResource() == null)\r
- cell.setForeground(noDiagramColor);\r
- else\r
- cell.setForeground(null);\r
- } else {\r
- cell.setText("invalid input: " + e.getClass().getSimpleName());\r
- }\r
- }\r
- });\r
- tree.setComparator(new ViewerComparator(AlphanumComparator.CASE_INSENSITIVE_COMPARATOR));\r
- tree.setFilters(new ViewerFilter[] {\r
- new ViewerFilter() {\r
- @Override\r
- public boolean select(Viewer viewer, Object parentElement, Object element) {\r
- if (matcher == null)\r
- return true;\r
-\r
- Node node = (Node) element;\r
- // If any children are in sight, show this element.\r
- for (Node child : node.getChildren()) {\r
- if (select(viewer, element, child))\r
- return true;\r
- }\r
-\r
- return matcher.reset(node.getName().toLowerCase()).matches();\r
- }\r
- }\r
- });\r
- tree.setCheckStateProvider(checkStateProvider);\r
- }\r
-\r
- Composite bar = new Composite(container, SWT.NONE);\r
- GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo(bar);\r
- bar.setLayout(new RowLayout());\r
- Button selectAll = new Button(bar, SWT.PUSH);\r
- selectAll.setText("Select &All");\r
- selectAll.addSelectionListener(new SelectionAdapter() {\r
- @Override\r
- public void widgetSelected(SelectionEvent e) {\r
- selectedNodes.addAll(exportModel.nodes.breadthFirstFlatten());\r
- for (Node root : exportModel.nodes.roots)\r
- tree.setSubtreeChecked(root, true);\r
- validatePage();\r
- }\r
- });\r
- Button clearSelection = new Button(bar, SWT.PUSH);\r
- clearSelection.setText("&Clear Selection");\r
- clearSelection.addSelectionListener(new SelectionAdapter() {\r
- @Override\r
- public void widgetSelected(SelectionEvent e) {\r
- selectedNodes.clear();\r
- for (Node root : exportModel.nodes.roots)\r
- tree.setSubtreeChecked(root, false);\r
- validatePage();\r
- }\r
- });\r
- Button selectVisible = new Button(bar, SWT.PUSH);\r
- selectVisible.setText("&Select Visible");\r
- selectVisible.addSelectionListener(new SelectionAdapter() {\r
- @Override\r
- public void widgetSelected(SelectionEvent e) {\r
- selectedNodes.addAll(getVisibleNodes());\r
- refreshAndExpandTree();\r
- validatePage();\r
- }\r
- });\r
- Button deselectVisible = new Button(bar, SWT.PUSH);\r
- deselectVisible.setText("&Deselect Visible");\r
- deselectVisible.addSelectionListener(new SelectionAdapter() {\r
- @Override\r
- public void widgetSelected(SelectionEvent e) {\r
- selectedNodes.removeAll(getVisibleNodes());\r
- refreshAndExpandTree();\r
- validatePage();\r
- }\r
- });\r
-\r
- toFileLabel = new Label(container, SWT.NONE);\r
- toFileLabel.setText("&To file:");\r
- exportLocation = new CCombo(container, SWT.BORDER);\r
- {\r
- exportLocation.setText("");\r
- GridDataFactory.fillDefaults().grab(true, false).span(1, 1).applyTo(exportLocation);\r
-\r
- for (String path : exportModel.recentLocations) {\r
- exportLocation.add(path);\r
- }\r
-\r
- exportLocationListener = new ModifyListener() {\r
- @Override\r
- public void modifyText(ModifyEvent e) {\r
- //System.out.println("export location changed by user");\r
- exportLocationTouchedByUser = true;\r
- validatePage();\r
- }\r
- };\r
- exportLocation.addModifyListener(exportLocationListener);\r
- }\r
- Button browseFileButton = new Button(container, SWT.PUSH);\r
- {\r
- browseFileButton.setText("Browse...");\r
- browseFileButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));\r
- browseFileButton.addSelectionListener(new SelectionAdapter() {\r
- @Override\r
- public void widgetSelected(SelectionEvent e) {\r
- FileDialog dialog = new FileDialog(getShell(), SWT.SAVE);\r
- dialog.setFilterExtensions(new String[] { "*.pdf" });\r
- dialog.setFilterNames(new String[] { "PDF Document" });\r
- String loc = exportLocation.getText();\r
- if (loc != null) {\r
- IPath p = new Path(loc);\r
- File f = p.toFile();\r
- if (f.isDirectory()) {\r
- dialog.setFilterPath(f.toString());\r
- } else if (f.isFile()) {\r
- IPath path = p.removeLastSegments(1);\r
- String name = p.lastSegment();\r
- dialog.setFilterPath(path.toOSString());\r
- dialog.setFileName(name);\r
- } else {\r
- dialog.setFilterPath(f.toString());\r
- IPath path = p.removeLastSegments(1);\r
- String name = p.lastSegment();\r
- f = path.toFile();\r
- if (f.isDirectory()) {\r
- dialog.setFilterPath(path.toOSString());\r
- }\r
- dialog.setFileName(name);\r
- }\r
- }\r
- String file = dialog.open();\r
- if (file == null)\r
- return;\r
- exportLocation.setText(file);\r
- validatePage();\r
- }\r
- });\r
- }\r
-\r
- final Button zoomToFitButton = new Button(container, SWT.CHECK);\r
- GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo(zoomToFitButton);\r
- zoomToFitButton.setText("F&it by content");\r
- zoomToFitButton.setSelection(exportModel.fitContentToPageMargins);\r
- zoomToFitButton.addSelectionListener(new SelectionAdapter() {\r
- @Override\r
- public void widgetSelected(SelectionEvent e) {\r
- exportModel.fitContentToPageMargins = zoomToFitButton.getSelection();\r
- }\r
- });\r
-\r
- /*\r
- final Button attachTGButton = new Button(container, SWT.CHECK);\r
- GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo( attachTGButton );\r
- attachTGButton.setText("Attach &TG (Importable diagram)");\r
- attachTGButton.setSelection(exportModel.attachTG);\r
- attachTGButton.addSelectionListener(new SelectionAdapter() {\r
- @Override\r
- public void widgetSelected(SelectionEvent e) {\r
- exportModel.attachTG = attachTGButton.getSelection();\r
- }\r
- });\r
- */\r
- \r
- final Button attachWikiButton = new Button(container, SWT.CHECK);\r
- GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo( attachWikiButton );\r
- attachWikiButton.setText("Attach &Wiki page");\r
- attachWikiButton.setSelection(exportModel.attachWiki);\r
- attachWikiButton.addSelectionListener(new SelectionAdapter() {\r
- @Override\r
- public void widgetSelected(SelectionEvent e) {\r
- exportModel.attachWiki = attachWikiButton.getSelection();\r
- }\r
- });\r
- \r
- setControl(container);\r
- validatePage();\r
-\r
- scheduleInitializeData(exportModel.selection);\r
- }\r
-\r
- private void scheduleInitializeData(final NamedResource modelSelection) {\r
- display.asyncExec(new Runnable() {\r
- @Override\r
- public void run() {\r
- if (filter.isDisposed())\r
- return;\r
-\r
- try {\r
- initializeData(modelSelection);\r
- } catch (DatabaseException e) {\r
- e.printStackTrace();\r
- } catch (InvocationTargetException e) {\r
- e.getTargetException().printStackTrace();\r
- } catch (InterruptedException e) {\r
- e.printStackTrace();\r
- }\r
- }\r
- });\r
- }\r
-\r
- private NamedResource getSelectedModel() {\r
- int sel = modelSelector.getSelectionIndex();\r
- if (sel != -1) {\r
- NamedResource nr = (NamedResource) modelSelector.getData("" + sel);\r
- return nr;\r
- }\r
- return null;\r
- }\r
-\r
- private void setExportLocationWithoutNotification(String text) {\r
- exportLocation.removeModifyListener(exportLocationListener);\r
- exportLocation.setText(text);\r
- exportLocation.addModifyListener(exportLocationListener);\r
- }\r
-\r
- private Collection<Node> getVisibleNodes() {\r
- Collection<Node> result = new ArrayList<Node>();\r
-\r
- Deque<TreeItem> todo = new ArrayDeque<TreeItem>();\r
- for (TreeItem ti : tree.getTree().getItems()) {\r
- todo.add(ti);\r
- }\r
-\r
- while (!todo.isEmpty()) {\r
- TreeItem item = todo.removeLast();\r
- Node node = (Node) item.getData();\r
- result.add(node);\r
-\r
- for (TreeItem child : item.getItems()) {\r
- todo.add(child);\r
- }\r
- }\r
-\r
- return result;\r
- }\r
-\r
- private void resetFilterString(String filterString) {\r
- String patternString = filterStrategy.toPatternString(filterString);\r
- if (patternString == null) {\r
- matcher = null;\r
- } else {\r
- matcher = Pattern.compile(patternString).matcher("");\r
- }\r
- refreshAndExpandTree();\r
- }\r
-\r
- private void refreshAndExpandTree() {\r
- tree.refresh();\r
- tree.expandAll();\r
- }\r
-\r
- private void initializeData(final NamedResource modelSelection) throws DatabaseException, InvocationTargetException, InterruptedException {\r
- if (modelSelection != null) {\r
- // Process input selection to find the model/state selected by default.\r
-\r
- // This may take longer than the user wants to wait without\r
- // notification.\r
-\r
- // !PROFILE\r
- long time = System.nanoTime();\r
-\r
- getWizard().getContainer().run(true, true, new IRunnableWithProgress() {\r
- @Override\r
- public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {\r
- try {\r
- final SubMonitor mon = SubMonitor.convert(monitor, "Searching for exportable diagrams...", 100);\r
- exportModel.sessionContext.getSession().syncRequest(new ReadRequest() {\r
- @Override\r
- public void run(ReadGraph graph) throws DatabaseException {\r
- exportModel.nodes = DiagramPrinter.browse(mon.newChild(100), graph, new Resource[] { modelSelection.getResource() });\r
- }\r
- });\r
- } catch (DatabaseException e) {\r
- throw new InvocationTargetException(e);\r
- } finally {\r
- monitor.done();\r
- }\r
- }\r
- });\r
-\r
- // !PROFILE\r
- long endTime = System.nanoTime();\r
- if (exportModel.nodes != null)\r
- System.out.println("Found " + exportModel.nodes.diagrams.size() + " diagrams in " + ((endTime - time)*1e-9) + " seconds.");\r
- }\r
-\r
- // Browsing was canceled by user.\r
- if (exportModel.nodes == null)\r
- return;\r
-\r
- // Setup selected states, select everything by default.\r
- selectedNodes.clear();\r
- selectedNodes.addAll(exportModel.nodes.breadthFirstFlatten());\r
-\r
- tree.setInput(this);\r
-\r
- for (Node root : exportModel.nodes.roots) {\r
- tree.setSubtreeChecked(root, true);\r
- }\r
-\r
- resetFilterString(filter.getText());\r
-\r
- modelSelector.removeSelectionListener(modelSelectorListener);\r
- int selectedIndex = -1;\r
- for (int i = 0; i < modelSelector.getItemCount(); ++i) {\r
- Object obj = modelSelector.getData("" + i);\r
- if (org.simantics.utils.ObjectUtils.objectEquals(obj, modelSelection)) {\r
- selectedIndex = i;\r
- }\r
- }\r
- if (selectedIndex == -1 && modelSelector.getItemCount() > 0)\r
- selectedIndex = 0;\r
- if (selectedIndex != -1)\r
- modelSelector.select(selectedIndex);\r
- modelSelector.addSelectionListener(modelSelectorListener);\r
-\r
- validatePage();\r
- }\r
-\r
- void validatePage() {\r
- //System.out.println("VALIDATE PAGE: " + exportLocationTouchedByUser);\r
- if (selectedNodes.size() == 0) {\r
- setMessage("Select the diagrams to export.");\r
- setErrorMessage(null);\r
- setPageComplete(false);\r
- return;\r
- }\r
-\r
- if (!exportLocationTouchedByUser) {\r
- String generatedName = null;\r
- // Generate file name automatically if user hasn't touched the name manually.\r
- NamedResource nr = getSelectedModel();\r
- if (nr != null) {\r
- if (selectedNodes.size() == 1) {\r
- generatedName = nr.getName() + "-" + selectedNodes.iterator().next().getName();\r
- } else {\r
- generatedName = nr.getName();\r
- }\r
- }\r
- //System.out.println("generate name: " + generatedName);\r
- if (generatedName != null) {\r
- if (!FileUtils.isValidFileName(generatedName))\r
- generatedName = (String) Bindings.STR_VARIANT.createUnchecked(Bindings.STRING, generatedName);\r
- String name = generatedName + ".pdf";\r
- \r
- abu:\r
- if ( !exportModel.recentLocations.isEmpty() ) {\r
- \r
- for ( String loc : exportModel.recentLocations )\r
- {\r
- if ( loc.endsWith(name) && !loc.equals(name) ) {\r
- name = loc;\r
- break abu; \r
- }\r
- }\r
- \r
- String firstLine = exportModel.recentLocations.iterator().next();\r
- File f = new File(firstLine); \r
- File parentFile = f.getParentFile();\r
- if ( parentFile!=null ) {\r
- name = new File( f.getParentFile(), name ).getAbsolutePath();\r
- }\r
- }\r
- setExportLocationWithoutNotification(name);\r
- }\r
- }\r
-\r
- String exportLoc = exportLocation.getText();\r
- if (exportLoc.isEmpty()) {\r
- setMessage("Select an export target file.");\r
- setErrorMessage(null);\r
- setPageComplete(false);\r
- return;\r
- }\r
- File file = new File(exportLoc);\r
- if (file.exists()) {\r
- if (file.isDirectory()) {\r
- setErrorMessage("The target already exists and it is a directory.");\r
- setPageComplete(false);\r
- return;\r
- }\r
- if (!file.isFile()) {\r
- setErrorMessage("The target already exists and it is a not a regular file.");\r
- setPageComplete(false);\r
- return;\r
- }\r
- }\r
- exportModel.exportLocation = file;\r
-\r
- int diagramCount = 0;\r
- for (Node n : selectedNodes)\r
- if (n.getDiagramResource() != null)\r
- ++diagramCount;\r
-\r
- String msg = diagramCount + " diagrams selected for export.";\r
-\r
- setMessage(msg);\r
- setErrorMessage(null);\r
- setPageComplete(true);\r
- }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2017 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
+ * Semantum Oy - #7297
+ *******************************************************************************/
+package org.simantics.modeling.ui.pdf;
+
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CCombo;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.simantics.databoard.Bindings;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.common.NamedResource;
+import org.simantics.db.common.request.ReadRequest;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.modeling.requests.CollectionResult;
+import org.simantics.modeling.requests.Node;
+import org.simantics.modeling.requests.Nodes;
+import org.simantics.ui.utils.ResourceAdaptionUtils;
+import org.simantics.utils.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PDFExportPage extends WizardPage {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(PDFExportPage.class);
+
+ protected Display display;
+
+ protected PDFExportPlan exportModel;
+
+ protected Combo modelSelector;
+ protected SelectionListener modelSelectorListener;
+
+ protected NodeTree nodeTree;
+
+ protected CCombo exportLocation;
+ protected ModifyListener exportLocationListener;
+
+ protected Set<Node> selectedNodes;
+
+ protected Label toFileLabel;
+
+ protected boolean exportLocationTouchedByUser = false;
+
+ protected PDFExportPage(PDFExportPlan model) {
+ super("Export Diagrams to PDF", "Define Exported Items", null);
+ this.exportModel = model;
+ this.selectedNodes = exportModel.selectedNodeSet;
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ this.display = parent.getDisplay();
+
+ Composite container = new Composite(parent, SWT.NONE);
+ {
+ GridLayout layout = new GridLayout();
+ layout.horizontalSpacing = 20;
+ layout.verticalSpacing = 10;
+ layout.numColumns = 3;
+ container.setLayout(layout);
+ }
+
+ Label modelSelectorLabel = new Label(container, SWT.NONE);
+ modelSelectorLabel.setText("Model Selector:");
+ GridDataFactory.fillDefaults().span(1, 1).applyTo(modelSelectorLabel);
+ modelSelector = new Combo(container, SWT.BORDER | SWT.READ_ONLY);
+ GridDataFactory.fillDefaults().span(2, 1).applyTo(modelSelector);
+ modelSelectorListener = new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ NamedResource data = (NamedResource) modelSelector.getData(String.valueOf(modelSelector.getSelectionIndex()));
+ scheduleInitializeData(data);
+ }
+ };
+
+ // Fill model selector combo
+ for (int i = 0; i < exportModel.selectableModels.size(); ++i) {
+ NamedResource nr = exportModel.selectableModels.get(i);
+ modelSelector.add(nr.getName());
+ modelSelector.setData("" + i, nr);
+ }
+
+ modelSelector.addSelectionListener(modelSelectorListener);
+
+ nodeTree = new NodeTree(container, selectedNodes);
+ GridDataFactory.fillDefaults().grab(true, true).span(3, 1).applyTo(nodeTree);
+ nodeTree.setSelectionChangeListener(this::validatePage);
+
+ toFileLabel = new Label(container, SWT.NONE);
+ toFileLabel.setText("&To file:");
+ exportLocation = new CCombo(container, SWT.BORDER);
+ {
+ exportLocation.setText("");
+ GridDataFactory.fillDefaults().grab(true, false).span(1, 1).applyTo(exportLocation);
+
+ for (String path : exportModel.recentLocations) {
+ exportLocation.add(path);
+ }
+
+ exportLocationListener = new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ //System.out.println("export location changed by user");
+ exportLocationTouchedByUser = true;
+ validatePage();
+ }
+ };
+ exportLocation.addModifyListener(exportLocationListener);
+ }
+ Button browseFileButton = new Button(container, SWT.PUSH);
+ {
+ browseFileButton.setText("Browse...");
+ browseFileButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+ browseFileButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ FileDialog dialog = new FileDialog(getShell(), SWT.SAVE);
+ dialog.setFilterExtensions(new String[] { "*.pdf" });
+ dialog.setFilterNames(new String[] { "PDF Document" });
+ String loc = exportLocation.getText();
+ if (loc != null) {
+ IPath p = new Path(loc);
+ File f = p.toFile();
+ if (f.isDirectory()) {
+ dialog.setFilterPath(f.toString());
+ } else if (f.isFile()) {
+ IPath path = p.removeLastSegments(1);
+ String name = p.lastSegment();
+ dialog.setFilterPath(path.toOSString());
+ dialog.setFileName(name);
+ } else {
+ dialog.setFilterPath(f.toString());
+ IPath path = p.removeLastSegments(1);
+ String name = p.lastSegment();
+ f = path.toFile();
+ if (f.isDirectory()) {
+ dialog.setFilterPath(path.toOSString());
+ }
+ dialog.setFileName(name);
+ }
+ }
+ String file = dialog.open();
+ if (file == null)
+ return;
+ exportLocation.setText(file);
+ validatePage();
+ }
+ });
+ }
+
+ final Button zoomToFitButton = new Button(container, SWT.CHECK);
+ GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo(zoomToFitButton);
+ zoomToFitButton.setText("F&it by content");
+ zoomToFitButton.setSelection(exportModel.fitContentToPageMargins);
+ zoomToFitButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ exportModel.fitContentToPageMargins = zoomToFitButton.getSelection();
+ }
+ });
+
+ /*
+ final Button attachTGButton = new Button(container, SWT.CHECK);
+ GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo( attachTGButton );
+ attachTGButton.setText("Attach &TG (Importable diagram)");
+ attachTGButton.setSelection(exportModel.attachTG);
+ attachTGButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ exportModel.attachTG = attachTGButton.getSelection();
+ }
+ });
+ */
+
+ final Button attachWikiButton = new Button(container, SWT.CHECK);
+ GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo( attachWikiButton );
+ attachWikiButton.setText("Attach &Wiki page");
+ attachWikiButton.setSelection(exportModel.attachWiki);
+ attachWikiButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ exportModel.attachWiki = attachWikiButton.getSelection();
+ }
+ });
+
+ final Button addPageNumbers = new Button(container, SWT.CHECK);
+ GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo( addPageNumbers );
+ addPageNumbers.setText("Add page &numbers");
+ addPageNumbers.setSelection(exportModel.addPageNumbers);
+ addPageNumbers.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ exportModel.addPageNumbers = addPageNumbers.getSelection();
+ }
+ });
+
+ setControl(container);
+ validatePage();
+
+ scheduleInitializeData(exportModel.selection);
+ }
+
+ private void scheduleInitializeData(final NamedResource modelSelection) {
+ display.asyncExec(() -> {
+ try {
+ if (!nodeTree.isDisposed())
+ initializeData(modelSelection);
+ } catch (DatabaseException | InterruptedException e) {
+ LOGGER.error("Input data initialization failed.", e);
+ } catch (InvocationTargetException e) {
+ LOGGER.error("Input data initialization failed.", e.getTargetException());
+ }
+ });
+ }
+
+ private NamedResource getSelectedModel() {
+ int sel = modelSelector.getSelectionIndex();
+ if (sel != -1) {
+ NamedResource nr = (NamedResource) modelSelector.getData("" + sel);
+ return nr;
+ }
+ return null;
+ }
+
+ private void setExportLocationWithoutNotification(String text) {
+ exportLocation.removeModifyListener(exportLocationListener);
+ exportLocation.setText(text);
+ exportLocation.addModifyListener(exportLocationListener);
+ }
+
+ private void initializeData(final NamedResource modelSelection) throws DatabaseException, InvocationTargetException, InterruptedException {
+ Set<Node> toBeSelected = new HashSet<>();
+
+ if (modelSelection != null) {
+ // Process input selection to find the model/state selected by default.
+
+ // This may take longer than the user wants to wait without
+ // notification.
+
+ // !PROFILE
+ long time = System.nanoTime();
+
+ getWizard().getContainer().run(true, true, monitor -> {
+ try {
+ SubMonitor mon = SubMonitor.convert(monitor, "Searching for exportable diagrams...", 100);
+ exportModel.sessionContext.getSession().syncRequest(new ReadRequest() {
+ @Override
+ public void run(ReadGraph graph) throws DatabaseException {
+ CollectionResult coll = exportModel.nodes = DiagramPrinter.browse(mon.newChild(100), graph, new Resource[] { modelSelection.getResource() });
+
+ // Decide initial selection based on exportModel.initialSelection
+ if (modelSelection.equals(exportModel.initialModelSelection)) {
+ Set<Resource> selectedResources = new HashSet<>();
+ for (Object o : exportModel.initialSelection.toList()) {
+ Resource r = ResourceAdaptionUtils.toSingleResource(o);
+ if (r != null)
+ selectedResources.add(r);
+ }
+ coll.walkTree(node -> {
+ if (node.getDiagramResource() != null) {
+ if (Nodes.parentIsInSet(toBeSelected, node))
+ toBeSelected.add(node);
+ else
+ for (Resource r : node.getDefiningResources())
+ if (selectedResources.contains(r))
+ toBeSelected.add(node);
+ }
+ return true;
+ });
+ }
+
+ // Filter out any excess nodes from the tree.
+ exportModel.nodes = coll = coll.withRoots(Nodes.depthFirstFilter(Nodes.DIAGRAM_RESOURCE_PREDICATE, coll.roots));
+
+ // Select all if initial selection doesn't dictate anything.
+ if (toBeSelected.isEmpty())
+ toBeSelected.addAll(coll.breadthFirstFlatten(CollectionResult.DIAGRAM_RESOURCE_FILTER));
+ }
+ });
+ } catch (DatabaseException e) {
+ throw new InvocationTargetException(e);
+ } finally {
+ monitor.done();
+ }
+ });
+
+ // !PROFILE
+ long endTime = System.nanoTime();
+ if (exportModel.nodes != null)
+ LOGGER.info("Found " + exportModel.nodes.diagrams.size() + " diagrams in " + ((endTime - time)*1e-9) + " seconds.");
+ }
+
+ // Browsing was canceled by user.
+ if (exportModel.nodes == null)
+ return;
+
+ // Setup selected states, select everything by default.
+ selectedNodes.clear();
+ selectedNodes.addAll(toBeSelected);
+
+ // Fully refresh node tree
+ nodeTree.setInput(exportModel.nodes);
+
+ modelSelector.removeSelectionListener(modelSelectorListener);
+ int selectedIndex = -1;
+ for (int i = 0; i < modelSelector.getItemCount(); ++i) {
+ Object obj = modelSelector.getData("" + i);
+ if (org.simantics.utils.ObjectUtils.objectEquals(obj, modelSelection)) {
+ selectedIndex = i;
+ }
+ }
+ if (selectedIndex == -1 && modelSelector.getItemCount() > 0)
+ selectedIndex = 0;
+ if (selectedIndex != -1)
+ modelSelector.select(selectedIndex);
+ modelSelector.addSelectionListener(modelSelectorListener);
+
+ validatePage();
+ }
+
+ void validatePage() {
+ int diagramCount = 0;
+ Node singleDiagram = null;
+ for (Node n : selectedNodes)
+ if (n.getDiagramResource() != null) {
+ ++diagramCount;
+ singleDiagram = n;
+ }
+
+ //System.out.println("VALIDATE PAGE: " + exportLocationTouchedByUser);
+ if (diagramCount == 0) {
+ setMessage("Select the diagrams to export.");
+ setErrorMessage(null);
+ setPageComplete(false);
+ return;
+ }
+
+ if (!exportLocationTouchedByUser) {
+ String generatedName = null;
+ // Generate file name automatically if user hasn't touched the name manually.
+ NamedResource nr = getSelectedModel();
+ if (nr != null) {
+ if (diagramCount == 1 && singleDiagram != null) {
+ generatedName = nr.getName() + "-" + singleDiagram.getName();
+ } else {
+ generatedName = nr.getName();
+ }
+ }
+ //System.out.println("generate name: " + generatedName);
+ if (generatedName != null) {
+ if (!FileUtils.isValidFileName(generatedName))
+ generatedName = (String) Bindings.STR_VARIANT.createUnchecked(Bindings.STRING, generatedName);
+ String name = generatedName + ".pdf";
+
+ abu:
+ if ( !exportModel.recentLocations.isEmpty() ) {
+
+ for ( String loc : exportModel.recentLocations )
+ {
+ if ( loc.endsWith(name) && !loc.equals(name) ) {
+ name = loc;
+ break abu;
+ }
+ }
+
+ String firstLine = exportModel.recentLocations.iterator().next();
+ File f = new File(firstLine);
+ File parentFile = f.getParentFile();
+ if ( parentFile!=null ) {
+ name = new File( f.getParentFile(), name ).getAbsolutePath();
+ }
+ }
+ setExportLocationWithoutNotification(name);
+ }
+ }
+
+ String exportLoc = exportLocation.getText();
+ if (exportLoc.isEmpty()) {
+ setMessage("Select an export target file.");
+ setErrorMessage(null);
+ setPageComplete(false);
+ return;
+ }
+ File file = new File(exportLoc);
+ if (file.exists()) {
+ if (file.isDirectory()) {
+ setErrorMessage("The target already exists and it is a directory.");
+ setPageComplete(false);
+ return;
+ }
+ if (!file.isFile()) {
+ setErrorMessage("The target already exists and it is a not a regular file.");
+ setPageComplete(false);
+ return;
+ }
+ }
+ exportModel.exportLocation = file;
+
+ String msg = diagramCount + " diagrams selected for export.";
+
+ setMessage(msg);
+ setErrorMessage(null);
+ setPageComplete(true);
+ }
+
+}