--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 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:
+ * Semantum Oy - #7297
+ *******************************************************************************/
+package org.simantics.modeling.ui.pdf;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+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.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreePath;
+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.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+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.modeling.requests.CollectionResult;
+import org.simantics.modeling.requests.Node;
+import org.simantics.utils.strings.AlphanumComparator;
+import org.simantics.utils.ui.ISelectionUtils;
+
+/**
+ * A tree of nodes intended for usable listing and selecting diagrams.
+ *
+ * @author Tuukka Lehtonen
+ * @since 1.30.0
+ */
+public class NodeTree extends Composite {
+
+ /**
+ * This exists to make {@link NodeCheckStateProvider} faster
+ */
+ private static class CheckStateCache {
+ Map<Node, Boolean> isChecked = new HashMap<>();
+ Map<Node, Boolean> isGrayed = new HashMap<>();
+
+ public void invalidate(Node n) {
+ for (; n != null; n = n.getParent()) {
+ isChecked.remove(n);
+ isGrayed.remove(n);
+ }
+ }
+ public void invalidate() {
+ isChecked.clear();
+ isGrayed.clear();
+ }
+ }
+
+ protected Display display;
+
+ protected LocalResourceManager resourceManager;
+
+ protected Color noDiagramColor;
+
+ protected IFilterStrategy filterStrategy = new DefaultFilterStrategy();
+
+ protected Text filter;
+
+ protected Matcher matcher = null;
+
+ protected CheckboxTreeViewer tree;
+
+ /**
+ * The tree paths that were expanded last time no filter was defined. Will
+ * be nullified after the expanded paths have been returned when
+ * {@link #matcher} turns null.
+ */
+ protected TreePath[] noFilterExpandedPaths;
+
+ protected Set<Node> selectedNodes;
+
+ protected CheckStateCache checkStateCache = new CheckStateCache();
+
+ protected Runnable selectionChangeListener;
+
+ protected CollectionResult nodes;
+
+ public NodeTree(Composite parent, Set<Node> selectedNodes) {
+ super(parent, 0);
+
+ this.display = getDisplay();
+ this.selectedNodes = selectedNodes;
+
+ resourceManager = new LocalResourceManager(JFaceResources.getResources(), this);
+ noDiagramColor = getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY);
+
+ GridLayoutFactory.fillDefaults().spacing(20, 10).numColumns(3).applyTo(this);
+
+ createFilter(this);
+ createTree(this);
+ createButtons(this);
+ }
+
+ public void setSelectionChangeListener(Runnable r) {
+ this.selectionChangeListener = r;
+ }
+
+ public void setInput(CollectionResult nodes) {
+ this.nodes = nodes;
+ tree.setInput(nodes);
+ resetFilterString(filter.getText());
+ }
+
+ private Runnable resetFilter = () -> resetFilterString(filter.getText());
+
+ private void createFilter(Composite parent) {
+ Label filterLabel = new Label(parent, SWT.NONE);
+ filterLabel.setText("Fi<er:");
+ GridDataFactory.fillDefaults().span(1, 1).applyTo(filterLabel);
+ filter = new Text(parent, SWT.BORDER);
+ GridDataFactory.fillDefaults().span(2, 1).applyTo(filter);
+ filter.addModifyListener(e -> display.timerExec(500, resetFilter));
+ }
+
+ private void createTree(Composite parent) {
+ tree = new CheckboxTreeViewer(parent, 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 diagrams to include in the exported document.");
+ tree.setAutoExpandLevel(2);
+ tree.addCheckStateListener(new CheckStateListener());
+ tree.setContentProvider(new NodeTreeContentProvider());
+ tree.setLabelProvider(new NodeLabelProvider());
+ tree.setCheckStateProvider(new NodeCheckStateProvider());
+ tree.setComparator(new ViewerComparator(AlphanumComparator.CASE_INSENSITIVE_COMPARATOR));
+ tree.setFilters(new ViewerFilter[] { new NodeFilter() });
+ }
+
+ private void createButtons(Composite parent) {
+ Composite bar = new Composite(parent, 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.setToolTipText("Select All Visible Diagrams");
+ selectAll.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ selectedNodes.addAll(filter.getText().isEmpty() ? nodes.breadthFirstFlatten(CollectionResult.DIAGRAM_RESOURCE_FILTER) : getVisibleNodes());
+ refreshTree(true);
+ fireChangeListener();
+ scheduleFocusTree();
+ }
+ });
+ Button clearSelection = new Button(bar, SWT.PUSH);
+ clearSelection.setText("&Deselect All");
+ clearSelection.setToolTipText("Deselect All Visible Diagrams");
+ clearSelection.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (filter.getText().isEmpty())
+ selectedNodes.clear();
+ else
+ selectedNodes.removeAll(getVisibleNodes());
+ refreshTree(true);
+ fireChangeListener();
+ scheduleFocusTree();
+ }
+ });
+ Button expand = new Button(bar, SWT.PUSH);
+ expand.setText("&Expand");
+ expand.setToolTipText("Fully Expand Selected Nodes or All Nodes");
+ expand.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ IStructuredSelection ss = tree.getStructuredSelection();
+ if (ss.isEmpty())
+ tree.expandAll();
+ else
+ for (Object n : ss.toList())
+ tree.expandToLevel(n, TreeViewer.ALL_LEVELS);
+ scheduleFocusTree();
+ }
+ });
+ Button collapse = new Button(bar, SWT.PUSH);
+ collapse.setText("&Collapse");
+ collapse.setToolTipText("Collapse Selected Nodes or All Nodes");
+ collapse.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ IStructuredSelection ss = tree.getStructuredSelection();
+ if (ss.isEmpty())
+ tree.collapseAll();
+ else
+ for (Object n : ss.toList())
+ tree.collapseToLevel(n, TreeViewer.ALL_LEVELS);
+ scheduleFocusTree();
+ }
+ });
+ }
+
+ protected void fireChangeListener() {
+ if (selectionChangeListener != null)
+ selectionChangeListener.run();
+ }
+
+ protected void scheduleFocusTree() {
+ display.asyncExec(() -> {
+ if (!tree.getTree().isDisposed() && !tree.getTree().isFocusControl())
+ tree.getTree().setFocus();
+ });
+ }
+
+ private Collection<Node> getVisibleNodes() {
+ Collection<Node> result = new ArrayList<>();
+
+ Deque<TreeItem> todo = new ArrayDeque<>();
+ for (TreeItem ti : tree.getTree().getItems()) {
+ todo.add(ti);
+ }
+
+ while (!todo.isEmpty()) {
+ TreeItem item = todo.removeLast();
+ Node node = (Node) item.getData();
+ if (node != null)
+ result.add(node);
+
+ for (TreeItem child : item.getItems()) {
+ todo.add(child);
+ }
+ }
+
+ return result;
+ }
+
+ private void resetFilterString(String filterString) {
+ TreePath[] restoreExpansions = null;
+ String patternString = filterStrategy.toPatternString(filterString);
+ if (patternString == null) {
+ if (matcher != null) {
+ // Filter has been removed
+ restoreExpansions = noFilterExpandedPaths;
+ noFilterExpandedPaths = null;
+ }
+ matcher = null;
+ } else {
+ if (matcher == null) {
+ // Filter has been defined after not being previously defined
+ noFilterExpandedPaths = tree.getExpandedTreePaths();
+ }
+ matcher = Pattern.compile(patternString).matcher("");
+ }
+ refreshTree(false);
+ if (restoreExpansions != null)
+ tree.setExpandedTreePaths(restoreExpansions);
+ else
+ tree.expandAll();
+ }
+
+ protected static boolean hasDiagram(Node n) {
+ return n.getDiagramResource() != null;
+ }
+
+ protected static boolean hasDiagramDeep(Node n) {
+ if (hasDiagram(n))
+ return true;
+ for (Node c : n.getChildren())
+ if (hasDiagramDeep(c))
+ return true;
+ return false;
+ }
+
+ protected boolean isSomethingSelected(Node node) {
+ if (selectedNodes.contains(node))
+ return true;
+
+ Collection<Node> children = node.getChildren();
+ if (!children.isEmpty()) {
+ for (Node child : children) {
+ if (!hasDiagramDeep(child))
+ continue;
+ if (isSomethingSelected(child))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected boolean isFullySelected(Node node) {
+ if (selectedNodes.contains(node))
+ return true;
+
+ int selectedCount = 0;
+ boolean allSelected = true;
+ Collection<Node> children = node.getChildren();
+ if (!children.isEmpty()) {
+ for (Node child : children) {
+ if (!hasDiagramDeep(child))
+ continue;
+ boolean selected = isFullySelected(child);
+ allSelected &= selected;
+ selectedCount += selected ? 1 : 0;
+ //System.out.println("\tisFullySelected: test child: " + child + " : " + selected + " => " + allSelected);
+ if (!selected)
+ break;
+ }
+ }
+ //System.out.println("isFullySelected(" + node + "): " + allSelected + ", " + selectedCount);
+ return allSelected && selectedCount > 0;
+ }
+
+ protected boolean isPartiallySelected(Node node) {
+ return !selectedNodes.contains(node) && isSomethingSelected(node) && !isFullySelected(node);
+ }
+
+ protected void refreshTree(boolean invalidateCheckStateCache) {
+ if (invalidateCheckStateCache)
+ checkStateCache.invalidate();
+ tree.refresh();
+ }
+
+ public void refreshTree() {
+ refreshTree(true);
+ }
+
+ public boolean addOrRemoveSelection(Node node, boolean add) {
+ boolean changed = false;
+ if (hasDiagram(node)) {
+ if (add)
+ changed = selectedNodes.add(node);
+ else
+ changed = selectedNodes.remove(node);
+ if (changed)
+ checkStateCache.invalidate(node);
+ }
+ return changed;
+ }
+
+ public boolean addOrRemoveSelectionRec(Node node, boolean add) {
+ boolean changed = false;
+ changed |= addOrRemoveSelection(node, add);
+ for (Node child : node.getChildren())
+ changed |= addOrRemoveSelectionRec(child, add);
+ return changed;
+ }
+
+ private static class NodeTreeContentProvider implements ITreeContentProvider {
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+ @Override
+ public void dispose() {
+ }
+ @Override
+ public Object[] getElements(Object inputElement) {
+ if (inputElement instanceof CollectionResult)
+ return ((CollectionResult) inputElement).roots.toArray();
+ return new Object[0];
+ }
+ @Override
+ public boolean hasChildren(Object element) {
+ Node n = (Node) element;
+ Collection<Node> children = n.getChildren();
+ if (children.isEmpty())
+ return false;
+ for (Node c : children)
+ if (hasDiagramDeep(c))
+ return true;
+ return false;
+
+ }
+ @Override
+ public Object getParent(Object element) {
+ return ((Node) element).getParent();
+ }
+ @Override
+ public Object[] getChildren(Object parentElement) {
+ Node n = (Node) parentElement;
+ List<Object> result = new ArrayList<>( n.getChildren().size() );
+ for (Node c : n.getChildren())
+ if (hasDiagramDeep(c))
+ result.add(c);
+ return result.toArray();
+ }
+ }
+
+ private class NodeLabelProvider extends 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());
+ }
+ }
+ }
+
+ private class CheckStateListener implements ICheckStateListener {
+ @Override
+ public void checkStateChanged(CheckStateChangedEvent event) {
+ final boolean checked = event.getChecked();
+ Node checkedNode = (Node) event.getElement();
+
+ Set<Node> nodes = new HashSet<>();
+ 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.refresh();
+ fireChangeListener();
+ }
+ }
+
+ private class NodeCheckStateProvider implements ICheckStateProvider {
+ @Override
+ public boolean isChecked(Object element) {
+ Node n = (Node) element;
+ Boolean cache = checkStateCache.isChecked.get(n);
+ if (cache != null)
+ return cache;
+ boolean checked = isSomethingSelected(n);
+ checkStateCache.isChecked.put(n, checked);
+ return checked;
+ }
+ @Override
+ public boolean isGrayed(Object element) {
+ Node n = (Node) element;
+ Boolean cache = checkStateCache.isGrayed.get(n);
+ if (cache != null)
+ return cache;
+ boolean grayed = n.getDiagramResource() == null && isPartiallySelected(n);
+ checkStateCache.isGrayed.put(n, grayed);
+ return grayed;
+ }
+ }
+
+ private class NodeFilter extends ViewerFilter {
+ @Override
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ if (matcher == null)
+ return true;
+
+ Node node = (Node) element;
+ boolean matches = matcher.reset(node.getName().toLowerCase()).matches();
+ if (matches)
+ return true;
+
+ // If any children are in sight, show this element.
+ for (Node child : node.getChildren())
+ if (select(viewer, element, child))
+ return true;
+
+ return false;
+ }
+ }
+
+}
\ No newline at end of file
/*******************************************************************************
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * 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
*
* Contributors:
* VTT Technical Research Centre of Finland - initial API and implementation
+ * Semantum Oy - initial selection handling improvements
*******************************************************************************/
package org.simantics.modeling.ui.pdf;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
-import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.preference.IPersistentPreferenceStore;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.IFilter;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.preferences.ScopedPreferenceStore;
+import org.simantics.NameLabelMode;
+import org.simantics.NameLabelUtil;
import org.simantics.Simantics;
-import org.simantics.browsing.ui.graph.impl.request.GetName;
import org.simantics.db.ReadGraph;
import org.simantics.db.Resource;
import org.simantics.db.common.NamedResource;
import org.simantics.db.common.request.ObjectsWithType;
+import org.simantics.db.common.request.PossibleIndexRoot;
import org.simantics.db.common.request.ReadRequest;
import org.simantics.db.exception.DatabaseException;
-import org.simantics.db.layer0.request.ActiveModels;
import org.simantics.db.management.ISessionContext;
import org.simantics.layer0.Layer0;
import org.simantics.modeling.requests.Node;
import org.simantics.ui.SimanticsUI;
import org.simantics.ui.utils.ResourceAdaptionUtils;
import org.simantics.utils.FileUtils;
+import org.simantics.utils.strings.AlphanumComparator;
import org.simantics.utils.ui.ErrorLogger;
import org.simantics.utils.ui.ExceptionUtils;
import org.simantics.utils.ui.workbench.StringMemento;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class PDFDiagramExportWizard extends Wizard implements IExportWizard {
+ private static final Logger LOGGER = LoggerFactory.getLogger(PDFDiagramExportWizard.class);
+
private static final int MAX_RECENT_EXPORT_PATHS = 10;
private static final String TAG_PATH = "path";
Deque<String> recentExportPaths;
boolean zoomToFit;
- boolean attachTG, attachWiki;
+ boolean attachTG, attachWiki, addPageNumbers;
- PDFExportPlan exportPlan;
+ PDFExportPlan exportPlan;
private boolean readPreferences() {
IPreferenceStore store = new ScopedPreferenceStore(InstanceScope.INSTANCE, Activator.PLUGIN_ID);
zoomToFit = store.getBoolean(Preferences.DIAGRAM_EXPORT_PDF_ZOOM_TO_FIT);
attachTG = store.getBoolean(Preferences.DIAGRAM_EXPORT_PDF_ATTACH_TG);
attachWiki = store.getBoolean(Preferences.DIAGRAM_EXPORT_PDF_ATTACH_WIKI);
+ addPageNumbers = store.getBoolean(Preferences.DIAGRAM_EXPORT_PDF_ADD_PAGE_NUMBERS);
return true;
}
store.putValue(Preferences.DIAGRAM_EXPORT_PDF_ZOOM_TO_FIT, String.valueOf(zoomToFit));
store.putValue(Preferences.DIAGRAM_EXPORT_PDF_ATTACH_TG, String.valueOf(attachTG));
store.putValue(Preferences.DIAGRAM_EXPORT_PDF_ATTACH_WIKI, String.valueOf(attachWiki));
+ store.putValue(Preferences.DIAGRAM_EXPORT_PDF_ADD_PAGE_NUMBERS, String.valueOf(addPageNumbers));
if (store.needsSaving())
store.save();
}
private Deque<String> decodePaths(String recentPathsPref) {
- Deque<String> result = new LinkedList<String>();
+ Deque<String> result = new LinkedList<>();
try {
StringMemento sm = new StringMemento(recentPathsPref);
for (IMemento m : sm.getChildren(TAG_PATH)) {
}
private NamedResource toNamedResource(ReadGraph graph, Resource r) throws DatabaseException {
- String name = graph.syncRequest(new GetName(r));
+ String name = NameLabelUtil.modalName(graph, r, NameLabelMode.NAME_AND_LABEL);
return new NamedResource(name, r);
}
exportPlan = new PDFExportPlan(ctx, recentExportPaths);
exportPlan.project = project;
- final Object selectedObject = selection.getFirstElement();
+ exportPlan.initialSelection = selection;
exportPlan.fitContentToPageMargins = zoomToFit;
exportPlan.attachTG = attachTG;
exportPlan.attachWiki = attachWiki;
+ exportPlan.addPageNumbers = addPageNumbers;
// Get all model names
try {
exportPlan.sessionContext.getSession().syncRequest(new ReadRequest() {
@Override
public void run(ReadGraph graph) throws DatabaseException {
- Resource selection = ResourceAdaptionUtils.toSingleResource(selectedObject);
- if (selection != null) {
- //exportModel.selection = new NamedResource(name + " (input selection)", selection);
- exportPlan.selection = toNamedResource(graph, selection);
- exportPlan.selectableModels.add(exportPlan.selection);
- } else {
- for (Resource activeModel : graph.syncRequest(new ActiveModels(exportPlan.project.get()))) {
- selection = activeModel;
- exportPlan.selection = toNamedResource(graph, activeModel);
- exportPlan.selectableModels.add( exportPlan.selection );
- break;
- }
- }
+ Set<Resource> processed = new HashSet<>();
+ List<NamedResource> models = new ArrayList<>();
- List<NamedResource> models = new ArrayList<NamedResource>();
-
Collection<Resource> ontologies = Simantics.applySCL("Simantics/SharedOntologies", "traverseSharedOntologies", graph, graph.getRootLibrary());
- for (Resource model : ontologies) {
- if (model.equals(selection))
- continue;
- models.add( toNamedResource(graph, model) );
+ for (Resource root : ontologies) {
+ if (processed.add(root))
+ models.add( toNamedResource(graph, root) );
}
-
+
for (Resource model : graph.syncRequest(new ObjectsWithType(exportPlan.project.get(),
Layer0.getInstance(graph).ConsistsOf, SimulationResource.getInstance(graph).Model))) {
- if (model.equals(selection))
- continue;
- models.add( toNamedResource(graph, model) );
+ if (processed.add(model))
+ models.add( toNamedResource(graph, model) );
}
- Collections.sort(models);
+ Collections.sort(models, AlphanumComparator.CASE_INSENSITIVE_COMPARATOR);
exportPlan.selectableModels.addAll(models);
- if (selection == null && !exportPlan.selectableModels.isEmpty()) {
+
+ Resource selected = ResourceAdaptionUtils.toSingleResource(selection.getFirstElement());
+ Resource indexRoot = selected != null ? graph.sync(new PossibleIndexRoot(selected)) : null;
+ if (indexRoot != null)
+ exportPlan.initialModelSelection = exportPlan.selection = toNamedResource(graph, indexRoot);
+
+ if (exportPlan.selection == null && !exportPlan.selectableModels.isEmpty())
exportPlan.selection = exportPlan.selectableModels.get(0);
- }
}
});
} catch (DatabaseException e) {
- e.printStackTrace();
+ LOGGER.error("Failed to initialize diagram PDF export wizard input data.", e);
}
}
recentExportPaths.addFirst(exportPlan.exportLocation.getAbsolutePath());
// Remove duplicates
- Set<String> dups = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
+ Set<String> dups = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
for (Iterator<String> it = recentExportPaths.iterator(); it.hasNext();) {
String path = it.next();
if (!dups.add(path)) {
zoomToFit = exportPlan.fitContentToPageMargins;
attachTG = exportPlan.attachTG;
attachWiki = exportPlan.attachWiki;
+ addPageNumbers = exportPlan.addPageNumbers;
writePreferences();
} catch (IOException e) {
long start = System.currentTimeMillis();
try {
- getContainer().run(true, true, new IRunnableWithProgress() {
- @Override
- public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
- try {
- DiagramPrinter.printToPdf(monitor, exportPlan, exportPlan.exportLocation.toString(), exportPlan.selectedNodes);
- } catch (PdfException e) {
- throw new InvocationTargetException(e);
- } finally {
- monitor.done();
- }
+ getContainer().run(true, true, monitor -> {
+ try {
+ DiagramPrinter.printToPdf(monitor, exportPlan, exportPlan.exportLocation.toString(), exportPlan.selectedNodes);
+ } catch (PdfException e) {
+ throw new InvocationTargetException(e);
+ } finally {
+ monitor.done();
}
});
} catch (InvocationTargetException e) {
return false;
}
long end = System.currentTimeMillis();
- System.out.println("PDF export took " + ((end - start) * 1e-3) + " seconds.");
+ LOGGER.info("PDF export took " + ((end - start) * 1e-3) + " seconds.");
return true;
}
/*******************************************************************************
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * 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
*
* 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.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.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.simantics.utils.strings.AlphanumComparator;
-import org.simantics.utils.ui.ISelectionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class PDFExportPage extends WizardPage {
- protected Display display;
+ private static final Logger LOGGER = LoggerFactory.getLogger(PDFExportPage.class);
- protected PDFExportPlan exportModel;
+ protected Display display;
- protected IFilterStrategy filterStrategy = new DefaultFilterStrategy();
+ protected PDFExportPlan exportModel;
protected Combo modelSelector;
protected SelectionListener modelSelectorListener;
- protected Text filter;
-
- protected Matcher matcher = null;
-
- protected CheckboxTreeViewer tree;
+ protected NodeTree nodeTree;
protected CCombo exportLocation;
protected ModifyListener exportLocationListener;
protected Set<Node> selectedNodes;
-
- protected LocalResourceManager resourceManager;
- protected Color noDiagramColor;
- protected Label toFileLabel;
+ 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;
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:");
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<er:");
- 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();
- }
- });
+ 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:");
}
});
*/
-
+
final Button attachWikiButton = new Button(container, SWT.CHECK);
GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo( attachWikiButton );
attachWikiButton.setText("Attach &Wiki page");
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();
}
private void scheduleInitializeData(final NamedResource modelSelection) {
- display.asyncExec(new Runnable() {
- @Override
- public void run() {
- if (filter.isDisposed())
- return;
-
- try {
+ display.asyncExec(() -> {
+ try {
+ if (!nodeTree.isDisposed())
initializeData(modelSelection);
- } catch (DatabaseException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.getTargetException().printStackTrace();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
+ } catch (DatabaseException | InterruptedException e) {
+ LOGGER.error("Input data initialization failed.", e);
+ } catch (InvocationTargetException e) {
+ LOGGER.error("Input data initialization failed.", e.getTargetException());
}
});
}
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 {
+ Set<Node> toBeSelected = new HashSet<>();
+
if (modelSelection != null) {
// Process input selection to find the model/state selected by default.
// !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() });
+ 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;
+ });
}
- });
- } catch (DatabaseException e) {
- throw new InvocationTargetException(e);
- } finally {
- monitor.done();
- }
+
+ // 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)
- System.out.println("Found " + exportModel.nodes.diagrams.size() + " diagrams in " + ((endTime - time)*1e-9) + " seconds.");
+ LOGGER.info("Found " + exportModel.nodes.diagrams.size() + " diagrams in " + ((endTime - time)*1e-9) + " seconds.");
}
// Browsing was canceled by user.
// Setup selected states, select everything by default.
selectedNodes.clear();
- selectedNodes.addAll(exportModel.nodes.breadthFirstFlatten());
-
- tree.setInput(this);
+ selectedNodes.addAll(toBeSelected);
- for (Node root : exportModel.nodes.roots) {
- tree.setSubtreeChecked(root, true);
- }
-
- resetFilterString(filter.getText());
+ // Fully refresh node tree
+ nodeTree.setInput(exportModel.nodes);
modelSelector.removeSelectionListener(modelSelectorListener);
int selectedIndex = -1;
}
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 (selectedNodes.size() == 0) {
+ if (diagramCount == 0) {
setMessage("Select the diagrams to export.");
setErrorMessage(null);
setPageComplete(false);
// 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();
+ if (diagramCount == 1 && singleDiagram != null) {
+ generatedName = nr.getName() + "-" + singleDiagram.getName();
} else {
generatedName = nr.getName();
}
}
exportModel.exportLocation = file;
- int diagramCount = 0;
- for (Node n : selectedNodes)
- if (n.getDiagramResource() != null)
- ++diagramCount;
-
String msg = diagramCount + " diagrams selected for export.";
setMessage(msg);
import java.util.List;
import java.util.Set;
+import org.eclipse.jface.viewers.IStructuredSelection;
import org.simantics.db.common.NamedResource;
import org.simantics.db.management.ISessionContext;
import org.simantics.export.core.pdf.PageNumbering;
// Input
public ISessionContext sessionContext;
public IProject project;
+ public IStructuredSelection initialSelection;
+ public NamedResource initialModelSelection;
public List<NamedResource> selectableModels = new ArrayList<NamedResource>();
public NamedResource selection;
public Collection<String> recentLocations;
/*******************************************************************************
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * 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
*
* Contributors:
* VTT Technical Research Centre of Finland - initial API and implementation
+ * Semantum Oy - page numbering additions
*******************************************************************************/
package org.simantics.modeling.ui.pdf;
String DIAGRAM_EXPORT_PDF_ZOOM_TO_FIT = "diagram.export.pdf.zoomToFit";
String DIAGRAM_EXPORT_PDF_ATTACH_TG = "diagram.export.pdf.attachTG";
String DIAGRAM_EXPORT_PDF_ATTACH_WIKI = "diagram.export.pdf.attachWiki";
-
+ String DIAGRAM_EXPORT_PDF_ADD_PAGE_NUMBERS = "diagram.export.pdf.addPageNumbers";
}
/*******************************************************************************
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * 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
import org.simantics.db.common.request.ReadRequest;
import org.simantics.db.common.request.ResourceRead;
import org.simantics.db.common.utils.NameUtils;
-import org.simantics.db.exception.AdaptionException;
import org.simantics.db.exception.DatabaseException;
import org.simantics.db.request.Read;
import org.simantics.diagram.query.DiagramRequests;
return g.syncRequest(new GetName(r));
}
-// Collection<String> getPartOfGroups(Resource diagram) throws DatabaseException {
-// Resource r = diagram;
-// Deque<String> result = new ArrayDeque<String>();
-// loop:
-// while (true) {
-// for (Resource partOf : g.getObjects(r, b.PartOf)) {
-// if (g.isInstanceOf(partOf, dr.DiagramLibrary)) {
-// result.addFirst(safeGetName(partOf));
-// r = partOf;
-// continue loop;
-// }
-// }
-// return result;
-// }
-// }
-
@Override
public CollectionResult perform(ReadGraph g) throws DatabaseException {
this.g = g;
SIMU = SimulationResource.getInstance(g);
final CollectionResult result = new CollectionResult();
- final Deque<Node> roots = new ArrayDeque<Node>();
+ final Deque<Node> roots = new ArrayDeque<>();
// 1. Based on input, look for the proper nodes to start browsing for diagrams.
for (Resource r : input) {
- /*if (g.isInstanceOf(r, SIMU.Model)) {
- // Complete models
- Resource composite = g.getPossibleObject(r, SIMU.HasConfiguration);
- Resource diagram = composite != null ? g.getPossibleObject(composite, mr.CompositeToDiagram) : null;
-
- if (DEBUG)
- System.out.println("Model root");
-
- if (composite != null) {
- Node node = new Node(null, safeGetName(r), diagram, composite, r);
- roots.add(node);
- result.roots.add(roots.peekLast());
- }
- } else*/ if (g.isInstanceOf(r, l0.IndexRoot)) {
-// for(Resource type : ModelingUtils.searchByTypeShallow(g, r, sr.ComponentType)) {
-// Resource composite = g.getPossibleObject(type, sr.IsDefinedBy);
-// Resource diagram = composite != null ? g.getPossibleObject(composite, mr.CompositeToDiagram) : null;
-// if(composite != null) {
-// Node node = new Node(null, safeGetName(r), diagram, composite, r);
-// roots.add(node);
-// result.roots.add(roots.peekLast());
-// }
-// }
-
- Node node = new Node(null, safeGetName(r), null, r);
- roots.add(node);
- result.roots.add(roots.peekLast());
-
+ if (g.isInstanceOf(r, l0.IndexRoot)) {
+ Node node = new Node(null, safeGetName(r), null, r);
+ roots.add(node);
+ result.roots.add(roots.peekLast());
} else if (g.isInstanceOf(r, sr.Composite)) {
// The contents of components
String name = null;
Resource model = g.getPossibleObject(r, SIMU.IsConfigurationOf);
- //Resource componentType = g.getPossibleObject(r, sr.Defines);
if (model != null) {
name = safeGetName(model);
-
if (DEBUG)
System.out.println("Configuration root: " + name);
-
-// } else if (componentType != null) {
-// Resource singleInstance = componentType != null ? g.getPossibleObject(componentType, b.HasSingleInstance) : null;
-// name = singleInstance != null ? safeGetName(singleInstance) : safeGetName(componentType);
-// System.out.println("Composite of component type root: " + name);
} else {
name = safeGetName(r);
if (DEBUG)
diagram = (diagram != null && g.isInstanceOf(diagram, dr.Composite)) ? diagram : null;
{
- Node node = new Node(null, name, diagram, r);
- roots.add(node);
- result.roots.add(roots.peekLast());
+ Node node = new Node(null, name, diagram, r);
+ roots.add(node);
+ result.roots.add(roots.peekLast());
}
-// } else if (g.isInstanceOf(r, sr.Component)) {
-// // Complete components themselves
-// Resource componentType = g.getSingleType(r, sr.Component);
-// Resource composite = g.getPossibleObject(componentType, sr.IsDefinedBy);
-// Resource diagram = (composite != null && g.isInstanceOf(composite, sr.Composite)) ? g.getPossibleObject(composite, mr.CompositeToDiagram) : null;
-// String name = safeGetName(r);
-// System.out.println("Component root: " + name);
-// roots.add(new Node(null, name, diagram, composite, r));
-// result.roots.add(roots.peekLast());
} else if (g.isInheritedFrom(r, dr.DefinedElement)) {
// Symbols
Resource composite = g.getPossibleObject(r, sr.IsDefinedBy);
name += " Symbol";
if (DEBUG)
System.out.println("Symbol root: " + name);
-
- {
- Node node = new Node(null, name, composite, r);
- roots.add(node);
- result.roots.add(roots.peekLast());
+
+ {
+ Node node = new Node(null, name, composite, r);
+ roots.add(node);
+ result.roots.add(roots.peekLast());
}
}
-// } else if (g.isInheritedFrom(r, sr.Component)) {
-// // Reusable component types
-// Resource composite = g.getPossibleObject(r, sr.IsDefinedBy);
-// Resource diagram = (composite != null && g.isInstanceOf(composite, sr.Composite)) ? g.getPossibleObject(composite, mr.CompositeToDiagram) : null;
-// String name = safeGetName(r);
-// System.out.println("Component type root: " + name);
-// roots.add(new Node(null, name, diagram, r, composite));
-// result.roots.add(roots.peekLast());
}
}
private void loadComposites(ReadGraph graph, final Node node) throws DatabaseException {
Resource diagram = node.getDiagramResource();
- //System.out.println("loadComposites(" + diagram + ", " + node + ")");
- if (diagram != null) {
+ if (DEBUG)
+ System.out.println("loadComposites(" + diagram + ", " + node + ")");
+ if (diagram != null)
result.addDiagram(diagram, node);
-// node.setPartOfGroups(getPartOfGroups(diagram));
- }
mon.setWorkRemaining(1000);
for(Resource r : graph.getObjects(node.getDefiningResources().resources[0], l0.ConsistsOf)) {
- if(graph.isInstanceOf(r, sr.Composite)) {
- String compositeName = graph.syncRequest(new GetName(r));
- Resource definingDiagram = graph.getPossibleObject(r, mr.CompositeToDiagram);
- Node n = new Node(node, compositeName, definingDiagram, r);
+ if(graph.isInstanceOf(r, sr.Composite)) {
+ String compositeName = graph.syncRequest(new GetName(r));
+ Resource definingDiagram = graph.getPossibleObject(r, mr.CompositeToDiagram);
+ Node n = new Node(node, compositeName, definingDiagram, r);
+ if (DEBUG)
+ System.out.println("Found composite: " + n);
loadComposites(graph, n);
mon.worked(1);
- } else if (graph.isInstanceOf(r, l0.Library)) {
- String compositeName = graph.syncRequest(new GetName(r));
- Node n = new Node(node, compositeName, null, r);
+ } else if (graph.isInstanceOf(r, l0.Library)) {
+ String compositeName = graph.syncRequest(new GetName(r));
+ Node n = new Node(node, compositeName, null, r);
+ if (DEBUG)
+ System.out.println("Found library: " + n);
loadComposites(graph, n);
mon.worked(1);
- } else if (graph.isInheritedFrom(r, sr.Component)) {
- String name = safeGetName(r);
- Node n = new Node(node, name, null, r);
- loadComposites(graph, n);
- mon.worked(1);
- }
+ } else if (graph.isInheritedFrom(r, sr.Component)) {
+ Resource definedBy = graph.getPossibleObject(r, sr.IsDefinedBy);
+ if (definedBy == null)
+ continue;
+ String name = safeGetName(r);
+ Node n = new Node(node, name, null, r);
+ if (DEBUG)
+ System.out.println("Found component: " + n);
+ loadComposites(graph, n);
+ mon.worked(1);
+ }
}
-
}
-
});
ILog log = Platform.getLog(Platform.getBundle(Plugin.PLUGIN_ID));
return result;
}
-
- static class GetName extends ResourceRead<String> {
+ static class GetName extends ResourceRead<String> {
public GetName(Resource resource) {
super(resource);
}
public String perform(ReadGraph graph) throws DatabaseException {
try {
return NameLabelUtil.modalName(graph, resource);
- } catch (AdaptionException e) {
+ } catch (DatabaseException e) {
return NameUtils.getSafeName(graph, resource);
}
}
-
}
}
\ No newline at end of file
*/
public class CollectionResult {
+ public static final IFilter DIAGRAM_RESOURCE_FILTER = o -> Nodes.DIAGRAM_RESOURCE_PREDICATE.test((Node) o);
+ public static final IFilter DIAGRAM_RESOURCE_AND_RVI_FILTER = o -> Nodes.DIAGRAM_RESOURCE_AND_RVI_PREDICATE.test((Node) o);
+
public class DiagramFilter implements IFilter {
private final IFilter proxy;
}
- final public Set<Node> roots = new ConcurrentSkipListSet<Node>();
- final private Set<Node> diagramSet = new ConcurrentSkipListSet<Node>();
- final public List<Node> diagramList = new Vector<Node>();
- final public Map<Resource, Node> diagrams = new ConcurrentHashMap<Resource, Node>();
+ public final Set<Node> roots;
+ private final Set<Node> diagramSet;
+ public final List<Node> diagramList;
+ public final Map<Resource, Node> diagrams;
+
+ public CollectionResult() {
+ this.roots = new ConcurrentSkipListSet<Node>();
+ this.diagramSet = new ConcurrentSkipListSet<Node>();
+ this.diagramList = new Vector<Node>();
+ this.diagrams = new ConcurrentHashMap<Resource, Node>();
+ }
+
+ private CollectionResult(Set<Node> roots, Set<Node> diagramSet, List<Node> diagramList, Map<Resource, Node> diagrams) {
+ this.roots = roots;
+ this.diagramSet = diagramSet;
+ this.diagramList = diagramList;
+ this.diagrams = diagrams;
+ }
+
+ public CollectionResult withRoots(Set<Node> roots) {
+ return new CollectionResult(roots, diagramSet, diagramList, diagrams);
+ }
public void addDiagram(Resource r, Node n) {
diagramList.add(n);
*/
public class Node implements Comparable<Node> {
- public static final Comparator<Node> CASE_INSENSITIVE_COMPARATOR = new Comparator<Node>() {
- @Override
- public int compare(Node o1, Node o2) {
- return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(o1.getName(), o2.getName());
- }
- };
+ public static final Comparator<Node> CASE_INSENSITIVE_COMPARATOR =
+ (o1, o2) -> AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(o1.getName(), o2.getName());
private final Node parent;
private final List<Node> children = new ArrayList<Node>();
+ private final List<Node> unmodifiableChildren = Collections.unmodifiableList(children);
/**
* May be <code>null</code> if there is no diagram for this node.
private final ResourceArray definingResource; // i.e. Composite
private final String name;
-// private String[] partOfGroups = {};
-
private PageDesc pageDesc;
- private String RVI;
+ private String rvi;
/**
* @param parent
parent.addChild(this);
}
+ public Node cloneWithoutChildren(Node parent) {
+ Node clone = new Node(parent, name, diagram, definingResource.resources);
+ clone.setRVI(rvi);
+ clone.setPageDesc(pageDesc);
+ return clone;
+ }
+
public Node getParent() {
return parent;
}
}
public Collection<Node> getChildren() {
- return Collections.unmodifiableCollection(children);
+ return unmodifiableChildren;
}
-// public void setPartOfGroups(Collection<String> groups) {
-// this.partOfGroups = groups.toArray(new String[groups.size()]);
-// }
-//
-// public String[] getPartOfGroups() {
-// return partOfGroups;
-// }
-
public void setPageDesc(PageDesc pageDesc) {
this.pageDesc = pageDesc;
}
- public void setRVI(String RVI) {
- this.RVI = RVI;
+ public void setRVI(String rvi) {
+ this.rvi = rvi;
}
public String getRVI() {
- return RVI;
+ return rvi;
}
public PageDesc getPageDesc() {
import java.util.Comparator;
import java.util.Deque;
import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.function.Predicate;
import org.eclipse.jface.viewers.IFilter;
import org.simantics.scl.runtime.function.Function1;
*/
public class Nodes {
+ public static final Predicate<Node> DIAGRAM_RESOURCE_PREDICATE = n -> n.getDiagramResource() != null;
+ public static final Predicate<Node> DIAGRAM_RESOURCE_AND_RVI_PREDICATE = n -> n.getDiagramResource() != null && n.getRVI() != null;
+
public static Collection<Node> breadthFirstFlatten(IFilter filter, Collection<Node> roots) {
- Collection<Node> result = new ArrayList<Node>();
- List<Node> sortedRoots = new ArrayList<Node>(roots);
+ Collection<Node> result = new ArrayList<>();
+ List<Node> sortedRoots = new ArrayList<>(roots);
Collections.sort(sortedRoots);
- Deque<Node> todo = new ArrayDeque<Node>(sortedRoots);
+ Deque<Node> todo = new ArrayDeque<>(sortedRoots);
while (!todo.isEmpty()) {
Node n = todo.removeFirst();
- List<Node> sorted = new ArrayList<Node>(n.getChildren());
+ List<Node> sorted = new ArrayList<>(n.getChildren());
Collections.sort(sorted);
todo.addAll(sorted);
if (filter == null || filter.select(n))
}
public static Collection<Node> depthFirstFlatten(IFilter filter, Collection<Node> roots, Comparator<? super Node> comparator) {
- Collection<Node> result = new ArrayList<Node>();
- List<Node> sortedRoots = new ArrayList<Node>(roots);
+ Collection<Node> result = new ArrayList<>();
+ List<Node> sortedRoots = new ArrayList<>(roots);
Collections.sort(sortedRoots, comparator);
for (Node n : sortedRoots) {
depthFirstFlattenRec(filter, comparator, n, result);
if (children.isEmpty())
return result;
- List<Node> sorted = new ArrayList<Node>(children);
+ List<Node> sorted = new ArrayList<>(children);
Collections.sort(sorted, comparator);
for (Node child : sorted)
depthFirstFlattenRec(filter, comparator, child, result);
* if the walk was cancelled
*/
public static boolean walkTree(Function1<Node, Boolean> filter, Collection<Node> roots) {
- List<Node> sortedRoots = new ArrayList<Node>(roots);
+ List<Node> sortedRoots = new ArrayList<>(roots);
Collections.sort(sortedRoots);
for (Node n : sortedRoots)
if (!walkTreeRec(filter, n))
Collection<Node> children = n.getChildren();
if (!children.isEmpty()) {
- List<Node> sorted = new ArrayList<Node>(children);
+ List<Node> sorted = new ArrayList<>(children);
Collections.sort(sorted);
for (Node child : sorted)
if (!walkTreeRec(filter, child))
return true;
}
+ public static boolean parentIsInSet(Set<Node> set, Node node) {
+ for (Node n = node.getParent(); n != null; n = n.getParent())
+ if (set.contains(n))
+ return true;
+ return false;
+ }
+
+ public static Set<Node> depthFirstFilter(Predicate<Node> filter, Collection<Node> nodes) {
+ Set<Node> result = new TreeSet<>(Node.CASE_INSENSITIVE_COMPARATOR);
+ for (Node n : nodes) {
+ Node newNode = depthFirstFilterRec(filter, n, null);
+ if (newNode != null)
+ result.add(newNode);
+ }
+ return result;
+ }
+
+ public static Node depthFirstFilter(Predicate<Node> filter, Node n) {
+ return depthFirstFilterRec(filter, n, null);
+ }
+
+ private static Node depthFirstFilterRec(Predicate<Node> filter, Node n, Node newParent) {
+ Collection<Node> children = n.getChildren();
+ if (children.isEmpty())
+ return filter.test(n) ? n.cloneWithoutChildren(newParent) : null;
+
+ Node newNode = n.cloneWithoutChildren(newParent);
+ int childCount = 0;
+ for (Node child : children) {
+ Node newChild = depthFirstFilterRec(filter, child, newNode);
+ if (newChild != null)
+ ++childCount;
+ }
+
+ return childCount > 0 ? newNode : null;
+ }
+
}