1 package org.simantics.export.ui;
\r
3 import java.net.MalformedURLException;
\r
5 import java.util.ArrayList;
\r
6 import java.util.Collection;
\r
7 import java.util.Collections;
\r
8 import java.util.Comparator;
\r
9 import java.util.HashMap;
\r
10 import java.util.HashSet;
\r
11 import java.util.List;
\r
12 import java.util.Map;
\r
13 import java.util.Set;
\r
14 import java.util.TreeMap;
\r
16 import org.eclipse.jface.resource.ImageDescriptor;
\r
17 import org.eclipse.jface.resource.JFaceResources;
\r
18 import org.eclipse.jface.resource.LocalResourceManager;
\r
19 import org.eclipse.jface.wizard.WizardPage;
\r
20 import org.eclipse.nebula.widgets.grid.Grid;
\r
21 import org.eclipse.nebula.widgets.grid.GridColumn;
\r
22 import org.eclipse.nebula.widgets.grid.GridItem;
\r
23 import org.eclipse.swt.SWT;
\r
24 import org.eclipse.swt.events.SelectionAdapter;
\r
25 import org.eclipse.swt.events.SelectionEvent;
\r
26 import org.eclipse.swt.events.SelectionListener;
\r
27 import org.eclipse.swt.graphics.Color;
\r
28 import org.eclipse.swt.graphics.Image;
\r
29 import org.eclipse.swt.graphics.RGB;
\r
30 import org.eclipse.swt.widgets.Composite;
\r
31 import org.simantics.db.exception.DatabaseException;
\r
32 import org.simantics.export.core.ExportContext;
\r
33 import org.simantics.export.core.error.ExportException;
\r
34 import org.simantics.export.core.intf.ContentType;
\r
35 import org.simantics.export.core.intf.Discoverer;
\r
36 import org.simantics.export.core.intf.Exporter;
\r
37 import org.simantics.export.core.intf.Format;
\r
38 import org.simantics.export.core.intf.Publisher;
\r
39 import org.simantics.export.core.manager.Content;
\r
40 import org.simantics.export.core.manager.ExportWizardResult;
\r
41 import org.simantics.export.core.util.ExportQueries;
\r
42 import org.simantics.export.ui.util.ExportUIQueries;
\r
43 import org.simantics.utils.datastructures.MapList;
\r
44 import org.simantics.utils.datastructures.ToStringComparator;
\r
45 import org.simantics.utils.strings.AlphanumComparator;
\r
46 import org.simantics.utils.ui.workbench.StringMemento;
\r
49 * Show wizard page where content and export format is selected.
\r
51 * @author toni.kalajainen@semantum.fi
\r
53 public class ContentSelectionPage extends WizardPage {
\r
55 /** Key for preference setting that contains sub-mementos for each content URI. */
\r
56 public static final String KEY_FORMAT_SELECTIONS = "org.simantics.modeling.ui.export.wizard.formatSelections";
\r
59 LocalResourceManager resourceManager;
\r
64 // Hash-code for the initial data
\r
65 String initialSelectionKey;
\r
66 Set<Content> initialSelection = new HashSet<Content>();
\r
68 // Previous selections
\r
69 StringMemento formatSelections;
\r
72 Collection<String> allModels, selectedModels;
\r
73 ToStringComparator toStringComparator = new ToStringComparator();
\r
74 MapList<ContentType, String> content; // ContentType -> Content[]
\r
75 MapList<ContentType, Format> typeToFormatMap; // ContentType -> Format
\r
76 MapList<String, ContentType> contentToTypeMap; // uri -> ContentType
\r
77 Map<String, Map<String, String>> labels; // ContentType -> URI -> Label
\r
78 MapList<String, String> modelContent; // ModelURI -> ContentURI
\r
81 List<Content> contentSelection = new ArrayList<Content>();
\r
83 public ContentSelectionPage(ExportContext ctx) throws ExportException {
\r
84 super("Select Content", "Select the PDF Pages and the attachments", null);
\r
90 void init() throws ExportException {
\r
92 System.out.println("Found Content Types:");
\r
93 for ( ContentType ct : ctx.eep.contentTypes() ) {
\r
94 System.out.println(" "+ct);
\r
96 System.out.println();
\r
98 System.out.println("Exporters:");
\r
99 for ( Exporter ex : ctx.eep.exporters() ) {
\r
100 System.out.println(" "+ex);
\r
102 System.out.println();
\r
104 System.out.println("Formats:");
\r
105 for ( Format format : ctx.eep.formats() ) {
\r
106 System.out.println(" "+format);
\r
108 System.out.println();
\r
110 System.out.println("Discoverers:");
\r
111 for ( Discoverer discoverer : ctx.eep.discoverers() ) {
\r
112 System.out.println(" "+discoverer);
\r
114 System.out.println();
\r
116 System.out.println("Publishers:");
\r
117 for ( Publisher publisher : ctx.eep.publishers() ) {
\r
118 System.out.println(" "+publisher.id());
\r
120 System.out.println();
\r
122 // Organize formats by content types - Filter out ContentTypes that don't have exporter and format.
\r
123 System.out.println("Mapped ContentTypes to Exporters:");
\r
124 typeToFormatMap = MapList.use( new TreeMap<ContentType, List<Format>>(toStringComparator) );
\r
125 for ( ContentType ct : ctx.eep.contentTypes() ) {
\r
126 for ( Exporter exp : ctx.eep.getExportersForContentType( ct.id() ) ) {
\r
127 Format format = ctx.eep.getFormat( exp.formatId() );
\r
128 if ( format==null ) continue;
\r
129 System.out.println(" "+ct.id()+" -> "+format.fileext());
\r
130 if (!typeToFormatMap.contains(ct, format)) typeToFormatMap.add(ct, format);
\r
133 System.out.println();
\r
135 // Discover the models in the project
\r
136 allModels = ctx.session.syncRequest( ExportUIQueries.models(ctx.project) );
\r
138 // Calculate hash for the initial selection
\r
139 int initialContentHash = 0x52f3a45;
\r
140 for ( String content : ctx.selection ) {
\r
141 initialContentHash = 13*initialContentHash + content.hashCode();
\r
143 initialSelectionKey = "InitialSelection-"+initialContentHash;
\r
144 String sel = ctx.store.get(initialSelectionKey, null);
\r
145 if ( sel != null ) {
\r
146 initialSelection = ExportWizardResult.parse(sel);
\r
148 // First time wizard was called with this selection.
\r
150 for ( String contentUri : ctx.selection ) {
\r
151 initialSelection.add( new Content(contentUri, null, "all", null, null, null) );
\r
155 // Choose the models from user interface selection
\r
156 selectedModels = new ArrayList<String>();
\r
157 StringBuilder modelsStr = new StringBuilder();
\r
158 for ( String content : ctx.selection ) {
\r
159 for ( String model : allModels ) {
\r
160 if ( content.equals(model) || content.startsWith(model + "/") ) {
\r
161 if ( !selectedModels.contains( model ) ) {
\r
162 selectedModels.add( model );
\r
163 if ( modelsStr.length()>0 ) modelsStr.append(", ");
\r
164 modelsStr.append( model );
\r
169 // If user has nothing selected, choose active models
\r
170 if ( selectedModels.isEmpty() ) selectedModels.addAll( ctx.activeModels );
\r
171 // If there are no active models, choose all models
\r
172 if ( selectedModels.isEmpty() ) selectedModels.addAll( allModels );
\r
174 labels = new HashMap<String, Map<String, String>>();
\r
175 labels.put( "model", ctx.session.syncRequest( ExportQueries.labels( selectedModels ) ) ); // Should Model CT be used for labeling?
\r
177 // Discover contents
\r
178 System.out.println("Discovering content: "+modelsStr);
\r
179 content = MapList.use( new TreeMap<ContentType, List<String>>(toStringComparator) );
\r
180 contentToTypeMap = MapList.use( new TreeMap<String, List<ContentType>>(toStringComparator) );
\r
181 modelContent = MapList.use( new TreeMap<String, List<String>>() );
\r
183 for ( ContentType ct : typeToFormatMap.getKeys() ) {
\r
184 System.out.println(" "+ct.label());
\r
185 for ( Discoverer discoverer : ctx.eep.getDiscoverers( ct.id() )) {
\r
186 System.out.println(" "+discoverer.toString());
\r
188 // Get content Uris
\r
189 Collection<String> contents = discoverer.discoverContent(ctx, selectedModels);
\r
190 List<String> contentUris = new ArrayList<String>( contents );
\r
193 Map<String, String> lbls = ct.getLabels(ctx, contentUris);
\r
194 labels.put( ct.id(), lbls );
\r
197 IndirectComparator comp = new IndirectComparator();
\r
198 comp.labels = lbls;
\r
199 Collections.sort( contentUris, comp );
\r
201 for ( String contentId : contentUris ) {
\r
202 content.add( ct, contentId );
\r
203 contentToTypeMap.add(contentId, ct);
\r
204 //modelContent.add(key)
\r
205 System.out.println(" "+contentId);
\r
210 System.out.println();
\r
213 } catch (DatabaseException e) {
\r
214 throw new ExportException(e);
\r
221 public void createControl(Composite parent) {
\r
222 grid = new Grid(parent, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI);
\r
223 grid.setHeaderVisible(true);
\r
225 resourceManager = new LocalResourceManager(JFaceResources.getResources(), grid);
\r
226 Color contentTypeColor = resourceManager.createColor( new RGB(245, 245, 252) );
\r
227 GridColumn column = new GridColumn(grid,SWT.NONE);
\r
228 column.setTree(true);
\r
229 column.setText("Name");
\r
230 column.setWidth(200);
\r
233 assertColumnIndex(1);
\r
235 Format pdfFormat = ctx.eep.getFormat("pdf");
\r
238 ImageDescriptor folderID = null;
\r
240 URL folderUrl = new URL("platform:/plugin/com.famfamfam.silk/icons/folder.png");
\r
241 folderID = ImageDescriptor.createFromURL( folderUrl );
\r
242 } catch (MalformedURLException e) {
\r
243 e.printStackTrace();
\r
246 List<GridItem> selectedNodes = new ArrayList<GridItem>();
\r
248 // Iterate all models
\r
249 for ( String modelUri : contentToTypeMap.getKeys() ) {
\r
250 ContentType modelContentType = null;
\r
251 for ( ContentType ct : contentToTypeMap.getValues(modelUri) ) {
\r
252 if ( ct.isModel() ) {
\r
253 modelContentType = ct;
\r
257 if (modelContentType==null) continue;
\r
259 // Create Model Node
\r
260 String modelLabel = labels.get("model").get(modelUri);
\r
261 GridItem modelNode = newLine(grid, modelLabel, modelUri, modelContentType.id());
\r
262 setIcon(modelNode, 0, modelContentType.icon(modelUri));
\r
263 modelNode.setToolTipText(0, modelUri);
\r
265 if ( ctx.selection.contains( modelUri ) ) selectedNodes.add( modelNode );
\r
267 // Columns for formats
\r
269 for ( ContentType ct : contentToTypeMap.getValues(modelUri) ) {
\r
270 for ( Format format : typeToFormatMap.getValues(ct) ) {
\r
272 assertColumnIndex( column1 );
\r
273 modelNode.setText(column1, format.fileext());
\r
274 modelNode.setGrayed(column1, false);
\r
275 modelNode.setCheckable(column1, true);
\r
276 modelNode.setData( Integer.toString(column1),
\r
277 new Content(modelUri, ct.id(), format.id(), modelLabel, format.fileext(), modelUri ) );
\r
278 modelNode.setChecked(column1, hasInitialSelection(modelUri, format.id()));
\r
279 modelNode.setToolTipText(column1, format.label());
\r
281 ImageDescriptor id = format.icon();
\r
283 Image icon = resourceManager.createImage(id);
\r
284 if ( icon!=null) modelNode.setImage(column1, icon);
\r
289 for ( ContentType ct : content.getKeys() )
\r
291 if ( ct.isModel() ) continue;
\r
292 // ContentType Node
\r
293 GridItem ctNode = newLine(modelNode, ct.label(), modelUri, ct.id());
\r
294 ctNode.setExpanded( true );
\r
295 ctNode.setBackground(0, contentTypeColor);
\r
296 ctNode.setBackground(contentTypeColor);
\r
297 setIcon(ctNode, 0, folderID);
\r
298 int contentCount = 0;
\r
299 ArrayList<Format> contentTypesFormats = new ArrayList<Format>();
\r
301 for ( String contentUri : content.getValues(ct) ) {
\r
302 // WORKAROUND: Should not be based on URI
\r
303 if ( !contentUri.startsWith(modelUri) ) continue;
\r
305 String nodeLabel = labels.get(ct.id()).get(contentUri);
\r
306 GridItem contentNode = newLine(ctNode, nodeLabel, contentUri, ct.id());
\r
308 contentNode.setToolTipText(0, contentUri);
\r
309 setIcon(contentNode, 0, ct.icon(contentUri));
\r
311 if ( ctx.selection.contains( contentUri) ) selectedNodes.add( contentNode );
\r
313 int columnNumber = 0;
\r
316 List<Format> formats = typeToFormatMap.getValues(ct);
\r
317 if ( formats.contains( pdfFormat )) {
\r
318 if ( !contentTypesFormats.contains(pdfFormat) ) contentTypesFormats.add(pdfFormat);
\r
320 assertColumnIndex( columnNumber );
\r
322 contentNode.setText(columnNumber, " "+pdfFormat.fileext());
\r
323 contentNode.setGrayed(columnNumber, false);
\r
324 contentNode.setCheckable(columnNumber, true);
\r
325 contentNode.setChecked(columnNumber, hasInitialSelection(contentUri, pdfFormat.id()) );
\r
326 contentNode.setToolTipText(columnNumber, pdfFormat.label());
\r
327 setIcon(contentNode, columnNumber, pdfFormat.icon());
\r
329 contentNode.setData(
\r
330 Integer.toString(columnNumber),
\r
331 new Content(contentUri, ct.id(), pdfFormat.id(), nodeLabel, pdfFormat.fileext(), modelUri ) );
\r
334 if ( !contentTypesFormats.contains(null) ) contentTypesFormats.add(null);
\r
336 assertColumnIndex( columnNumber );
\r
339 // Attachment Columns
\r
340 for (Format format : formats ) {
\r
341 if ( format==pdfFormat ) continue;
\r
342 if ( !contentTypesFormats.contains(format) ) contentTypesFormats.add(format);
\r
344 assertColumnIndex( columnNumber );
\r
345 contentNode.setText(columnNumber, " "+format.fileext());
\r
346 contentNode.setGrayed(columnNumber, false);
\r
347 contentNode.setCheckable(columnNumber, true);
\r
348 contentNode.setChecked(columnNumber, hasInitialSelection(contentUri, format.id()) );
\r
349 contentNode.setToolTipText(columnNumber, format.label());
\r
350 setIcon(contentNode, columnNumber, format.icon());
\r
352 contentNode.setData(
\r
353 Integer.toString(columnNumber),
\r
354 new Content(contentUri, ct.id(), format.id(), nodeLabel, format.fileext(), modelUri ) );
\r
358 // Add the *.pdf buttons
\r
359 int columnNumber = 0;
\r
360 Set<GridItem> gis = new HashSet<GridItem>();
\r
361 for ( Format format : contentTypesFormats ) {
\r
363 ctNode.setBackground(columnNumber, contentTypeColor);
\r
364 if ( format == null ) continue;
\r
365 ctChecks.add( new CTCheck(ctNode, columnNumber, format) );
\r
366 ctNode.setCheckable(columnNumber, true);
\r
367 ctNode.setGrayed(columnNumber, true);
\r
368 //setIcon(ctNode, columnNumber, format.icon());
\r
370 //ctNode.setData(Integer.toString(columnNumber), format );
\r
371 //ctNode.setText(columnNumber, "*"+format.fileext());
\r
374 if ( contentCount == 0 ) {
\r
379 modelNode.setExpanded( true );
\r
381 grid.setSelection( selectedNodes.toArray( new GridItem[selectedNodes.size()] ) );
\r
382 if ( selectedNodes.size()>0 ) {
\r
383 GridItem first = selectedNodes.get(0);
\r
384 grid.setFocusItem( first );
\r
387 grid.addSelectionListener(ctChecksListener);
\r
389 grid.addSelectionListener( new SelectionAdapter() {
\r
390 public void widgetSelected(SelectionEvent e) {
\r
391 if ( e.item == null || e.item instanceof GridItem==false ) return;
\r
392 GridItem gi = (GridItem) e.item;
\r
393 GridColumn column = grid.getColumn( new Point(e.x, e.y) );
\r
394 if ( column == null ) return;
\r
395 int columnIndex = -1;
\r
396 int columnCount = grid.getColumnCount();
\r
397 for ( int i=0; i<columnCount; i++) {
\r
398 GridColumn gc = grid.getColumn(i);
\r
399 if ( gc == column ) {
\r
404 System.out.println(e.detail);
\r
405 System.out.println(e);
\r
406 System.out.println(columnIndex);
\r
407 String text = gi.getText(columnIndex);
\r
408 System.out.println(text);
\r
413 setPageComplete(true);
\r
416 void setIcon(GridItem node, int index, ImageDescriptor icon) {
\r
417 if ( icon == null ) return;
\r
418 Image image = resourceManager.createImage(icon);
\r
419 if ( image == null ) return;
\r
420 node.setImage(index, image);
\r
424 * Creates column index if doesn't exist.
\r
425 * Column=2, is "Pages"
\r
426 * Column>=3, is "Attachement"
\r
428 * @param columnIndex
\r
430 void assertColumnIndex(int columnIndex) {
\r
431 while ( columnIndex >= grid.getColumnCount() ) {
\r
432 int cc = grid.getColumnCount();
\r
434 GridColumn column = new GridColumn(grid, SWT.CHECK);
\r
435 column.setText( cc==1?"Pages":"Attachments");
\r
436 column.setWidth( cc==1?150:200 );
\r
438 for (GridItem gi : grid.getItems()) {
\r
439 gi.setGrayed(cc, true);
\r
440 gi.setCheckable(cc, false);
\r
446 boolean hasInitialSelection(String uri, String formatId) {
\r
447 for (Content c : initialSelection) {
\r
448 if ( !c.url.equals( uri ) ) continue;
\r
449 if ( c.formatId.equals("all") || c.formatId.equals(formatId) ) return true;
\r
454 GridItem newLine(Object parent, String label, String url, String contentTypeId) {
\r
455 GridItem gi = null;
\r
456 if (parent instanceof Grid) {
\r
457 gi = new GridItem( (Grid)parent, SWT.NONE);
\r
459 gi = new GridItem( (GridItem)parent, SWT.NONE);
\r
462 gi.setText( label );
\r
463 if ( url!=null || contentTypeId!=null ) gi.setData( new Content(url, contentTypeId, null, label, null, null) );
\r
464 for ( int columnIndex=0; columnIndex<grid.getColumnCount(); columnIndex++ ) {
\r
465 gi.setGrayed(columnIndex, true);
\r
466 gi.setCheckable(columnIndex, false);
\r
472 public void validatePage() {
\r
473 List<Content> newContentSelection = new ArrayList<Content>();
\r
474 // Get list of content.. something must be checked
\r
475 int columnWidth = grid.getColumnCount();
\r
476 Set<String> checkedFormats = new HashSet<String>();
\r
477 for (GridItem gi : grid.getItems()) {
\r
479 checkedFormats.clear();
\r
480 GridItem parentItem = gi.getParentItem();
\r
481 if ( parentItem!=null ) {
\r
482 for (int c=0; c<columnWidth; c++) {
\r
483 if ( parentItem.getChecked(c) ) {
\r
484 Object data = parentItem.getData( Integer.toString(c) );
\r
485 if ( data==null || data instanceof Format == false ) continue;
\r
486 Format format = (Format) data;
\r
487 checkedFormats.add( format.id() );
\r
492 for (int c=0; c<columnWidth; c++) {
\r
493 Object data = gi.getData( Integer.toString(c) );
\r
494 if ( data==null || data instanceof Content == false ) continue;
\r
495 Content content = (Content) data;
\r
496 if ( gi.getChecked(c) || checkedFormats.contains(content.formatId) ) {
\r
497 newContentSelection.add( content );
\r
503 contentSelection = newContentSelection;
\r
506 public List<Content> getContentSelection() {
\r
507 return contentSelection;
\r
510 public void savePrefs() {
\r
511 String str = ExportWizardResult.print( getContentSelection() );
\r
512 ctx.store.put(initialSelectionKey, str);
\r
515 static class IndirectComparator implements Comparator<String> {
\r
516 Map<String, String> labels;
\r
519 public int compare(String o1, String o2) {
\r
520 String l1 = null, l2 = null;
\r
521 if ( labels != null ) {
\r
522 l1 = labels.get(o1);
\r
523 l2 = labels.get(o2);
\r
525 if ( l1 == null ) l1 = o1;
\r
526 if ( l2 == null ) l2 = o2;
\r
527 return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(l1, l2);
\r
531 //// Code for following clicks on ContentType format specific checkboxes
\r
532 List<CTCheck> ctChecks = new ArrayList<CTCheck>();
\r
533 static class CTCheck {
\r
537 boolean lastKnownCheckedStatus = false;
\r
538 CTCheck(GridItem gi, int columnNumber, Format format) {
\r
540 this.columnNumber = columnNumber;
\r
541 this.format = format;
\r
543 boolean previousSelection;
\r
544 boolean checkStatus() {
\r
545 return gi.getChecked(columnNumber);
\r
547 void setCheck(boolean checked) {
\r
548 gi.setChecked(columnNumber, checked);
\r
552 SelectionListener ctChecksListener = new SelectionAdapter() {
\r
553 public void widgetSelected(SelectionEvent e) {
\r
554 if ( e.item == null || e.item instanceof GridItem==false ) return;
\r
555 int columnWidth = grid.getColumnCount();
\r
556 for ( CTCheck cc : ctChecks ) {
\r
557 boolean checked = cc.checkStatus();
\r
558 if ( checked == cc.lastKnownCheckedStatus ) continue;
\r
559 cc.lastKnownCheckedStatus = checked;
\r
561 for ( GridItem gi : cc.gi.getItems() ) {
\r
562 for ( int columnNumber = 0; columnNumber<columnWidth; columnNumber++ ) {
\r
563 Object data = gi.getData( Integer.toString( columnNumber ) );
\r
564 if ( data==null || data instanceof Content == false ) continue;
\r
565 Content content = (Content) data;
\r
566 if ( !content.formatId.equals( cc.format.id() )) continue;
\r
567 gi.setChecked(columnNumber, checked);
\r