]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFExportPage.java
Merge "Revert "Default property editing restores assertions""
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / pdf / PDFExportPage.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2017 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *     Semantum Oy - #7297
12  *******************************************************************************/
13 package org.simantics.modeling.ui.pdf;
14
15 import java.io.File;
16 import java.lang.reflect.InvocationTargetException;
17 import java.util.HashSet;
18 import java.util.Set;
19
20 import org.eclipse.core.runtime.IPath;
21 import org.eclipse.core.runtime.Path;
22 import org.eclipse.core.runtime.SubMonitor;
23 import org.eclipse.jface.layout.GridDataFactory;
24 import org.eclipse.jface.wizard.WizardPage;
25 import org.eclipse.swt.SWT;
26 import org.eclipse.swt.custom.CCombo;
27 import org.eclipse.swt.events.ModifyEvent;
28 import org.eclipse.swt.events.ModifyListener;
29 import org.eclipse.swt.events.SelectionAdapter;
30 import org.eclipse.swt.events.SelectionEvent;
31 import org.eclipse.swt.events.SelectionListener;
32 import org.eclipse.swt.layout.GridData;
33 import org.eclipse.swt.layout.GridLayout;
34 import org.eclipse.swt.widgets.Button;
35 import org.eclipse.swt.widgets.Combo;
36 import org.eclipse.swt.widgets.Composite;
37 import org.eclipse.swt.widgets.Display;
38 import org.eclipse.swt.widgets.FileDialog;
39 import org.eclipse.swt.widgets.Label;
40 import org.simantics.databoard.Bindings;
41 import org.simantics.db.ReadGraph;
42 import org.simantics.db.Resource;
43 import org.simantics.db.common.NamedResource;
44 import org.simantics.db.common.request.ReadRequest;
45 import org.simantics.db.exception.DatabaseException;
46 import org.simantics.modeling.requests.CollectionResult;
47 import org.simantics.modeling.requests.Node;
48 import org.simantics.modeling.requests.Nodes;
49 import org.simantics.ui.utils.ResourceAdaptionUtils;
50 import org.simantics.utils.FileUtils;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 public class PDFExportPage extends WizardPage {
55
56     private static final Logger    LOGGER = LoggerFactory.getLogger(PDFExportPage.class);
57
58     protected Display              display;
59
60     protected PDFExportPlan        exportModel;
61
62     protected Combo                modelSelector;
63     protected SelectionListener    modelSelectorListener;
64
65     protected NodeTree             nodeTree;
66
67     protected CCombo               exportLocation;
68     protected ModifyListener       exportLocationListener;
69
70     protected Set<Node>            selectedNodes;
71     
72     protected Label                toFileLabel;
73
74     protected boolean              exportLocationTouchedByUser = false;
75
76     protected PDFExportPage(PDFExportPlan model) {
77         super("Export Diagrams to PDF", "Define Exported Items", null);
78         this.exportModel = model;
79         this.selectedNodes = exportModel.selectedNodeSet;
80     }
81
82     @Override
83     public void createControl(Composite parent) {
84         this.display = parent.getDisplay();
85
86         Composite container = new Composite(parent, SWT.NONE);
87         {
88             GridLayout layout = new GridLayout();
89             layout.horizontalSpacing = 20;
90             layout.verticalSpacing = 10;
91             layout.numColumns = 3;
92             container.setLayout(layout);
93         }
94
95         Label modelSelectorLabel = new Label(container, SWT.NONE);
96         modelSelectorLabel.setText("Model Selector:");
97         GridDataFactory.fillDefaults().span(1, 1).applyTo(modelSelectorLabel);
98         modelSelector = new Combo(container, SWT.BORDER | SWT.READ_ONLY);
99         GridDataFactory.fillDefaults().span(2, 1).applyTo(modelSelector);
100         modelSelectorListener = new SelectionAdapter() {
101             @Override
102             public void widgetSelected(SelectionEvent e) {
103                 NamedResource data = (NamedResource) modelSelector.getData(String.valueOf(modelSelector.getSelectionIndex()));
104                 scheduleInitializeData(data);
105             }
106         };
107
108         // Fill model selector combo
109         for (int i = 0; i < exportModel.selectableModels.size(); ++i) {
110             NamedResource nr = exportModel.selectableModels.get(i);
111             modelSelector.add(nr.getName());
112             modelSelector.setData("" + i, nr);
113         }
114
115         modelSelector.addSelectionListener(modelSelectorListener);
116
117         nodeTree = new NodeTree(container, selectedNodes);
118         GridDataFactory.fillDefaults().grab(true, true).span(3, 1).applyTo(nodeTree);
119         nodeTree.setSelectionChangeListener(this::validatePage);
120
121         toFileLabel = new Label(container, SWT.NONE);
122         toFileLabel.setText("&To file:");
123         exportLocation = new CCombo(container, SWT.BORDER);
124         {
125             exportLocation.setText("");
126             GridDataFactory.fillDefaults().grab(true, false).span(1, 1).applyTo(exportLocation);
127
128             for (String path : exportModel.recentLocations) {
129                 exportLocation.add(path);
130             }
131
132             exportLocationListener = new ModifyListener() {
133                 @Override
134                 public void modifyText(ModifyEvent e) {
135                     //System.out.println("export location changed by user");
136                     exportLocationTouchedByUser = true;
137                     validatePage();
138                 }
139             };
140             exportLocation.addModifyListener(exportLocationListener);
141         }
142         Button browseFileButton = new Button(container, SWT.PUSH);
143         {
144             browseFileButton.setText("Browse...");
145             browseFileButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
146             browseFileButton.addSelectionListener(new SelectionAdapter() {
147                 @Override
148                 public void widgetSelected(SelectionEvent e) {
149                     FileDialog dialog = new FileDialog(getShell(), SWT.SAVE);
150                     dialog.setFilterExtensions(new String[] { "*.pdf" });
151                     dialog.setFilterNames(new String[] { "PDF Document" });
152                     String loc = exportLocation.getText();
153                     if (loc != null) {
154                         IPath p = new Path(loc);
155                         File f = p.toFile();
156                         if (f.isDirectory()) {
157                             dialog.setFilterPath(f.toString());
158                         } else if (f.isFile()) {
159                             IPath path = p.removeLastSegments(1);
160                             String name = p.lastSegment();
161                             dialog.setFilterPath(path.toOSString());
162                             dialog.setFileName(name);
163                         } else {
164                             dialog.setFilterPath(f.toString());
165                             IPath path = p.removeLastSegments(1);
166                             String name = p.lastSegment();
167                             f = path.toFile();
168                             if (f.isDirectory()) {
169                                 dialog.setFilterPath(path.toOSString());
170                             }
171                             dialog.setFileName(name);
172                         }
173                     }
174                     String file = dialog.open();
175                     if (file == null)
176                         return;
177                     exportLocation.setText(file);
178                     validatePage();
179                 }
180             });
181         }
182
183         final Button zoomToFitButton = new Button(container, SWT.CHECK);
184         GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo(zoomToFitButton);
185         zoomToFitButton.setText("F&it by content");
186         zoomToFitButton.setSelection(exportModel.fitContentToPageMargins);
187         zoomToFitButton.addSelectionListener(new SelectionAdapter() {
188             @Override
189             public void widgetSelected(SelectionEvent e) {
190                 exportModel.fitContentToPageMargins = zoomToFitButton.getSelection();
191             }
192         });
193
194         /*
195         final Button attachTGButton = new Button(container, SWT.CHECK);
196         GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo( attachTGButton );
197         attachTGButton.setText("Attach &TG (Importable diagram)");
198         attachTGButton.setSelection(exportModel.attachTG);
199         attachTGButton.addSelectionListener(new SelectionAdapter() {
200             @Override
201             public void widgetSelected(SelectionEvent e) {
202                 exportModel.attachTG = attachTGButton.getSelection();
203             }
204         });
205         */
206
207         final Button attachWikiButton = new Button(container, SWT.CHECK);
208         GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo( attachWikiButton );
209         attachWikiButton.setText("Attach &Wiki page");
210         attachWikiButton.setSelection(exportModel.attachWiki);
211         attachWikiButton.addSelectionListener(new SelectionAdapter() {
212             @Override
213             public void widgetSelected(SelectionEvent e) {
214                 exportModel.attachWiki = attachWikiButton.getSelection();
215             }
216         });
217
218         final Button addPageNumbers = new Button(container, SWT.CHECK);
219         GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo( addPageNumbers );
220         addPageNumbers.setText("Add page &numbers");
221         addPageNumbers.setSelection(exportModel.addPageNumbers);
222         addPageNumbers.addSelectionListener(new SelectionAdapter() {
223             @Override
224             public void widgetSelected(SelectionEvent e) {
225                 exportModel.addPageNumbers = addPageNumbers.getSelection();
226             }
227         });
228
229         setControl(container);
230         validatePage();
231
232         scheduleInitializeData(exportModel.selection);
233     }
234
235     private void scheduleInitializeData(final NamedResource modelSelection) {
236         display.asyncExec(() -> {
237             try {
238                 if (!nodeTree.isDisposed())
239                     initializeData(modelSelection);
240             } catch (DatabaseException | InterruptedException e) {
241                 LOGGER.error("Input data initialization failed.", e);
242             } catch (InvocationTargetException e) {
243                 LOGGER.error("Input data initialization failed.", e.getTargetException());
244             }
245         });
246     }
247
248     private NamedResource getSelectedModel() {
249         int sel = modelSelector.getSelectionIndex();
250         if (sel != -1) {
251             NamedResource nr = (NamedResource) modelSelector.getData("" + sel);
252             return nr;
253         }
254         return null;
255     }
256
257     private void setExportLocationWithoutNotification(String text) {
258         exportLocation.removeModifyListener(exportLocationListener);
259         exportLocation.setText(text);
260         exportLocation.addModifyListener(exportLocationListener);
261     }
262
263     private void initializeData(final NamedResource modelSelection) throws DatabaseException, InvocationTargetException, InterruptedException {
264         Set<Node> toBeSelected = new HashSet<>();
265
266         if (modelSelection != null) {
267             // Process input selection to find the model/state selected by default.
268
269             // This may take longer than the user wants to wait without
270             // notification.
271
272             // !PROFILE
273             long time = System.nanoTime();
274
275             getWizard().getContainer().run(true, true, monitor -> {
276                 try {
277                     SubMonitor mon = SubMonitor.convert(monitor, "Searching for exportable diagrams...", 100);
278                     exportModel.sessionContext.getSession().syncRequest(new ReadRequest() {
279                         @Override
280                         public void run(ReadGraph graph) throws DatabaseException {
281                             CollectionResult coll = exportModel.nodes = DiagramPrinter.browse(mon.newChild(100), graph, new Resource[] { modelSelection.getResource() });
282
283                             // Decide initial selection based on exportModel.initialSelection
284                             if (modelSelection.equals(exportModel.initialModelSelection)) {
285                                 Set<Resource> selectedResources = new HashSet<>();
286                                 for (Object o : exportModel.initialSelection.toList()) {
287                                     Resource r = ResourceAdaptionUtils.toSingleResource(o);
288                                     if (r != null)
289                                         selectedResources.add(r);
290                                 }
291                                 coll.walkTree(node -> {
292                                     if (node.getDiagramResource() != null) {
293                                         if (Nodes.parentIsInSet(toBeSelected, node))
294                                             toBeSelected.add(node);
295                                         else
296                                             for (Resource r : node.getDefiningResources())
297                                                 if (selectedResources.contains(r))
298                                                     toBeSelected.add(node);
299                                     }
300                                     return true;
301                                 });
302                             }
303
304                             // Filter out any excess nodes from the tree.
305                             exportModel.nodes = coll = coll.withRoots(Nodes.depthFirstFilter(Nodes.DIAGRAM_RESOURCE_PREDICATE, coll.roots));
306
307                             // Select all if initial selection doesn't dictate anything.
308                             if (toBeSelected.isEmpty())
309                                 toBeSelected.addAll(coll.breadthFirstFlatten(CollectionResult.DIAGRAM_RESOURCE_FILTER));
310                         }
311                     });
312                 } catch (DatabaseException e) {
313                     throw new InvocationTargetException(e);
314                 } finally {
315                     monitor.done();
316                 }
317             });
318
319             // !PROFILE
320             long endTime = System.nanoTime();
321             if (exportModel.nodes != null)
322                 LOGGER.info("Found " + exportModel.nodes.diagrams.size() + " diagrams in " + ((endTime - time)*1e-9) + " seconds.");
323         }
324
325         // Browsing was canceled by user.
326         if (exportModel.nodes == null)
327             return;
328
329         // Setup selected states, select everything by default.
330         selectedNodes.clear();
331         selectedNodes.addAll(toBeSelected);
332
333         // Fully refresh node tree
334         nodeTree.setInput(exportModel.nodes);
335
336         modelSelector.removeSelectionListener(modelSelectorListener);
337         int selectedIndex = -1;
338         for (int i = 0; i < modelSelector.getItemCount(); ++i) {
339             Object obj = modelSelector.getData("" + i);
340             if (org.simantics.utils.ObjectUtils.objectEquals(obj, modelSelection)) {
341                 selectedIndex = i;
342             }
343         }
344         if (selectedIndex == -1 && modelSelector.getItemCount() > 0)
345             selectedIndex = 0;
346         if (selectedIndex != -1)
347             modelSelector.select(selectedIndex);
348         modelSelector.addSelectionListener(modelSelectorListener);
349
350         validatePage();
351     }
352
353     void validatePage() {
354         int diagramCount = 0;
355         Node singleDiagram = null;
356         for (Node n : selectedNodes)
357             if (n.getDiagramResource() != null) {
358                 ++diagramCount;
359                 singleDiagram = n;
360             }
361
362         //System.out.println("VALIDATE PAGE: " + exportLocationTouchedByUser);
363         if (diagramCount == 0) {
364             setMessage("Select the diagrams to export.");
365             setErrorMessage(null);
366             setPageComplete(false);
367             return;
368         }
369
370         if (!exportLocationTouchedByUser) {
371             String generatedName = null;
372             // Generate file name automatically if user hasn't touched the name manually.
373             NamedResource nr = getSelectedModel();
374             if (nr != null) {
375                 if (diagramCount == 1 && singleDiagram != null) {
376                     generatedName = nr.getName() + "-" + singleDiagram.getName();
377                 } else {
378                     generatedName = nr.getName();
379                 }
380             }
381             //System.out.println("generate name: " + generatedName);
382             if (generatedName != null) {
383                 if (!FileUtils.isValidFileName(generatedName))
384                     generatedName = (String) Bindings.STR_VARIANT.createUnchecked(Bindings.STRING, generatedName);
385                 String name = generatedName + ".pdf";
386                 
387                 abu:
388                 if ( !exportModel.recentLocations.isEmpty() ) {
389                         
390                         for ( String loc : exportModel.recentLocations )
391                         {
392                                 if ( loc.endsWith(name) && !loc.equals(name) ) {
393                                         name = loc;
394                                         break abu; 
395                                 }
396                         }
397                         
398                         String firstLine = exportModel.recentLocations.iterator().next();
399                         File f = new File(firstLine);    
400                         File parentFile = f.getParentFile();
401                         if ( parentFile!=null ) {
402                                 name = new File( f.getParentFile(), name ).getAbsolutePath();
403                         }
404                 }
405                 setExportLocationWithoutNotification(name);
406             }
407         }
408
409         String exportLoc = exportLocation.getText();
410         if (exportLoc.isEmpty()) {
411             setMessage("Select an export target file.");
412             setErrorMessage(null);
413             setPageComplete(false);
414             return;
415         }
416         File file = new File(exportLoc);
417         if (file.exists()) {
418             if (file.isDirectory()) {
419                 setErrorMessage("The target already exists and it is a directory.");
420                 setPageComplete(false);
421                 return;
422             }
423             if (!file.isFile()) {
424                 setErrorMessage("The target already exists and it is a not a regular file.");
425                 setPageComplete(false);
426                 return;
427             }
428         }
429         exportModel.exportLocation = file;
430
431         String msg = diagramCount + " diagrams selected for export.";
432
433         setMessage(msg);
434         setErrorMessage(null);
435         setPageComplete(true);
436     }
437
438 }