]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.export.ui/src/org/simantics/export/ui/OptionsPage.java
9d2cea02042eb8432d75f52c03c1a08323a57dce
[simantics/platform.git] / bundles / org.simantics.export.ui / src / org / simantics / export / ui / OptionsPage.java
1 package org.simantics.export.ui;
2
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.List;
6 import java.util.Map;
7 import java.util.Set;
8 import java.util.TreeMap;
9 import java.util.TreeSet;
10 import java.util.regex.Matcher;
11 import java.util.regex.Pattern;
12
13 import org.eclipse.jface.wizard.WizardPage;
14 import org.eclipse.swt.SWT;
15 import org.eclipse.swt.custom.ScrolledComposite;
16 import org.eclipse.swt.layout.GridData;
17 import org.eclipse.swt.layout.GridLayout;
18 import org.eclipse.swt.widgets.Combo;
19 import org.eclipse.swt.widgets.Composite;
20 import org.eclipse.swt.widgets.Control;
21 import org.eclipse.swt.widgets.Event;
22 import org.eclipse.swt.widgets.Listener;
23 import org.osgi.service.prefs.BackingStoreException;
24 import org.osgi.service.prefs.Preferences;
25 import org.simantics.databoard.Accessors;
26 import org.simantics.databoard.Bindings;
27 import org.simantics.databoard.Datatypes;
28 import org.simantics.databoard.accessor.RecordAccessor;
29 import org.simantics.databoard.accessor.error.AccessorConstructionException;
30 import org.simantics.databoard.accessor.error.AccessorException;
31 import org.simantics.databoard.accessor.reference.ChildReference;
32 import org.simantics.databoard.accessor.reference.LabelReference;
33 import org.simantics.databoard.binding.RecordBinding;
34 import org.simantics.databoard.binding.error.BindingException;
35 import org.simantics.databoard.binding.error.DatatypeConstructionException;
36 import org.simantics.databoard.binding.error.RuntimeBindingException;
37 import org.simantics.databoard.binding.mutable.Variant;
38 import org.simantics.databoard.forms.DataboardForm;
39 import org.simantics.databoard.forms.DataboardForm.Problem;
40 import org.simantics.databoard.type.RecordType;
41 import org.simantics.databoard.type.UnionType;
42 import org.simantics.export.core.ExportContext;
43 import org.simantics.export.core.error.ExportException;
44 import org.simantics.export.core.intf.ContentType;
45 import org.simantics.export.core.intf.Exporter;
46 import org.simantics.export.core.intf.Format;
47 import org.simantics.export.core.intf.Publisher;
48 import org.simantics.export.core.manager.Content;
49 import org.simantics.export.core.manager.ExportAction;
50 import org.simantics.export.core.manager.ExportManager;
51 import org.simantics.export.core.manager.ExportPlan;
52 import org.simantics.export.core.manager.ExportWizardResult;
53 import org.simantics.export.core.util.ExporterUtils;
54 import org.simantics.utils.datastructures.Arrays;
55 import org.simantics.utils.datastructures.MapList;
56 import org.simantics.utils.datastructures.ToStringComparator;
57 import org.simantics.utils.datastructures.collections.CollectionUtils;
58 import org.simantics.utils.ui.ExceptionUtils;
59 import org.simantics.utils.ui.dialogs.ShowMessage;
60
61 /**
62  * Dynamic Options page. Exporter, Importer and Format contributes options to this page. 
63  *  
64  * @author toni.kalajainen@semantum.fi
65  */
66 public class OptionsPage extends WizardPage {
67
68         public static String S_OUTPUT_OPTIONS = "Output Options";
69         public static LabelReference P_OUTPUT_OPTIONS = new LabelReference( S_OUTPUT_OPTIONS );
70         
71         /** A reference to combo box selection */
72         public static String S_PUBLISH = "Publish to";
73         public static ChildReference P_PUBLISH = ChildReference.compile(P_OUTPUT_OPTIONS, new LabelReference(S_PUBLISH));
74         
75         ExportContext ctx; 
76         
77         ScrolledComposite scroll;
78         Composite composite;
79         DataboardForm form;
80
81         List<Content> selection;
82         int selectionHash;
83         String selectedPublisherId;
84         
85         public OptionsPage(ExportContext ctx) throws ExportException {
86                 super("Options page", "Select export options", null);
87                 
88                 this.ctx = ctx;
89         }
90
91         Listener modificationListener = new Listener() {                
92                 public void handleEvent(Event event) {
93                         if ( updatingForm ) return;
94                         validate();
95                 }
96         };
97         
98         boolean updatingForm;
99         Listener outputSettingsModifiedListener = new Listener() {              
100                 public void handleEvent(Event event) {
101                         updatingForm = true;
102                         try {
103                                 Preferences contentScopePrefs = ctx.store.node( "Selection-"+selectionHash );
104                                 Preferences workspaceScopePrefs = ctx.store;
105                                 
106                                 Composite outputOptions = (Composite) form.getControl(composite, P_OUTPUT_OPTIONS);
107                                 Combo publishTo = (Combo) form.getControl(composite, P_PUBLISH);                        
108                                 String newPublisherLabel = publishTo.getText();
109                                 Publisher newPublisher = ctx.eep.getPublisherByLabel(newPublisherLabel);
110                                 String newPublisherId = newPublisher==null?null:newPublisher.id();
111                                 //if ( newPublisherId.equals(selectedPublisherId) ) return;
112                                 
113                                 // Save Preferences
114                                 RecordBinding binding = ctx.databoard.getMutableBinding( form.type() );
115                                 Object obj = binding.createDefault();
116                                 form.readFields(composite, binding, obj);
117                                 Variant options = new Variant(binding, obj);
118                                 
119                                 Publisher oldPublisher = ctx.eep.getPublisher( selectedPublisherId );
120                                 if ( oldPublisher!=null ) {
121                                         ChildReference oldOptionsRef = new LabelReference( oldPublisher.label() );
122                                         try {
123                                                 Variant locationOptions = options.getComponent( oldOptionsRef );
124                                                 oldPublisher.publisherClass().savePref(locationOptions, contentScopePrefs, workspaceScopePrefs);
125                                         } catch ( AccessorConstructionException ee ) {}
126                                 }
127
128                                 List<Content> manifest = getManifestFor(selection, options);
129                                 cleanPublisherFromGroup(selectedPublisherId);
130                                 addPublisherToGroup(newPublisherId, manifest);
131                                 
132                                 outputOptions.pack(true);
133                                 outputOptions.layout(true);
134                                 composite.pack(true);
135                                 composite.layout(true);
136                                 
137                                 RecordType dummy = new RecordType();
138                                 RecordType newPublisherOptions = newPublisher.publisherClass().locationOptions(ctx, manifest);
139                                 dummy.addComponent( newPublisherLabel, newPublisherOptions );
140                                 binding = ctx.databoard.getMutableBinding( dummy );
141                                 obj = binding.createDefault();
142                                 options = new Variant(binding, obj);
143                                 ChildReference locationOptionsRef = new LabelReference( newPublisherLabel );
144                                 Variant locationOptions = options.getComponent( locationOptionsRef );
145                                 newPublisher.publisherClass().fillDefaultPrefs(ctx, selection, options, locationOptions);
146                                 newPublisher.publisherClass().loadPref(locationOptions, contentScopePrefs, workspaceScopePrefs);        
147                                 //loadPublisherPref(newPublisherId, options, contentScopePrefs, workspaceScopePrefs);
148                                 form.writeFields(outputOptions, (RecordBinding) options.getBinding(), options.getValue());
149                                 
150                                 selectedPublisherId = newPublisherId;
151
152                                 updatingForm = false;
153                                 validate();
154                         } catch ( BindingException e ) {
155                                 setErrorMessage( e.getClass().getName()+": "+ e.getMessage() );
156                     ExceptionUtils.logError(e);                 
157                         } catch (AccessorConstructionException e) {
158                                 setErrorMessage( e.getClass().getName()+": "+ e.getMessage() );
159                     ExceptionUtils.logError(e);                 
160                         } catch (AccessorException e) {
161                                 setErrorMessage( e.getClass().getName()+": "+ e.getMessage() );
162                     ExceptionUtils.logError(e);                 
163                         } catch (ExportException e) {
164                                 setErrorMessage( e.getClass().getName()+": "+ e.getMessage() );
165                     ExceptionUtils.logError(e);                 
166                         } finally {
167                                 updatingForm = false;
168                         }
169                 }
170         };
171         
172         @Override
173         public void createControl(Composite parent) {
174                 
175             scroll = new ScrolledComposite(parent, SWT.V_SCROLL);
176             composite = new Composite(scroll, 0);
177                 composite.setLayout( new GridLayout(3, false) );                        
178                 composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1));                   
179         scroll.setContent(composite);
180         scroll.setExpandHorizontal(true);
181         scroll.setExpandVertical(false);
182         scroll.getVerticalBar().setIncrement(scroll.getVerticalBar().getIncrement()*8);
183
184             form = new DataboardForm();
185             form.setFirstColumnWidth(200);
186
187                 composite.pack();
188                 setControl(scroll);
189         setPageComplete(true);
190         
191         }
192         
193         public void update(List<Content> contents) 
194         {
195                 try {
196                         // 0. Initialization
197                         Set<String> contentUris = new TreeSet<String>();
198                         MapList<String, Content> uriToContentMap = new MapList<String, Content>();
199                         MapList<ContentType, String> contentByContentType = new MapList<ContentType, String>();
200                         MapList<Format, String> contentByFormat = new MapList<Format, String>();
201                         List<Format> formats = new ArrayList<Format>();
202                         Map<String, Format> contentFormatMap = new TreeMap<String, Format>( String.CASE_INSENSITIVE_ORDER );
203                         for (Content content : contents) {
204                                 contentUris.add(content.url);
205                                 ContentType ct = ctx.eep.getContentType( content.contentTypeId );
206                                 contentByContentType.add(ct, content.url);
207                                 Format format = ctx.eep.getFormat( content.formatId );
208                                 contentByFormat.add(format, content.url);
209                                 uriToContentMap.add(content.url, content);
210                         }
211                         formats.addAll( contentByFormat.getKeys() );
212                         
213                         Collections.sort(formats, new ToStringComparator());
214                                                 
215                         for (Content content : contents) {
216                                 String id = content.formatId;
217                                 Format format = contentFormatMap.get( id );
218                                 if ( format != null ) continue;
219                                 format = ctx.eep.getFormat(id);
220                                 contentFormatMap.put(id, format);
221                         }
222
223                         MapList<Exporter, String> exporterContentMap = new MapList<Exporter, String>();
224                         TreeMap<String, Exporter> orderedExporters = new TreeMap<String, Exporter>( String.CASE_INSENSITIVE_ORDER );
225                         for (Content content : contents) {
226                                 for (Exporter exporter : ctx.eep.getExporters(content.formatId, content.contentTypeId) ) {
227                                         exporterContentMap.add(exporter, content.url);
228                                         orderedExporters.put(exporter.formatId()+exporter.contentTypeId()+exporter.exportAction().getClass(), exporter);
229                                 }
230                         }
231                         
232                         // 1. Save selections from previous form
233                         savePrefs();
234                         
235                         // 2. Clear previous form
236                         form.clear(composite);
237
238                         // 3. Create options record
239                         RecordType optionsRecord = new RecordType();
240
241                         // Add Output options box
242                     RecordType outputOptions = new RecordType();
243                         
244                         for ( Format format : formats ) {
245                                 if ( format.isGroupFormat() && contentByFormat.getValues(format).size()>1 ) {
246                                         outputOptions.addComponent("Merge "+format.fileext()+" content into one file", Datatypes.BOOLEAN);
247                                 }
248                                 
249                                 if ( format.isContainerFormat() ) {
250                                         List<String> formatsContentUris = contentByFormat.getValues(format);
251                                         int attachmentCount = 0;
252                                         for ( String contentUri : formatsContentUris ) {
253                                                 for ( Content content : uriToContentMap.getValues(contentUri) ) {
254                                                         if ( !content.formatId.equals(format.id()) ) attachmentCount++;
255                                                 }
256                                         }
257                                         // Add as possible attachment, all contents that don't have this format
258                                         // their their content type.
259                                         for ( Content content : contents ) {
260                                                 if ( ctx.eep.getExporters(format.id(), content.contentTypeId).length == 0) attachmentCount++;
261                                         }
262                                         
263                                         if ( attachmentCount > 0 ) { 
264                                                 outputOptions.addComponent("Include attachments to "+format.fileext(), Datatypes.BOOLEAN);
265                                                 outputOptions.addComponent("Export attachments of "+format.fileext()+" to separate files", Datatypes.BOOLEAN);
266                                         }
267                                 }
268                         }
269                         
270                         UnionType publisherType = new UnionType();
271                         for (Publisher publisher : ctx.eep.publishers()) publisherType.addComponent(publisher.label(), Datatypes.VOID);
272                         outputOptions.addComponent(S_PUBLISH, publisherType);
273                         
274                     optionsRecord.addComponent(S_OUTPUT_OPTIONS, outputOptions);                    
275                     
276                         // Add Format specific boxes
277                         for (Format format : contentFormatMap.values()) {
278                                 RecordType formatOptions = format.formatActions().options(ctx);
279                                 if ( formatOptions==null ) continue;
280                                 optionsRecord.mergeRecord( formatOptions );
281                         }
282         
283                         // Add Exporter specific boxes
284                         for (Exporter exporter : orderedExporters.values()) {                           
285                                 List<String> exportSpecificContents = exporterContentMap.getValues(exporter);
286                                 if ( exportSpecificContents==null || exportSpecificContents.isEmpty() ) continue;
287                                 RecordType exporterOptions = exporter.exportAction().options(ctx, exportSpecificContents);
288                                 if ( exporterOptions == null ) continue;
289                                 optionsRecord.mergeRecord( exporterOptions );
290                         }
291
292                         // 4. Load default and previous selections of the options ( All but publisher )
293                         ctx.databoard.clear();
294                         RecordBinding optionsBinding = ctx.databoard.getMutableBinding( optionsRecord );
295                         Object optionsObj = optionsBinding.createDefaultUnchecked();
296                         Variant options = new Variant(optionsBinding, optionsObj);
297                         {
298                                 Preferences workspaceScopePrefs = ctx.store;
299                                 Preferences contentScopePrefs = ctx.store( contents );
300                                 
301                                 for (Exporter exporter : orderedExporters.values()) {
302                                         exporter.exportAction().fillDefaultPrefs(ctx, options);
303                                         exporter.exportAction().loadPref(options, contentScopePrefs, workspaceScopePrefs);
304                                 }
305                                 
306                                 for (Format format : contentByFormat.getKeys()) {
307                                         format.formatActions().fillDefaultPrefs( ctx, options );
308                                         format.formatActions().loadPref(options, contentScopePrefs, workspaceScopePrefs);
309                                 }
310                                 
311                                 fillDefaultPrefs(options);
312                                 loadPref(options, contentScopePrefs, workspaceScopePrefs);
313                         }
314                         
315                         // 5. Create form
316                         form.addFields(composite, optionsRecord);
317                         form.addListener(composite, form.type(), modificationListener);
318                         Composite outputOptionsGroup = (Composite) form.getControl(composite, P_OUTPUT_OPTIONS);
319                         RecordType dummy = new RecordType();
320                         dummy.addComponent(S_OUTPUT_OPTIONS, outputOptions);
321                         form.addListener(outputOptionsGroup, dummy, outputSettingsModifiedListener);
322                         form.writeFields(composite, optionsBinding, optionsObj);
323                         
324                         // 6. Add publisher
325                         {
326                                 selection = contents;
327                                 Preferences workspaceScopePrefs = ctx.store;
328                                 Preferences contentScopePrefs = ctx.store.node( "Selection-"+selectionHash );
329                                 selectedPublisherId = ctx.store.get("publisherId", "");         
330                                 Publisher publisher = ctx.eep.getPublisher(selectedPublisherId);
331                                 if ( publisher != null ) {
332                                         
333                                         // 6A. Manifest
334                                         List<Content> manifest = getManifestFor(contents, options);
335                                         
336                                         // 6B. Default and previous settings
337                                         String label = publisher.label();
338                                         RecordType publisherOptionsType = publisher.publisherClass().locationOptions(ctx, manifest);
339                                         RecordType publisherOptionsRootType = new RecordType();
340                                         publisherOptionsRootType.addComponent(label, publisherOptionsType);
341                                         RecordBinding publisherOptionsRootBinding = ctx.databoard.getMutableBinding( publisherOptionsRootType );
342                                         Object publisherOptionsRootObj = publisherOptionsRootBinding.createDefaultUnchecked();
343                                         Variant publisherOptionsRoot = new Variant(publisherOptionsRootBinding, publisherOptionsRootObj);
344                                         try {
345                                                 ChildReference locationOptionsRef = new LabelReference( label );
346                                                 Variant locationOptions = publisherOptionsRoot.getComponent( locationOptionsRef );
347                                                 publisher.publisherClass().fillDefaultPrefs(ctx, selection, options, locationOptions);
348                                                 publisher.publisherClass().loadPref(locationOptions, contentScopePrefs, workspaceScopePrefs);   
349                                         } catch ( AccessorConstructionException ee ) {
350                                         }
351                                         
352                                         // 6C. Add Publisher form
353                                         addPublisherToGroup(selectedPublisherId, manifest);
354                                         form.writeFields(composite, publisherOptionsRootBinding, publisherOptionsRootObj);
355                                 }
356                         }
357
358                         // 8. Validate page
359                         composite.pack();
360                         validate();
361                         
362                 } catch (BindingException e) {
363             ExceptionUtils.logError(e);                 
364                         ShowMessage.showError("Unexpected error", e.getClass().getName()+" "+e.getMessage());
365                         throw new RuntimeBindingException(e);
366                 } catch (ExportException e) {
367             ExceptionUtils.logError(e);                 
368                         ShowMessage.showError("Unexpected error", e.getClass().getName()+" "+e.getMessage());
369                 } catch (DatatypeConstructionException e) {
370             ExceptionUtils.logError(e);                 
371                         ShowMessage.showError("Unexpected error", e.getClass().getName()+" "+e.getMessage());
372                 } catch (AccessorConstructionException e) {
373             ExceptionUtils.logError(e);                 
374                         ShowMessage.showError("Unexpected error", e.getClass().getName()+" "+e.getMessage());
375                 } catch (AccessorException e) {
376             ExceptionUtils.logError(e);                 
377                         // TODO Auto-generated catch block
378                         e.printStackTrace();
379                 }
380                 
381         }
382
383         /**
384          * Saves publisher prefs from the UI to preference nodes.
385          * 
386          * @throws ExportException
387          */
388         void savePublisherPref(String publisherId, Variant options, Preferences contentScopePrefs, Preferences workspaceScopePrefs) throws ExportException {
389                 try {
390 //                      Preferences contentScopePrefs = ctx.store.node( "Selection-"+selectionHash );
391 //                      Preferences workspaceScopePrefs = ctx.store;
392
393 //                      RecordBinding binding = ctx.databoard.getMutableBinding( form.type() );
394 //                      Object obj = binding.createDefault();
395 //                      form.readFields(composite, binding, obj);
396 //                      Variant options = new Variant(binding, obj);
397                         
398                         Publisher publisher = ctx.eep.getPublisher( publisherId );
399                         if ( publisher==null ) return;
400                         Variant locationOptions = options.getComponent( new LabelReference(publisher.label()) );
401                         publisher.publisherClass().savePref(locationOptions, contentScopePrefs, workspaceScopePrefs);
402 //              } catch (BindingException e) {
403 //                      throw new ExportException( e );
404                 } catch (AccessorConstructionException e) {
405             ExceptionUtils.logError(e);                 
406                         //throw new ExportException( e );
407 //              } catch (AccessorException e) {
408 //                      throw new ExportException( e );
409                 }
410         }
411         
412         void loadPublisherPref(String publisherId, Variant options, Preferences contentScopePrefs, Preferences workspaceScopePrefs) throws ExportException {
413                 try {
414 //                      Preferences contentScopePrefs = ctx.store.node( "Selection-"+selectionHash );
415 //                      Preferences workspaceScopePrefs = ctx.store;
416                         
417                         Publisher publisher = ctx.eep.getPublisher( publisherId );
418                         if ( publisher == null ) return;
419                         
420                         // There is a problem here if selection was built with manifest
421 //                      RecordType optionsType = publisher.publiserClass().locationOptions(ctx, selection);                     
422 //                      RecordBinding binding = ctx.databoard.getMutableBinding( optionsType );
423 //                      Object obj = binding.createDefault();
424 //                      Variant locationOptions = new Variant(binding, obj);
425                         Variant locationOptions = options.getComponent( new LabelReference( publisher.label() ) );
426                         publisher.publisherClass().fillDefaultPrefs(ctx, selection, options, locationOptions);
427                         publisher.publisherClass().loadPref(locationOptions, contentScopePrefs, workspaceScopePrefs);   
428 //              } catch (BindingException e) {
429 //                      throw new ExportException( e );
430                 } catch (AccessorConstructionException e) {
431             ExceptionUtils.logError(e);                 
432                         //throw new ExportException( e );
433 //              } catch (AccessorException e) {
434 //                      throw new ExportException( e );
435                 }
436         }
437
438         /**
439          * Remove any publisher specific controls from output options.
440          */
441         void cleanPublisherFromGroup(String oldPublisherId) {
442                 Publisher publisher = ctx.eep.getPublisher(oldPublisherId);
443                 if ( publisher != null ) {
444                         String fieldName = publisher.label();
445                         if ( form.type().hasComponent(fieldName)) {
446                                 form.type().removeComponent(fieldName);
447                                 ctx.databoard.clear();
448                         }
449                 }
450                 Combo publishTo = (Combo) form.getControl(composite, P_PUBLISH);
451                 Composite group = (Composite) publishTo.getParent();
452                 Control children[] = group.getChildren();
453                 int index = Arrays.indexOf( children, publishTo );
454                 for (int i=children.length-1; i>index; i--) {
455                         children[i].dispose();
456                 }
457         }
458         
459         /**
460          * Add controls of a publisher id 
461          * 
462          * @param publisherId
463          * @throws ExportException 
464          */
465         void addPublisherToGroup( String publisherId, List<Content> contents ) throws ExportException {
466                 try {
467                         Composite group = (Composite) form.getControl(composite, P_OUTPUT_OPTIONS);
468                         if ( group == null ) return;
469                         Publisher publisher = ctx.eep.getPublisher( publisherId );
470                         if ( publisher == null ) return;
471                         RecordType publisherOptions = publisher.publisherClass().locationOptions(ctx, contents);                
472                         //form.type().addComponent(publisher.label(), publisherOptions);
473                         RecordType options = new RecordType();
474                         options.addComponent(publisher.label(), publisherOptions);
475                         form.addFields(group, publisherOptions, publisher.label());
476                         form.addListener(group, options, modificationListener);
477                         ctx.databoard.clear();
478                 } catch (BindingException e) {
479                         throw new ExportException(e);
480                 } catch (AccessorConstructionException e) {
481                         throw new ExportException(e);
482                 } catch (AccessorException e) {
483                         throw new ExportException(e);
484                 }
485         }
486         
487         List<Content> getManifestFor(List<Content> selection, Variant options) {                
488                 try {
489                         ExportWizardResult result = new ExportWizardResult();
490                         result.options = options;
491                         result.accessor = Accessors.getAccessor(result.options);
492                         result.contents = selection;
493                         result.type = (RecordType) options.type();
494                         result.publisherId = "file";
495                         
496                         List<ExportAction> actions = new ArrayList<ExportAction>();
497                         List<Content> manifest = new ArrayList<Content>(); 
498                         result.createExportActions(ctx, actions, manifest);
499                         return manifest;
500                 } catch (AccessorConstructionException e) {
501                         return selection;
502                 } catch (ExportException e) {
503                         e.printStackTrace();
504                         return selection;
505                 }
506         }       
507         
508         public ExportWizardResult getOutput()
509         throws ExportException
510         {
511                 ExportWizardResult result = new ExportWizardResult();
512                 try {
513                         ctx.databoard.clear();
514                         result.type = form.type();
515                     RecordBinding binding = (RecordBinding) ctx.databoard.getMutableBinding( result.type );
516                     Object optionsObj = binding.createDefault();
517                     result.options = new Variant(binding, optionsObj);
518                         form.readFields(composite, binding, optionsObj);
519                         result.accessor = Accessors.getAccessor(result.options);
520                         result.contents = selection;
521                         
522                         
523                         String publisherLabel = ExporterUtils.getUnionValue(result.accessor, P_PUBLISH);
524                         Publisher publisher = ctx.eep.getPublisherByLabel(publisherLabel);
525                         result.publisherId = publisher==null?"":publisher.id();                 
526                         
527                 } catch (BindingException e) {
528                         throw new ExportException(e);                   
529                 } catch (AccessorException e) {
530                         throw new ExportException(e);
531                 } catch (AccessorConstructionException e) {
532                         throw new ExportException(e);
533                 }
534                 
535                 return result;
536         }
537                 
538         void validate() {               
539                 List<Problem> problems = form.validate(composite);
540                 List<String> errs = DataboardForm.toStrings(problems);
541                 
542                 if ( errs.isEmpty() ) {
543                         try {
544                                 ExportWizardResult result = getOutput();
545                                 ExportPlan plan = new ExportPlan();
546                                 result.createPlan(ctx, plan);
547                                 ExportManager mgr = new ExportManager(result.options, ctx);
548                                 errs.addAll( mgr.validate(ctx, plan) ) ;
549                         } catch (ExportException e) {
550                                 errs.add(e.getMessage());
551                         }
552                 } else {
553                         CollectionUtils.unique( errs );                 
554                 }
555                 
556
557                 setErrorMessage( errs.isEmpty() ? null : CollectionUtils.toString(errs, ", ") );
558                 setPageComplete( errs.isEmpty() );
559         }
560                 
561         /**
562          * Save wizard preferences
563          * 
564          * @param options
565          * @param contentScopePrefs
566          * @param workspaceScopePrefs
567          * @throws ExportException
568          */
569         void savePref(Variant options, Preferences contentScopePrefs, Preferences workspaceScopePrefs) throws ExportException
570         {
571         try {
572                         RecordAccessor ra = Accessors.getAccessor(options);
573                         String publisherId = ExporterUtils.getUnionValue(ra, P_PUBLISH); 
574                         Publisher publisher = ctx.eep.getPublisherByLabel(publisherId);
575                         if ( publisher!=null ) workspaceScopePrefs.put("publisherId", publisher.id());
576                         
577                         if ( ra.type().hasComponent(P_OUTPUT_OPTIONS.label) ) {
578                                 RecordAccessor rao = ra.getComponent( P_OUTPUT_OPTIONS );
579                                                                 
580                                 Pattern merge_pattern = Pattern.compile("Merge ([^\\s]*) content into one file");
581                                 Pattern include_pattern = Pattern.compile("Include attachments to ([^\\s]*)");
582                                 Pattern export_pattern = Pattern.compile("Export attachments of ([^\\s]*) to separate files");
583                                 
584                                 for (int i=0; i<rao.count(); i++) {
585                                         String name = rao.type().getComponent(i).name;
586                                         Matcher m;
587                                         
588                                         m = merge_pattern.matcher(name);
589                                         if ( m.matches() ) {
590                                                 String fileExt = m.group(1);
591                                                 Format format = ctx.eep.getFormatByExt(fileExt);
592                                                 Boolean value = (Boolean) rao.getFieldValue(i, Bindings.BOOLEAN);
593                                                 String key = format.id()+"_merge";
594                                                 contentScopePrefs.putBoolean(key, value);
595                                                 workspaceScopePrefs.putBoolean(key, value);
596                                         }
597                                         
598                                         m = include_pattern.matcher(name);
599                                         if ( m.matches() ) {
600                                                 String fileExt = m.group(1);
601                                                 Format format = ctx.eep.getFormatByExt(fileExt);
602                                                 Boolean value = (Boolean) rao.getFieldValue(i, Bindings.BOOLEAN);
603                                                 String key = format.id()+"_include_attachments";
604                                                 contentScopePrefs.putBoolean(key, value);
605                                                 workspaceScopePrefs.putBoolean(key, value);
606                                         }
607                                         
608                                         m = export_pattern.matcher(name);
609                                         if ( m.matches() ) {
610                                                 String fileExt = m.group(1);
611                                                 Format format = ctx.eep.getFormatByExt(fileExt);
612                                                 Boolean value = (Boolean) rao.getFieldValue(i, Bindings.BOOLEAN);
613                                                 String key = format.id()+"_export_attachments";
614                                                 contentScopePrefs.putBoolean(key, value);
615                                                 workspaceScopePrefs.putBoolean(key, value);
616                                         }
617                                 }
618                         }
619                         
620                 } catch (AccessorConstructionException e) {
621                         throw new ExportException(e);
622                 } catch (AccessorException e) {
623                         throw new ExportException(e);
624                 }
625                 
626         }
627
628         /**
629          * Load wizard preferences
630          * 
631          * @param binding
632          * @param options
633          * @param contentScopePrefs
634          * @param workspaceScopePrefs
635          * @throws ExportException
636          */
637         void loadPref(Variant options, Preferences contentScopePrefs, Preferences workspaceScopePrefs) throws ExportException
638         {
639                 //Preferences workspaceScopePrefs = ctx.store;
640         try {
641                         RecordAccessor ra = Accessors.getAccessor(options);             
642                         String publisherId = workspaceScopePrefs.get("publisherId", "");
643                         Publisher publisher = ctx.eep.getPublisher(publisherId);
644                         if ( publisher != null ) ExporterUtils.setUnionValue(ra, P_PUBLISH, publisher.label());
645                         
646                         if ( ra.type().hasComponent(P_OUTPUT_OPTIONS.label) ) {
647                                 RecordAccessor rao = ra.getComponent( P_OUTPUT_OPTIONS );
648                                                                 
649                                 for (Format format : ctx.eep.formats()) {
650                                         if ( format.isGroupFormat() ) {
651                                                 String key = format.id()+"_merge";
652                                                 Boolean value = null;
653                                                 if ( containsKey(contentScopePrefs, key) ) {
654                                                         value = contentScopePrefs.getBoolean(key, false); 
655                                                 } else if ( containsKey(workspaceScopePrefs, key) ) {
656                                                         value = workspaceScopePrefs.getBoolean(key, false);
657                                                 }
658                                                                                         
659                                                 if ( value != null ) {
660                                                         String key2 = "Merge "+format.fileext()+" content into one file";
661                                                         int index = rao.type().getComponentIndex2(key2);
662                                                         if ( index>=0 ) {
663                                                                 rao.setFieldValue(index, Bindings.BOOLEAN, value);
664                                                         }
665                                                 }                                       
666                                         }
667                                         
668                                         if ( format.isContainerFormat() ) {
669                                                 String key = format.id()+"_include_attachments";
670                                                 Boolean value = null;
671                                                 if ( containsKey(contentScopePrefs, key) ) {
672                                                         value = contentScopePrefs.getBoolean(key, false); 
673                                                 } else if ( containsKey(workspaceScopePrefs, key) ) {
674                                                         value = workspaceScopePrefs.getBoolean(key, false);
675                                                 }
676                                                                                         
677                                                 if ( value != null ) {
678                                                         String key2 = "Include attachments to "+format.fileext();
679                                                         int index = rao.type().getComponentIndex2(key2);
680                                                         if ( index>=0 ) {
681                                                                 rao.setFieldValue(index, Bindings.BOOLEAN, value);
682                                                         }
683                                                 }                                       
684                                         }
685                                         
686                                         if ( format.isContainerFormat() ) {
687                                                 String key = format.id()+"_export_attachments";
688                                                 Boolean value = null;
689                                                 if ( containsKey(contentScopePrefs, key) ) {
690                                                         value = contentScopePrefs.getBoolean(key, false); 
691                                                 } else if ( containsKey(workspaceScopePrefs, key) ) {
692                                                         value = workspaceScopePrefs.getBoolean(key, false);
693                                                 }
694                                                                                         
695                                                 if ( value != null ) {
696                                                         String key2 = "Export attachments of "+format.fileext()+" to separate files";
697                                                         int index = rao.type().getComponentIndex2(key2);
698                                                         if ( index>=0 ) {
699                                                                 rao.setFieldValue(index, Bindings.BOOLEAN, value);
700                                                         }
701                                                 }                                       
702                                         }
703                                         
704                                 }
705                         }
706                                         
707                 } catch (AccessorConstructionException e) {
708                         throw new ExportException(e);
709                 } catch (AccessorException e) {
710                         throw new ExportException(e);
711                 }               
712         }
713         
714         /**
715          * Save selections from previous form
716          */
717         public void savePrefs() throws ExportException {
718                 try {
719                         int oldSelectionHash = selectionHash;                   
720                         Preferences contentScopePrefs = ctx.store.node( "Selection-"+oldSelectionHash );
721                         Preferences workspaceScopePrefs = ctx.store;
722                                         
723                         RecordBinding binding = ctx.databoard.getMutableBinding( form.type() );
724                         Object obj = binding.createDefault();
725                         Variant options = new Variant(binding, obj);
726                         form.readFields(composite, binding, obj);
727                                                 
728                         Combo publishTo = (Combo) form.getControl(composite, P_PUBLISH);                
729                         String publisherLabel = publishTo==null?null:publishTo.getText();
730                         if ( publisherLabel != null ) {
731                                 Publisher publisher = ctx.eep.getPublisherByLabel( publisherLabel );
732                                 if ( publisher!=null ) {
733                                         try {
734                                                 ChildReference locationOptionsRef = new LabelReference(publisher.label());
735                                                 Variant locationOptions = options.getComponent( locationOptionsRef );
736                                                 publisher.publisherClass().savePref(locationOptions, contentScopePrefs, workspaceScopePrefs);
737                                         } catch ( AccessorConstructionException e ) {} 
738                                 }
739                         }
740                         
741                         for (Exporter exporter : ctx.eep.exporters()) {
742                                 exporter.exportAction().savePref(options, contentScopePrefs, workspaceScopePrefs);
743                         }
744                                         
745                         for (Format format : ctx.eep.formats()) {
746                                 format.formatActions().savePref(options, contentScopePrefs, workspaceScopePrefs);
747                         }                               
748                                         
749                         savePref(options, contentScopePrefs, workspaceScopePrefs);
750                 } catch (BindingException e) {
751                         throw new ExportException( e ); 
752                 } catch (AccessorConstructionException e) {
753                         throw new ExportException( e ); 
754                 } catch (AccessorException e) {
755                         throw new ExportException( e ); 
756                 } catch (ExportException e) {
757                         throw new ExportException( e ); 
758                 }
759         }
760
761         public void fillDefaultPrefs(Variant options) throws ExportException {
762         try {
763                         RecordAccessor ra = Accessors.getAccessor(options);
764
765                         if ( ra.type().hasComponent(P_OUTPUT_OPTIONS.label) ) {
766                                 RecordAccessor rao = ra.getComponent( P_OUTPUT_OPTIONS );
767                                 
768                                 for (Format format : ctx.eep.formats()) {
769                                         if ( format.isContainerFormat() ) {
770                                                 String key = "Include attachments to "+format.fileext();
771                                                 int index = rao.type().getComponentIndex2(key);
772                                                 if ( index>=0 ) rao.setFieldValue(index, Bindings.BOOLEAN, true);
773                                                 
774                                                 key = "Export attachments of "+format.fileext()+" to separate files";;
775                                                 index = rao.type().getComponentIndex2(key);
776                                                 if ( index>=0 ) rao.setFieldValue(index, Bindings.BOOLEAN, true);
777                                         }                       
778                                 }
779                                 
780                         }
781                 
782                 } catch (AccessorConstructionException e) {
783                         throw new ExportException(e);
784                 } catch (AccessorException e) {
785                         throw new ExportException(e);
786                 }
787         }       
788         
789         static boolean containsKey(Preferences pref, String key) {
790                 try {
791                         for (String x : pref.keys()) if ( x.equals(key) ) return true;
792                 } catch (BackingStoreException e) {
793                         e.printStackTrace();
794                 } 
795                 return false;           
796         }
797                 
798 }