]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFExportPage.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / pdf / PDFExportPage.java
index 8920decfed1b11f768f3efc259c79c7107c1b221..7ef2efb9406f283b578f6bfdcabc7669d91e997a 100644 (file)
-/*******************************************************************************\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&lter:");\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, 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.pdf;
+
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.viewers.CellLabelProvider;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTreeViewer;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.ICheckStateProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CCombo;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+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.graphics.Color;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+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.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.TreeItem;
+import org.simantics.browsing.ui.common.views.DefaultFilterStrategy;
+import org.simantics.browsing.ui.common.views.IFilterStrategy;
+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.Node;
+import org.simantics.utils.FileUtils;
+import org.simantics.utils.strings.AlphanumComparator;
+import org.simantics.utils.ui.ISelectionUtils;
+
+public class PDFExportPage extends WizardPage {
+
+       protected Display              display;
+
+    protected PDFExportPlan       exportModel;
+
+    protected IFilterStrategy      filterStrategy     = new DefaultFilterStrategy();
+
+    protected Combo                modelSelector;
+    protected SelectionListener    modelSelectorListener;
+
+    protected Text                 filter;
+
+    protected Matcher              matcher            = null;
+
+    protected CheckboxTreeViewer   tree;
+
+    protected CCombo               exportLocation;
+    protected ModifyListener       exportLocationListener;
+
+    protected Set<Node>            selectedNodes;
+
+    protected LocalResourceManager resourceManager;
+    protected Color                noDiagramColor;
+    
+    protected Label                               toFileLabel;
+
+    protected boolean              exportLocationTouchedByUser = false;
+
+    ICheckStateProvider checkStateProvider = new ICheckStateProvider() {
+        @Override
+        public boolean isChecked(Object element) {
+            Node node = (Node) element;
+
+            // Primarily checked if any children are selected.
+            Collection<Node> children = node.getChildren();
+            if (!children.isEmpty()) {
+                for (Node child : node.getChildren())
+                    if (isChecked(child))
+                        return true;
+
+                // No children are checked, not checked.
+                return false;
+            }
+
+            // Otherwise checked only if selected.
+            return selectedNodes.contains(node);
+        }
+        @Override
+        public boolean isGrayed(Object element) {
+            Node node = (Node) element;
+
+            // Grayed if there are children but not all of them are selected.
+            Collection<Node> children = node.getChildren();
+            if (!children.isEmpty()) {
+                for (Node child : children)
+                    if (!selectedNodes.contains(child))
+                        return true;
+            }
+
+            // Grayed if the node itself contains no diagram.
+            if (node.getDiagramResource() == null)
+                return true;
+
+            // Otherwise never grayed.
+            return 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);
+        }
+        resourceManager = new LocalResourceManager(JFaceResources.getResources());
+        container.addDisposeListener(new DisposeListener() {
+            @Override
+            public void widgetDisposed(DisposeEvent e) {
+                resourceManager.dispose();
+            }
+        });
+        noDiagramColor = container.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY);
+
+        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);
+
+//        Label label = new Label(container, SWT.NONE);
+//        label.setText("Diagrams to Export:");
+//        GridDataFactory.fillDefaults().span(3, 1).applyTo(label);
+
+        Label filterLabel = new Label(container, SWT.NONE);
+        filterLabel.setText("Fi&lter:");
+        GridDataFactory.fillDefaults().span(1, 1).applyTo(filterLabel);
+        filter = new Text(container, SWT.BORDER);
+        GridDataFactory.fillDefaults().span(2, 1).applyTo(filter);
+        filter.addModifyListener(new ModifyListener() {
+            @Override
+            public void modifyText(ModifyEvent e) {
+                resetFilterString(filter.getText());
+            }
+        });
+
+        tree = new CheckboxTreeViewer(container, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION);
+        {
+            tree.setUseHashlookup(true);
+            GridDataFactory.fillDefaults().grab(true, true).span(3, 1).applyTo(tree.getControl());
+            tree.getControl().setToolTipText("Selects the diagram to include in the exported document.");
+            tree.setAutoExpandLevel(TreeViewer.ALL_LEVELS);
+            tree.addCheckStateListener(new ICheckStateListener(){
+                void addOrRemoveSelection(Node node, boolean add) {
+                    if (add)
+                        selectedNodes.add(node);
+                    else
+                        selectedNodes.remove(node);
+                }
+                void addOrRemoveSelectionRec(Node node, boolean add) {
+                    addOrRemoveSelection(node, add);
+                    for (Node child : node.getChildren())
+                        addOrRemoveSelectionRec(child, add);
+                }
+                @Override
+                public void checkStateChanged(CheckStateChangedEvent event) {
+                    final boolean checked = event.getChecked();
+                    Node checkedNode = (Node) event.getElement();
+
+                    Set<Node> nodes = new HashSet<Node>();
+                    Set<Node> selection = ISelectionUtils.filterSetSelection(tree.getSelection(), Node.class);
+                    if (selection.contains(checkedNode))
+                        nodes.addAll(selection);
+                    else
+                        tree.setSelection(StructuredSelection.EMPTY);
+                    nodes.add(checkedNode);
+
+                    for (Node node : nodes) {
+                        addOrRemoveSelectionRec(node, checked);
+
+//                        tree.setSubtreeChecked(node, checked);
+//                         The checked node is always either checked or not checked, never grayed.
+//                        tree.setGrayed(node, checkStateProvider.isGrayed(node));
+
+//                        Node parent = node.getParent();
+//                        if (parent != null) {
+//                            tree.setChecked(parent, checkStateProvider.isChecked(parent));
+//                            tree.setGrayed(parent, checkStateProvider.isGrayed(parent));
+//                        }
+                    }
+
+                    refreshAndExpandTree();
+                    validatePage();
+                }
+            });
+
+            tree.setContentProvider(new ITreeContentProvider(){
+                @Override
+                public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+                }
+                @Override
+                public void dispose() {
+                }
+                @Override
+                public Object[] getElements(Object inputElement) {
+                    return exportModel.nodes.roots.toArray();
+                }
+                @Override
+                public boolean hasChildren(Object element) {
+                    Node n = (Node) element;
+                    if (n.getChildren().isEmpty()) return false;
+                       for (Node c : n.getChildren()) if (hasDiagram(c)) return true; 
+                    return false;
+                    
+                }
+                @Override
+                public Object getParent(Object element) {
+                    Node n = (Node) element;
+                    return n.getParent();
+                }
+                @Override
+                public Object[] getChildren(Object parentElement) {
+                    Node n = (Node) parentElement;
+                       List<Object> result = new ArrayList<Object>( n.getChildren().size() );
+                       for (Node c : n.getChildren()) 
+                               if (hasDiagram(c)) 
+                                       result.add(c);
+                    return result.toArray();
+                }
+                
+                boolean hasDiagram(Node n)
+                {                      
+                       if (n.getDiagramResource()!=null) return true;
+                       for (Node c : n.getChildren()) if (hasDiagram(c)) return true;
+                       return false;
+                }
+            });
+            tree.setLabelProvider(new CellLabelProvider() {
+                @Override
+                public void update(ViewerCell cell) {
+                    Object e = cell.getElement();
+                    if (e instanceof Node) {
+                        Node n = (Node) e;
+                        String name = DiagramPrinter.formDiagramName(n, false);
+                        cell.setText(name);
+
+                        if (n.getDiagramResource() == null)
+                            cell.setForeground(noDiagramColor);
+                        else
+                            cell.setForeground(null);
+                    } else {
+                        cell.setText("invalid input: " + e.getClass().getSimpleName());
+                    }
+                }
+            });
+            tree.setComparator(new ViewerComparator(AlphanumComparator.CASE_INSENSITIVE_COMPARATOR));
+            tree.setFilters(new ViewerFilter[] {
+                    new ViewerFilter() {
+                        @Override
+                        public boolean select(Viewer viewer, Object parentElement, Object element) {
+                            if (matcher == null)
+                                return true;
+
+                            Node node = (Node) element;
+                            // If any children are in sight, show this element.
+                            for (Node child : node.getChildren()) {
+                                if (select(viewer, element, child))
+                                    return true;
+                            }
+
+                            return matcher.reset(node.getName().toLowerCase()).matches();
+                        }
+                    }
+            });
+            tree.setCheckStateProvider(checkStateProvider);
+        }
+
+        Composite bar = new Composite(container, SWT.NONE);
+        GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo(bar);
+        bar.setLayout(new RowLayout());
+        Button selectAll = new Button(bar, SWT.PUSH);
+        selectAll.setText("Select &All");
+        selectAll.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                selectedNodes.addAll(exportModel.nodes.breadthFirstFlatten());
+                for (Node root : exportModel.nodes.roots)
+                    tree.setSubtreeChecked(root, true);
+                validatePage();
+            }
+        });
+        Button clearSelection = new Button(bar, SWT.PUSH);
+        clearSelection.setText("&Clear Selection");
+        clearSelection.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                selectedNodes.clear();
+                for (Node root : exportModel.nodes.roots)
+                    tree.setSubtreeChecked(root, false);
+                validatePage();
+            }
+        });
+        Button selectVisible = new Button(bar, SWT.PUSH);
+        selectVisible.setText("&Select Visible");
+        selectVisible.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                selectedNodes.addAll(getVisibleNodes());
+                refreshAndExpandTree();
+                validatePage();
+            }
+        });
+        Button deselectVisible = new Button(bar, SWT.PUSH);
+        deselectVisible.setText("&Deselect Visible");
+        deselectVisible.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                selectedNodes.removeAll(getVisibleNodes());
+                refreshAndExpandTree();
+                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();
+            }
+        });
+        
+        setControl(container);
+        validatePage();
+
+        scheduleInitializeData(exportModel.selection);
+    }
+
+    private void scheduleInitializeData(final NamedResource modelSelection) {
+        display.asyncExec(new Runnable() {
+            @Override
+            public void run() {
+                if (filter.isDisposed())
+                    return;
+
+                try {
+                    initializeData(modelSelection);
+                } catch (DatabaseException e) {
+                    e.printStackTrace();
+                } catch (InvocationTargetException e) {
+                    e.getTargetException().printStackTrace();
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+        });
+    }
+
+    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 Collection<Node> getVisibleNodes() {
+        Collection<Node> result = new ArrayList<Node>();
+
+        Deque<TreeItem> todo = new ArrayDeque<TreeItem>();
+        for (TreeItem ti : tree.getTree().getItems()) {
+            todo.add(ti);
+        }
+
+        while (!todo.isEmpty()) {
+            TreeItem item = todo.removeLast();
+            Node node = (Node) item.getData();
+            result.add(node);
+
+            for (TreeItem child : item.getItems()) {
+                todo.add(child);
+            }
+        }
+
+        return result;
+    }
+
+    private void resetFilterString(String filterString) {
+        String patternString = filterStrategy.toPatternString(filterString);
+        if (patternString == null) {
+            matcher = null;
+        } else {
+            matcher = Pattern.compile(patternString).matcher("");
+        }
+        refreshAndExpandTree();
+    }
+
+    private void refreshAndExpandTree() {
+        tree.refresh();
+        tree.expandAll();
+    }
+
+    private void initializeData(final NamedResource modelSelection) throws DatabaseException, InvocationTargetException, InterruptedException {
+        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, new IRunnableWithProgress() {
+                @Override
+                public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+                    try {
+                        final SubMonitor mon = SubMonitor.convert(monitor, "Searching for exportable diagrams...", 100);
+                        exportModel.sessionContext.getSession().syncRequest(new ReadRequest() {
+                            @Override
+                            public void run(ReadGraph graph) throws DatabaseException {
+                                exportModel.nodes = DiagramPrinter.browse(mon.newChild(100), graph, new Resource[] { modelSelection.getResource() });
+                            }
+                        });
+                    } catch (DatabaseException e) {
+                        throw new InvocationTargetException(e);
+                    } finally {
+                        monitor.done();
+                    }
+                }
+            });
+
+            // !PROFILE
+            long endTime = System.nanoTime();
+            if (exportModel.nodes != null)
+                System.out.println("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(exportModel.nodes.breadthFirstFlatten());
+
+        tree.setInput(this);
+
+        for (Node root : exportModel.nodes.roots) {
+            tree.setSubtreeChecked(root, true);
+        }
+
+        resetFilterString(filter.getText());
+
+        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() {
+        //System.out.println("VALIDATE PAGE: " + exportLocationTouchedByUser);
+        if (selectedNodes.size() == 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 (selectedNodes.size() == 1) {
+                    generatedName = nr.getName() + "-" + selectedNodes.iterator().next().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;
+
+        int diagramCount = 0;
+        for (Node n : selectedNodes)
+            if (n.getDiagramResource() != null)
+                ++diagramCount;
+
+        String msg = diagramCount + " diagrams selected for export.";
+
+        setMessage(msg);
+        setErrorMessage(null);
+        setPageComplete(true);
+    }
+
+}