package org.simantics.export.ui; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.resource.LocalResourceManager; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.nebula.widgets.grid.Grid; import org.eclipse.nebula.widgets.grid.GridColumn; import org.eclipse.nebula.widgets.grid.GridItem; import org.eclipse.swt.SWT; 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.graphics.Image; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Composite; import org.simantics.db.exception.DatabaseException; import org.simantics.export.core.ExportContext; import org.simantics.export.core.error.ExportException; import org.simantics.export.core.intf.ContentType; import org.simantics.export.core.intf.Discoverer; import org.simantics.export.core.intf.Exporter; import org.simantics.export.core.intf.Format; import org.simantics.export.core.intf.Publisher; import org.simantics.export.core.manager.Content; import org.simantics.export.core.manager.ExportWizardResult; import org.simantics.export.core.util.ExportQueries; import org.simantics.export.ui.util.ExportUIQueries; import org.simantics.utils.datastructures.MapList; import org.simantics.utils.datastructures.ToStringComparator; import org.simantics.utils.strings.AlphanumComparator; import org.simantics.utils.ui.workbench.StringMemento; /** * Show wizard page where content and export format is selected. * * @author toni.kalajainen@semantum.fi */ public class ContentSelectionPage extends WizardPage { /** Key for preference setting that contains sub-mementos for each content URI. */ public static final String KEY_FORMAT_SELECTIONS = "org.simantics.modeling.ui.export.wizard.formatSelections"; //$NON-NLS-1$ // UI stuff LocalResourceManager resourceManager; Grid grid; // Initial data ExportContext ctx; // Hash-code for the initial data String initialSelectionKey; Set initialSelection = new HashSet(); // Previous selections StringMemento formatSelections; // Initializations Collection allModels, selectedModels; ToStringComparator toStringComparator = new ToStringComparator(); MapList content; // ContentType -> Content[] MapList typeToFormatMap; // ContentType -> Format MapList contentToTypeMap; // uri -> ContentType Map> labels; // ContentType -> URI -> Label MapList modelContent; // ModelURI -> ContentURI // User selections List contentSelection = new ArrayList(); public ContentSelectionPage(ExportContext ctx) throws ExportException { super(Messages.ContentSelectionPage_SelectContent, Messages.ContentSelectionPage_SelectContentDescription, null); this.ctx = ctx; init(); } void init() throws ExportException { try { System.out.println("Found Content Types:"); //$NON-NLS-1$ for ( ContentType ct : ctx.eep.contentTypes() ) { System.out.println(" "+ct); //$NON-NLS-1$ } System.out.println(); System.out.println("Exporters:"); //$NON-NLS-1$ for ( Exporter ex : ctx.eep.exporters() ) { System.out.println(" "+ex); //$NON-NLS-1$ } System.out.println(); System.out.println("Formats:"); //$NON-NLS-1$ for ( Format format : ctx.eep.formats() ) { System.out.println(" "+format); //$NON-NLS-1$ } System.out.println(); System.out.println("Discoverers:"); //$NON-NLS-1$ for ( Discoverer discoverer : ctx.eep.discoverers() ) { System.out.println(" "+discoverer); //$NON-NLS-1$ } System.out.println(); System.out.println("Publishers:"); //$NON-NLS-1$ for ( Publisher publisher : ctx.eep.publishers() ) { System.out.println(" "+publisher.id()); //$NON-NLS-1$ } System.out.println(); // Organize formats by content types - Filter out ContentTypes that don't have exporter and format. System.out.println("Mapped ContentTypes to Exporters:"); //$NON-NLS-1$ typeToFormatMap = MapList.use( new TreeMap>(toStringComparator) ); for ( ContentType ct : ctx.eep.contentTypes() ) { for ( Exporter exp : ctx.eep.getExportersForContentType( ct.id() ) ) { Format format = ctx.eep.getFormat( exp.formatId() ); if ( format==null ) continue; System.out.println(" "+ct.id()+" -> "+format.fileext()); //$NON-NLS-1$ //$NON-NLS-2$ if (!typeToFormatMap.contains(ct, format)) typeToFormatMap.add(ct, format); } } System.out.println(); // Discover the models in the project allModels = ctx.session.syncRequest( ExportUIQueries.models(ctx.project) ); // Calculate hash for the initial selection int initialContentHash = 0x52f3a45; for ( String content : ctx.selection ) { initialContentHash = 13*initialContentHash + content.hashCode(); } initialSelectionKey = "InitialSelection-"+initialContentHash; //$NON-NLS-1$ String sel = ctx.store.get(initialSelectionKey, null); if ( sel != null ) { initialSelection = ExportWizardResult.parse(sel); } else { // First time wizard was called with this selection. // Check in for ( String contentUri : ctx.selection ) { initialSelection.add( new Content(contentUri, null, "all", null, null, null) ); //$NON-NLS-1$ } } // Choose the models from user interface selection selectedModels = new ArrayList(); StringBuilder modelsStr = new StringBuilder(); for ( String content : ctx.selection ) { for ( String model : allModels ) { if ( content.equals(model) || content.startsWith(model + "/") ) { //$NON-NLS-1$ if ( !selectedModels.contains( model ) ) { selectedModels.add( model ); if ( modelsStr.length()>0 ) modelsStr.append(", "); //$NON-NLS-1$ modelsStr.append( model ); } } } } // If user has nothing selected, choose active models if ( selectedModels.isEmpty() ) selectedModels.addAll( ctx.activeModels ); // If there are no active models, choose all models if ( selectedModels.isEmpty() ) selectedModels.addAll( allModels ); // UI labels labels = new HashMap>(); labels.put( "model", ctx.session.syncRequest( ExportQueries.labels( selectedModels ) ) ); // Should Model CT be used for labeling? //$NON-NLS-1$ // Discover contents System.out.println("Discovering content: "+modelsStr); //$NON-NLS-1$ content = MapList.use( new TreeMap>(toStringComparator) ); contentToTypeMap = MapList.use( new TreeMap>(toStringComparator) ); modelContent = MapList.use( new TreeMap>() ); for ( ContentType ct : typeToFormatMap.getKeys() ) { System.out.println(" "+ct.label()); //$NON-NLS-1$ for ( Discoverer discoverer : ctx.eep.getDiscoverers( ct.id() )) { System.out.println(" "+discoverer.toString()); //$NON-NLS-1$ // Get content Uris Collection contents = discoverer.discoverContent(ctx, selectedModels); List contentUris = new ArrayList( contents ); // Get UI Labels Map lbls = ct.getLabels(ctx, contentUris); labels.put( ct.id(), lbls ); // Sort content IndirectComparator comp = new IndirectComparator(); comp.labels = lbls; Collections.sort( contentUris, comp ); for ( String contentId : contentUris ) { content.add( ct, contentId ); contentToTypeMap.add(contentId, ct); //modelContent.add(key) System.out.println(" "+contentId); //$NON-NLS-1$ } } } System.out.println(); } catch (DatabaseException e) { throw new ExportException(e); } } @Override public void createControl(Composite parent) { grid = new Grid(parent, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI); grid.setHeaderVisible(true); resourceManager = new LocalResourceManager(JFaceResources.getResources(), grid); Color contentTypeColor = resourceManager.createColor( new RGB(245, 245, 252) ); GridColumn column = new GridColumn(grid,SWT.NONE); column.setTree(true); column.setText(Messages.ContentSelectionPage_Name); column.setWidth(200); // "Pagees" assertColumnIndex(1); Format pdfFormat = ctx.eep.getFormat("pdf"); //$NON-NLS-1$ ImageDescriptor folderID = null; try { URL folderUrl = new URL("platform:/plugin/com.famfamfam.silk/icons/folder.png"); //$NON-NLS-1$ folderID = ImageDescriptor.createFromURL( folderUrl ); } catch (MalformedURLException e) { e.printStackTrace(); } List selectedNodes = new ArrayList(); // Iterate all models for ( String modelUri : contentToTypeMap.getKeys() ) { ContentType modelContentType = null; for ( ContentType ct : contentToTypeMap.getValues(modelUri) ) { if ( ct.isModel() ) { modelContentType = ct; break; } } if (modelContentType==null) continue; // Create Model Node String modelLabel = labels.get("model").get(modelUri); //$NON-NLS-1$ GridItem modelNode = newLine(grid, modelLabel, modelUri, modelContentType.id()); setIcon(modelNode, 0, modelContentType.icon(modelUri)); modelNode.setToolTipText(0, modelUri); if ( ctx.selection.contains( modelUri ) ) selectedNodes.add( modelNode ); // Columns for formats int column1 = 1; for ( ContentType ct : contentToTypeMap.getValues(modelUri) ) { for ( Format format : typeToFormatMap.getValues(ct) ) { column1++; assertColumnIndex( column1 ); modelNode.setText(column1, format.fileext()); modelNode.setGrayed(column1, false); modelNode.setCheckable(column1, true); modelNode.setData( Integer.toString(column1), new Content(modelUri, ct.id(), format.id(), modelLabel, format.fileext(), modelUri ) ); modelNode.setChecked(column1, hasInitialSelection(modelUri, format.id())); modelNode.setToolTipText(column1, format.label()); ImageDescriptor id = format.icon(); if ( id!=null ) { Image icon = resourceManager.createImage(id); if ( icon!=null) modelNode.setImage(column1, icon); } } } for ( ContentType ct : content.getKeys() ) { if ( ct.isModel() ) continue; // ContentType Node GridItem ctNode = newLine(modelNode, ct.label(), modelUri, ct.id()); ctNode.setExpanded( true ); ctNode.setBackground(0, contentTypeColor); ctNode.setBackground(contentTypeColor); setIcon(ctNode, 0, folderID); int contentCount = 0; ArrayList contentTypesFormats = new ArrayList(); for ( String contentUri : content.getValues(ct) ) { // WORKAROUND: Should not be based on URI if ( !contentUri.startsWith(modelUri) ) continue; // Content Node String nodeLabel = labels.get(ct.id()).get(contentUri); GridItem contentNode = newLine(ctNode, nodeLabel, contentUri, ct.id()); contentCount++; contentNode.setToolTipText(0, contentUri); setIcon(contentNode, 0, ct.icon(contentUri)); if ( ctx.selection.contains( contentUri) ) selectedNodes.add( contentNode ); int columnNumber = 0; // PDF Column List formats = typeToFormatMap.getValues(ct); if ( formats.contains( pdfFormat )) { if ( !contentTypesFormats.contains(pdfFormat) ) contentTypesFormats.add(pdfFormat); columnNumber++; assertColumnIndex( columnNumber ); contentNode.setText(columnNumber, " "+pdfFormat.fileext()); //$NON-NLS-1$ contentNode.setGrayed(columnNumber, false); contentNode.setCheckable(columnNumber, true); contentNode.setChecked(columnNumber, hasInitialSelection(contentUri, pdfFormat.id()) ); contentNode.setToolTipText(columnNumber, pdfFormat.label()); setIcon(contentNode, columnNumber, pdfFormat.icon()); contentNode.setData( Integer.toString(columnNumber), new Content(contentUri, ct.id(), pdfFormat.id(), nodeLabel, pdfFormat.fileext(), modelUri ) ); } else { if ( !contentTypesFormats.contains(null) ) contentTypesFormats.add(null); columnNumber++; assertColumnIndex( columnNumber ); } // Attachment Columns for (Format format : formats ) { if ( format==pdfFormat ) continue; if ( !contentTypesFormats.contains(format) ) contentTypesFormats.add(format); columnNumber++; assertColumnIndex( columnNumber ); contentNode.setText(columnNumber, " "+format.fileext()); //$NON-NLS-1$ contentNode.setGrayed(columnNumber, false); contentNode.setCheckable(columnNumber, true); contentNode.setChecked(columnNumber, hasInitialSelection(contentUri, format.id()) ); contentNode.setToolTipText(columnNumber, format.label()); setIcon(contentNode, columnNumber, format.icon()); contentNode.setData( Integer.toString(columnNumber), new Content(contentUri, ct.id(), format.id(), nodeLabel, format.fileext(), modelUri ) ); } } // Add the *.pdf buttons int columnNumber = 0; Set gis = new HashSet(); for ( Format format : contentTypesFormats ) { columnNumber++; ctNode.setBackground(columnNumber, contentTypeColor); if ( format == null ) continue; ctChecks.add( new CTCheck(ctNode, columnNumber, format) ); ctNode.setCheckable(columnNumber, true); ctNode.setGrayed(columnNumber, true); //setIcon(ctNode, columnNumber, format.icon()); gis.add(ctNode); //ctNode.setData(Integer.toString(columnNumber), format ); //ctNode.setText(columnNumber, "*"+format.fileext()); } if ( contentCount == 0 ) { ctNode.dispose(); } } modelNode.setExpanded( true ); } grid.setSelection( selectedNodes.toArray( new GridItem[selectedNodes.size()] ) ); if ( selectedNodes.size()>0 ) { GridItem first = selectedNodes.get(0); grid.setFocusItem( first ); } grid.addSelectionListener(ctChecksListener); /* grid.addSelectionListener( new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { if ( e.item == null || e.item instanceof GridItem==false ) return; GridItem gi = (GridItem) e.item; GridColumn column = grid.getColumn( new Point(e.x, e.y) ); if ( column == null ) return; int columnIndex = -1; int columnCount = grid.getColumnCount(); for ( int i=0; i=3, is "Attachement" * * @param columnIndex */ void assertColumnIndex(int columnIndex) { while ( columnIndex >= grid.getColumnCount() ) { int cc = grid.getColumnCount(); GridColumn column = new GridColumn(grid, SWT.CHECK); column.setText( cc==1?Messages.ContentSelectionPage_Pages:Messages.ContentSelectionPage_Attachments); column.setWidth( cc==1?150:200 ); for (GridItem gi : grid.getItems()) { gi.setGrayed(cc, true); gi.setCheckable(cc, false); } } } boolean hasInitialSelection(String uri, String formatId) { for (Content c : initialSelection) { if ( !c.url.equals( uri ) ) continue; if ( c.formatId.equals("all") || c.formatId.equals(formatId) ) return true; //$NON-NLS-1$ } return false; } GridItem newLine(Object parent, String label, String url, String contentTypeId) { GridItem gi = null; if (parent instanceof Grid) { gi = new GridItem( (Grid)parent, SWT.NONE); } else { gi = new GridItem( (GridItem)parent, SWT.NONE); } gi.setText( label ); if ( url!=null || contentTypeId!=null ) gi.setData( new Content(url, contentTypeId, null, label, null, null) ); for ( int columnIndex=0; columnIndex newContentSelection = new ArrayList(); // Get list of content.. something must be checked int columnWidth = grid.getColumnCount(); Set checkedFormats = new HashSet(); for (GridItem gi : grid.getItems()) { /* checkedFormats.clear(); GridItem parentItem = gi.getParentItem(); if ( parentItem!=null ) { for (int c=0; c getContentSelection() { return contentSelection; } public void savePrefs() { String str = ExportWizardResult.print( getContentSelection() ); ctx.store.put(initialSelectionKey, str); } static class IndirectComparator implements Comparator { Map labels; @Override public int compare(String o1, String o2) { String l1 = null, l2 = null; if ( labels != null ) { l1 = labels.get(o1); l2 = labels.get(o2); } if ( l1 == null ) l1 = o1; if ( l2 == null ) l2 = o2; return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(l1, l2); } } //// Code for following clicks on ContentType format specific checkboxes List ctChecks = new ArrayList(); static class CTCheck { GridItem gi; int columnNumber; Format format; boolean lastKnownCheckedStatus = false; CTCheck(GridItem gi, int columnNumber, Format format) { this.gi = gi; this.columnNumber = columnNumber; this.format = format; } boolean previousSelection; boolean checkStatus() { return gi.getChecked(columnNumber); } void setCheck(boolean checked) { gi.setChecked(columnNumber, checked); } } SelectionListener ctChecksListener = new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { if ( e.item == null || e.item instanceof GridItem==false ) return; int columnWidth = grid.getColumnCount(); for ( CTCheck cc : ctChecks ) { boolean checked = cc.checkStatus(); if ( checked == cc.lastKnownCheckedStatus ) continue; cc.lastKnownCheckedStatus = checked; for ( GridItem gi : cc.gi.getItems() ) { for ( int columnNumber = 0; columnNumber