]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/wizard/MigrateWizard.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / wizard / MigrateWizard.java
1 /*******************************************************************************
2  * Copyright (c) 2014, 2015 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  *     Semantum Oy - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.modeling.ui.wizard;
13
14 import java.lang.reflect.InvocationTargetException;
15 import java.util.ArrayList;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.Comparator;
19 import java.util.Map;
20 import java.util.Set;
21
22 import org.eclipse.core.runtime.IStatus;
23 import org.eclipse.core.runtime.OperationCanceledException;
24 import org.eclipse.core.runtime.Status;
25 import org.eclipse.core.runtime.SubMonitor;
26 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
27 import org.eclipse.core.runtime.preferences.InstanceScope;
28 import org.eclipse.jface.dialogs.IDialogSettings;
29 import org.eclipse.jface.dialogs.MessageDialog;
30 import org.eclipse.jface.layout.GridDataFactory;
31 import org.eclipse.jface.layout.GridLayoutFactory;
32 import org.eclipse.jface.layout.RowLayoutFactory;
33 import org.eclipse.jface.resource.ImageDescriptor;
34 import org.eclipse.jface.window.Window;
35 import org.eclipse.jface.wizard.Wizard;
36 import org.eclipse.jface.wizard.WizardPage;
37 import org.eclipse.swt.SWT;
38 import org.eclipse.swt.custom.CCombo;
39 import org.eclipse.swt.events.ModifyEvent;
40 import org.eclipse.swt.events.ModifyListener;
41 import org.eclipse.swt.events.SelectionEvent;
42 import org.eclipse.swt.events.SelectionListener;
43 import org.eclipse.swt.graphics.Point;
44 import org.eclipse.swt.layout.GridLayout;
45 import org.eclipse.swt.widgets.Button;
46 import org.eclipse.swt.widgets.Composite;
47 import org.eclipse.swt.widgets.Control;
48 import org.eclipse.swt.widgets.Event;
49 import org.eclipse.swt.widgets.Label;
50 import org.eclipse.swt.widgets.List;
51 import org.eclipse.swt.widgets.Listener;
52 import org.eclipse.swt.widgets.Shell;
53 import org.eclipse.swt.widgets.Text;
54 import org.simantics.Simantics;
55 import org.simantics.databoard.Bindings;
56 import org.simantics.databoard.util.URIStringUtils;
57 import org.simantics.db.ReadGraph;
58 import org.simantics.db.Resource;
59 import org.simantics.db.WriteGraph;
60 import org.simantics.db.common.NamedResource;
61 import org.simantics.db.common.request.ObjectsWithType;
62 import org.simantics.db.common.request.UnaryRead;
63 import org.simantics.db.common.request.UniqueRead;
64 import org.simantics.db.common.request.WriteResultRequest;
65 import org.simantics.db.common.utils.Logger;
66 import org.simantics.db.common.utils.Versions;
67 import org.simantics.db.exception.CancelTransactionException;
68 import org.simantics.db.exception.DatabaseException;
69 import org.simantics.diagram.stubs.DiagramResource;
70 import org.simantics.layer0.Layer0;
71 import org.simantics.modeling.MigrateModel;
72 import org.simantics.modeling.MigrateModel.MigrationOperation;
73 import org.simantics.modeling.ModelingResources;
74 import org.simantics.modeling.UserComponentMigration;
75 import org.simantics.modeling.ui.Activator;
76 import org.simantics.structural.stubs.StructuralResource2;
77 import org.simantics.ui.workbench.dialogs.ResourceSelectionDialog3;
78 import org.simantics.utils.datastructures.Pair;
79 import org.simantics.utils.datastructures.Triple;
80 import org.simantics.utils.strings.AlphanumComparator;
81
82 import gnu.trove.map.hash.THashMap;
83 import gnu.trove.set.hash.THashSet;
84 import gnu.trove.set.hash.TIntHashSet;
85
86 /**
87  * @author Antti Villberg
88  */
89 public class MigrateWizard extends Wizard {
90
91         final String initial;
92         
93     MigratePage  migratePage;
94
95         IEclipsePreferences prefnode;
96     
97     public MigrateWizard(String initial) {
98         
99         this.initial = initial;
100
101         setWindowTitle("Perform migration");
102         setNeedsProgressMonitor(true);
103         setForcePreviousAndNextButtons(false);
104         setDialogSettings(Activator.getDefault().getDialogSettings());
105
106         prefnode = InstanceScope.INSTANCE.getNode( "org.simantics.modeling.ui.wizard.MigrateWizard" );
107         
108     }
109
110     @Override
111     public void addPages() {
112         migratePage = new MigratePage(initial);
113         addPage(migratePage);
114     }
115
116     @Override
117     public boolean canFinish() {
118 //        if (model.spec.name.isEmpty())
119 //            return false;
120         return true;
121     }
122
123     @Override
124     public boolean performFinish() {
125
126         int locationIndex = migratePage.locations.getSelectionIndex();
127         if(locationIndex == -1) return true;
128
129         if(migratePage.model == null || migratePage.model.instances.isEmpty()) return true;
130
131         int[] sel = migratePage.instances.getSelectionIndices();
132         TIntHashSet sels = new TIntHashSet();
133         for(int i : sel) sels.add(i);
134
135         Collection<MigrationOperation> ops = migratePage.model.sortedShownInstances;
136         int index = 0;
137         final ArrayList<MigrationOperation> result = new ArrayList<>();
138         for(MigrationOperation op : ops) {
139                 if(sels.contains(index)) result.add(op);
140                 index++;
141         }
142         
143         if(result.isEmpty()) return true;
144         
145         try {
146             String[] report = { null };
147             getContainer().run(true, true, monitor -> {
148                 SubMonitor mon = SubMonitor.convert(monitor, 1000);
149                 try {
150                     report[0] = Simantics.getSession().syncRequest(new WriteResultRequest<String>() {
151                         @Override
152                         public String perform(WriteGraph graph) throws DatabaseException {
153                             graph.markUndoPoint();
154                             String report = UserComponentMigration.doMigration(mon.newChild(500, SubMonitor.SUPPRESS_NONE), graph, result);
155                             UserComponentMigration.doPostMigration(mon.newChild(500, SubMonitor.SUPPRESS_NONE), graph, result);
156                             mon.setTaskName("Committing Changes");
157                             mon.subTask("");
158                             return report;
159                         }
160                     });
161                 } catch (DatabaseException e) {
162                     throw new InvocationTargetException(e);
163                 } finally {
164                     monitor.done();
165                 }
166             });
167
168
169             ReportDialog md = new ReportDialog(getShell(), report[0], 800, 500);
170             md.open();
171
172             return true;
173         } catch (InvocationTargetException e) {
174             // Don't show user cancellations as errors.
175             Throwable cause = e.getCause();
176             if (!(cause instanceof CancelTransactionException || cause instanceof OperationCanceledException)) {
177                 Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
178                         "Migration failed, see Error Log for details.", e.getCause()));
179             }
180         } catch (InterruptedException e) {
181             Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
182                     "Migration interrupted, see Error Log for details.", e));
183         }
184         return false;
185     }
186
187     static class ReportDialog extends MessageDialog {
188         private final String report;
189         private final int initialWidth;
190         private final int initialHeight;
191
192         public ReportDialog(Shell shell, String report, int width, int height) {
193             super(shell, 
194                     "Migration report", null, 
195                     "", 
196                     MessageDialog.INFORMATION, new String[] { "Continue" }, 0);
197             this.report = report;
198             this.initialWidth = width;
199             this.initialHeight = height;
200         }
201
202         @Override
203         protected boolean isResizable() {
204             return true;
205         }
206
207         @Override
208         protected Point getInitialSize() {
209             return new Point(initialWidth, initialHeight);
210         }
211
212         @Override
213         protected Control createCustomArea(Composite composite) {
214             GridLayoutFactory.fillDefaults().applyTo(composite);
215             Text text = new Text(composite, SWT.MULTI | SWT.V_SCROLL | SWT.READ_ONLY | SWT.BORDER);
216             text.setText(report);
217             GridDataFactory.fillDefaults().grab(true, true).applyTo(text);
218             return composite;
219         }
220     }
221
222     abstract static class SelectionAdapter implements SelectionListener {
223         @Override
224         public void widgetDefaultSelected(SelectionEvent e) {
225             widgetSelected(e);
226         }
227     }
228
229     class MigratePage extends WizardPage {
230
231         String                initial;
232         
233         MigrateModel          model;
234
235         Text                  source;
236         Button                browseSource;
237         Text                  target;
238         Button                browseTarget;
239         Label                 symbolsLabel;
240         CCombo                symbols;
241         Label                 instanceLabel;
242         Label                             locationsLabel;
243         CCombo                locations;
244         Composite             buttonBar;
245         Label                 instancesLabel;
246         List                  instances;
247
248         /**
249          * ID of the location that has been previously selected by the user.
250          * Used to prevent the location from being reset every time the user
251          * makes a change in any of the other selections.
252          * 
253          * See first field of {@link MigrateModel#instances}.
254          */
255         String                previouslySelectedLocationId = null;
256
257         public MigratePage(String initial) {
258             super("Perform migration", "Perform migration", null);
259             this.initial = initial;
260         }
261
262         @Override
263         public void createControl(Composite parent) {
264             Composite container = new Composite(parent, SWT.NONE);
265             {
266                 GridLayout layout = new GridLayout();
267                 layout.horizontalSpacing = 20;
268                 layout.verticalSpacing = 10;
269                 layout.numColumns = 10;
270                 container.setLayout(layout);
271             }
272
273             new Label(container, SWT.NONE).setText("&Source:");
274             source = new Text(container, SWT.BORDER);
275             source.setText(initial);
276             source.addModifyListener(new ModifyListener() {
277                 @Override
278                 public void modifyText(ModifyEvent e) {
279                     refreshModel();
280                     refreshInstances();
281                 }
282             });
283             GridDataFactory.fillDefaults().grab(true, false).span(8, 1).applyTo(source);
284
285             browseSource = new Button(container, SWT.NONE);
286             browseSource.setText("&Browse");
287             GridDataFactory.fillDefaults().grab(false, false).applyTo(browseSource);
288             browseSource.addSelectionListener(new SelectionAdapter() {
289                 @Override
290                 public void widgetSelected(SelectionEvent e_) {
291                     try {
292                         Map<String, Pair<String, ImageDescriptor>> map = Simantics.getSession().syncRequest(new BrowseSourceContentRequest(target.getText()));
293                         String uri = queryTargetSelection("Select Source Type", map);
294                         if (uri != null)
295                             source.setText(uri);
296                     } catch (DatabaseException e) {
297                         Logger.defaultLogError(e);
298                     }
299                 }
300             });
301
302             new Label(container, SWT.NONE).setText("&Target:");
303             target = new Text(container, SWT.BORDER);
304             target.setText(initial);
305             target.addModifyListener(new ModifyListener() {
306                 @Override
307                 public void modifyText(ModifyEvent e) {
308                     refreshSymbols();
309                     refreshModel();
310                     refreshInstances();
311                 }
312             });
313             GridDataFactory.fillDefaults().grab(true, false).span(8, 1).applyTo(target);
314
315             browseTarget = new Button(container, SWT.NONE);
316             browseTarget.setText("B&rowse");
317             GridDataFactory.fillDefaults().grab(false, false).applyTo(browseTarget);
318             browseTarget.addSelectionListener(new SelectionAdapter() {
319                 @Override
320                 public void widgetSelected(SelectionEvent e_) {
321                     try {
322                         Map<String, Pair<String, ImageDescriptor>> map = Simantics.getSession().syncRequest(new BrowseTargetContentRequest(source.getText()));
323                         String uri = queryTargetSelection("Select Target Type", map);
324                         if (uri != null)
325                             target.setText(uri);
326                     } catch (DatabaseException e) {
327                         Logger.defaultLogError(e);
328                     }
329                 }
330             });
331
332             symbolsLabel = new Label(container, SWT.NONE);
333             symbolsLabel.setText("Target &symbol:");
334             GridDataFactory.fillDefaults().applyTo(symbolsLabel);
335
336             symbols = new CCombo(container, SWT.BORDER | SWT.READ_ONLY);
337             symbols.setVisibleItemCount(10);
338             symbols.addSelectionListener(new SelectionAdapter() {
339                 @Override
340                 public void widgetSelected(SelectionEvent e) {
341                     refreshModel();
342                     refreshInstances();
343                 }
344             });
345             GridDataFactory.fillDefaults().grab(true, false).span(9, 1).applyTo(symbols);
346
347             instanceLabel = new Label(container, SWT.NONE);
348             GridDataFactory.fillDefaults().grab(true, false).span(10, 1).applyTo(instanceLabel);
349             instanceLabel.setText("");
350
351             locationsLabel = new Label(container, SWT.NONE);
352             locationsLabel.setText("&Locations:");
353             locations = new CCombo(container, SWT.BORDER | SWT.READ_ONLY);
354             locations.setVisibleItemCount(25);
355             locations.addSelectionListener(new SelectionAdapter() {
356                 @Override
357                 public void widgetSelected(SelectionEvent e) {
358                     int index = locations.getSelectionIndex();
359                     if (index >= 0 && index < model.instances.size()) {
360                         previouslySelectedLocationId = model.instances.get(index).first;
361                     }
362                     refreshInstances();
363                 }
364             });
365             GridDataFactory.fillDefaults().grab(true, false).span(9, 1).applyTo(locations);
366
367             instancesLabel = new Label(container, SWT.NONE);
368             instancesLabel.setText("&Select instances to migrate:");
369             GridDataFactory.fillDefaults().grab(true, false).span(10, 1).applyTo(instancesLabel);
370
371             buttonBar = new Composite(container, SWT.NONE);
372             RowLayoutFactory.fillDefaults().type(SWT.HORIZONTAL).applyTo(buttonBar);
373             GridDataFactory.fillDefaults().grab(true, false).span(10, 1).applyTo(buttonBar);
374             Button selectAll = new Button(buttonBar, SWT.PUSH);
375             selectAll.setText("Select &All");
376             Button selectNone = new Button(buttonBar, SWT.PUSH);
377             selectNone.setText("Select &None");
378             selectAll.addSelectionListener(new SelectionAdapter() {
379                 @Override
380                 public void widgetSelected(SelectionEvent e) {
381                     instances.selectAll();
382                 }
383             });
384             selectNone.addSelectionListener(new SelectionAdapter() {
385                 @Override
386                 public void widgetSelected(SelectionEvent e) {
387                     instances.deselectAll();
388                 }
389             });
390
391             instances = new List(container, SWT.MULTI | SWT.WRAP | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
392             GridDataFactory.fillDefaults().grab(true, true).span(10, 1).applyTo(instances);
393             instances.addListener(SWT.Modify, validateListener);
394
395             refreshSymbols();
396             refreshModel();
397             refreshInstances();
398
399             setControl(container);
400             validatePage();
401         }
402
403         String queryTargetSelection(String title, Map<String, Pair<String, ImageDescriptor>> map) {
404             Shell shell = source.getShell();
405             ResourceSelectionDialog3<String> dialog = new ResourceSelectionDialog3<String>(shell, map, title, false) {
406                 @Override
407                 protected IDialogSettings getBaseDialogSettings() {
408                     return Activator.getDefault().getDialogSettings();
409                 }
410             };
411             if (dialog.open() == Window.OK)
412                 return (String) dialog.getFirstResult();
413             return null;
414         }
415
416         void refreshSymbols() {
417             try {
418
419                 final String uri = target.getText();
420
421                 Collection<NamedResource> syms = Simantics.getSession().syncRequest(new UniqueRead<Collection<NamedResource>>() {
422
423                     @Override
424                     public Collection<NamedResource> perform(ReadGraph graph) throws DatabaseException {
425
426                         Layer0 L0 = Layer0.getInstance(graph);
427                         DiagramResource DIA = DiagramResource.getInstance(graph);
428                         ModelingResources MOD = ModelingResources.getInstance(graph);
429
430                         Set<NamedResource> result = new THashSet<>();
431                         Resource componentType = graph.getResource(uri);
432
433                         Set<Resource> potentialSymbols = new THashSet<>();
434                         potentialSymbols.addAll(graph.syncRequest(new ObjectsWithType(componentType, L0.ConsistsOf, DIA.ElementClass)));
435                         potentialSymbols.addAll(graph.getObjects(componentType, MOD.ComponentTypeToSymbol));
436
437                         for(Resource symbol : potentialSymbols) {
438                             if(!graph.hasStatement(symbol, MOD.SymbolToComponentType, componentType)) continue;
439                             String name = graph.getRelatedValue(symbol, L0.HasName, Bindings.STRING);
440                             if(graph.hasStatement(symbol, MOD.SymbolToComponentType, componentType))
441                                 result.add(new NamedResource(name, symbol));
442                         }
443
444                         return new ArrayList<>(result);
445
446                     }
447
448                 });
449
450                 symbols.removeAll();
451                 symbols.add("<retain symbol name>");
452                 for(NamedResource nr : syms) {
453                     symbols.add(nr.getName());
454                 }
455                 symbols.setData(syms);
456                 symbols.select(0);
457
458                 if(syms.isEmpty()) {
459                     symbolsLabel.setVisible(false);
460                     symbols.setVisible(false);
461                     GridDataFactory.fillDefaults().exclude(true).applyTo(symbolsLabel);
462                     GridDataFactory.fillDefaults().exclude(true).grab(true, false).span(9, 1).applyTo(symbols);
463                 } else {
464                     symbolsLabel.setVisible(true);
465                     symbols.setVisible(true);
466                     GridDataFactory.fillDefaults().applyTo(symbolsLabel);
467                     GridDataFactory.fillDefaults().grab(true, false).span(9, 1).applyTo(symbols);
468                 }
469
470                 symbols.getParent().layout();
471
472             } catch (DatabaseException e) {
473                 Logger.defaultLogError(e);
474             }
475         }
476
477         void refreshModel() {
478             final String sourceText = source.getText();
479             final String targetText = target.getText();
480             int symbolIndex = symbols.getSelectionIndex();
481             Resource symbol = null;
482             if(symbolIndex > 0) {
483                 @SuppressWarnings("unchecked")
484                 java.util.List<NamedResource> nrs = (java.util.List<NamedResource>)symbols.getData();
485                 symbol = nrs.get(symbolIndex-1).getResource();
486             }
487             final Resource finalSymbol = symbol;
488
489             try {
490                 model = Simantics.getSession().syncRequest(new UniqueRead<MigrateModel>() {
491                     @Override
492                     public MigrateModel perform(ReadGraph graph) throws DatabaseException {
493                         Layer0 L0 = Layer0.getInstance(graph);
494                         StructuralResource2 STR = StructuralResource2.getInstance(graph);
495
496                         Resource source = graph.getPossibleResource(sourceText);
497                         if(source == null) return model;
498                         Resource target = graph.getPossibleResource(targetText);
499                         if(target == null) return model;
500
501                         if(graph.isInstanceOf(source, STR.ComponentType)) {
502                             return UserComponentMigration.getComponentTypeModel(graph, source, target, finalSymbol);
503                         } else if(graph.isInstanceOf(source, L0.SharedOntology)) {
504                             return UserComponentMigration.getSharedOntologyModel(graph, source, target);
505                         } else {
506                             return null;
507                         }
508                     }
509                 });
510             } catch (DatabaseException e) {
511                 Logger.defaultLogError(e);
512             }
513
514             instances.removeAll();
515             locations.removeAll();
516
517             if (model == null)
518                 return;
519
520             int preSelect = -1, i = 0;
521             for (Triple<String,NamedResource,Collection<MigrationOperation>> r : model.instances) {
522                 locations.add(r.second.getName() + " (" + r.third.size() + " instances)");
523                 if (r.first.equals(previouslySelectedLocationId))
524                     preSelect = i;
525                 if (preSelect < 0 && model.activeModels.contains(r.second.getResource()))
526                     preSelect = i;
527                 ++i;
528             }
529             if (locations.getItemCount() == 0) {
530                 locations.add("<no instances were found>");
531                 locations.select(0);
532             } else {
533                 locations.select(preSelect > -1 ? preSelect : 0);
534             }
535         }
536
537         void refreshInstances() {
538
539             int toMigrate = 0;
540             for(Triple<String,NamedResource,Collection<MigrationOperation>> pair : model.instances) {
541                 toMigrate += pair.third.size();
542             }
543
544             if(model.instanceCount == 0)
545                 instanceLabel.setText("No instances were found.");
546             else if(model.instanceCount == 1) {
547                 if(toMigrate == 1) {
548                     instanceLabel.setText("1 migratable instance found.");
549                 } else {
550                     instanceLabel.setText("1 instance found, but it cannot be migrated with current settings.");
551                 }
552             } else {
553                 if(toMigrate < model.instanceCount) {
554                     if(toMigrate == 0) {
555                         instanceLabel.setText(model.instanceCount + " instances were found. None of them can be migrated with current settings.");
556                     } else {
557                         instanceLabel.setText(model.instanceCount + " instances were found. " + (model.instanceCount-toMigrate) + " of them cannot be migrated with current settings.");
558                     }
559                 } else {
560                     instanceLabel.setText(model.instanceCount + " migratable instances found. ");
561                 }
562             }
563
564             instances.removeAll();
565
566             if (model == null)
567                 return;
568
569             if(toMigrate == 0) {
570                 locationsLabel.setVisible(false);
571                 locations.setVisible(false);
572                 GridDataFactory.fillDefaults().exclude(true).applyTo(locationsLabel);
573                 GridDataFactory.fillDefaults().exclude(true).grab(true, false).span(9, 1).applyTo(locations);
574             } else {
575                 locationsLabel.setVisible(true);
576                 locations.setVisible(true);
577                 GridDataFactory.fillDefaults().applyTo(locationsLabel);
578                 GridDataFactory.fillDefaults().grab(true, false).span(9, 1).applyTo(locations);
579             }
580
581             if(!model.instances.isEmpty()) {
582
583                 int locationIndex = locations.getSelectionIndex();
584                 if(locationIndex == -1) return;
585
586                 model.sortedShownInstances = new ArrayList<>();
587                 for(MigrationOperation o : model.instances.get(locationIndex).third)
588                     model.sortedShownInstances.add(o);
589                 Collections.sort(model.sortedShownInstances, MIGRATION_OP_COMPARATOR);
590                 for(MigrationOperation o : model.sortedShownInstances) {
591                     String uri = o.toString();
592                     uri = uri.replace("http://Projects/Development%20Project/", "");
593                     uri = URIStringUtils.unescape(uri);
594                     instances.add(uri);
595                 }
596
597             }
598
599             if(model.sortedShownInstances.isEmpty()) {
600                 instancesLabel.setVisible(false);
601                 instances.setVisible(false);
602                 buttonBar.setVisible(false);
603                 GridDataFactory.fillDefaults().exclude(true).grab(true, false).span(9, 1).applyTo(instancesLabel);
604                 GridDataFactory.fillDefaults().exclude(true).grab(true, true).span(10, 1).applyTo(instances);
605                 GridDataFactory.fillDefaults().exclude(true).grab(true, false).span(10, 1).applyTo(buttonBar);
606             } else {
607                 GridDataFactory.fillDefaults().grab(true, false).span(9, 1).applyTo(instancesLabel);
608                 GridDataFactory.fillDefaults().grab(true, true).span(10, 1).applyTo(instances);
609                 GridDataFactory.fillDefaults().grab(true, false).span(10, 1).applyTo(buttonBar);
610                 instancesLabel.setVisible(true);
611                 instances.setVisible(true);
612                 buttonBar.setVisible(true);
613             }
614
615             locations.getParent().layout();
616
617         }
618
619         Listener validateListener = new Listener() {
620             @Override
621             public void handleEvent(Event event) {
622                 switch (event.type) {
623                     case SWT.Modify:
624                         validatePage();
625                     case SWT.Selection:
626                         validatePage();
627                         break;
628                     case SWT.FocusIn:
629                     {
630                         if (event.widget instanceof Text) {
631                             Text t = (Text) event.widget;
632                             t.selectAll();
633                         }
634                         break;
635                     }
636                 }
637             }
638         };
639
640         private void validatePage() {
641             setMessage(null);
642             setErrorMessage(null);
643             setPageComplete(true);
644         }
645
646     }
647
648     private static final Comparator<MigrationOperation> MIGRATION_OP_COMPARATOR = new Comparator<MigrateModel.MigrationOperation>() {
649         @Override
650         public int compare(MigrationOperation o1, MigrationOperation o2) {
651             return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(o1.instanceToMigrate.getName(), o2.instanceToMigrate.getName());
652         }
653     };
654
655     private static abstract class BrowseContentRequest extends UnaryRead<String, Map<String, Pair<String, ImageDescriptor>>> {
656
657         public BrowseContentRequest(String uri) {
658             super(uri);
659         }
660
661         @Override
662         public Map<String, Pair<String, ImageDescriptor>> perform(ReadGraph graph) throws DatabaseException {
663             Resource root = graph.getPossibleResource(parameter);
664             if (root == null)
665                 return null;
666
667             Map<String, Pair<String, ImageDescriptor>> result = new THashMap<>();
668             Collection<NamedResource> infos = getVersions(graph, root); 
669             for (NamedResource info : infos)
670                 result.put(graph.getURI(info.getResource()), Pair.<String,ImageDescriptor>make(Versions.getStandardPathNameString(graph, info.getResource()), null));
671
672             return result;
673         }
674
675         protected abstract Collection<NamedResource> getVersions(ReadGraph graph, Resource root) throws DatabaseException;
676
677     }
678
679     private static class BrowseSourceContentRequest extends BrowseContentRequest {
680         public BrowseSourceContentRequest(String uri) {
681             super(uri);
682         }
683         @Override
684         protected Collection<NamedResource> getVersions(ReadGraph graph, Resource root) throws DatabaseException {
685             return Versions.getOlderVersions(graph, root);
686         }
687     }
688
689     private static class BrowseTargetContentRequest extends BrowseContentRequest {
690         public BrowseTargetContentRequest(String uri) {
691             super(uri);
692         }
693         @Override
694         protected Collection<NamedResource> getVersions(ReadGraph graph, Resource root) throws DatabaseException {
695             return Versions.getNewerVersions(graph, root);
696         }
697     }
698
699 }