1 /*******************************************************************************
\r
2 * Copyright (c) 2014, 2015 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * Semantum Oy - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.modeling.ui.wizard;
\r
14 import java.lang.reflect.InvocationTargetException;
\r
15 import java.util.ArrayList;
\r
16 import java.util.Collection;
\r
17 import java.util.Collections;
\r
18 import java.util.Comparator;
\r
19 import java.util.Map;
\r
20 import java.util.Set;
\r
22 import org.eclipse.core.runtime.IStatus;
\r
23 import org.eclipse.core.runtime.OperationCanceledException;
\r
24 import org.eclipse.core.runtime.Status;
\r
25 import org.eclipse.core.runtime.SubMonitor;
\r
26 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
\r
27 import org.eclipse.core.runtime.preferences.InstanceScope;
\r
28 import org.eclipse.jface.dialogs.IDialogSettings;
\r
29 import org.eclipse.jface.dialogs.MessageDialog;
\r
30 import org.eclipse.jface.layout.GridDataFactory;
\r
31 import org.eclipse.jface.layout.GridLayoutFactory;
\r
32 import org.eclipse.jface.layout.RowLayoutFactory;
\r
33 import org.eclipse.jface.resource.ImageDescriptor;
\r
34 import org.eclipse.jface.window.Window;
\r
35 import org.eclipse.jface.wizard.Wizard;
\r
36 import org.eclipse.jface.wizard.WizardPage;
\r
37 import org.eclipse.swt.SWT;
\r
38 import org.eclipse.swt.custom.CCombo;
\r
39 import org.eclipse.swt.events.ModifyEvent;
\r
40 import org.eclipse.swt.events.ModifyListener;
\r
41 import org.eclipse.swt.events.SelectionEvent;
\r
42 import org.eclipse.swt.events.SelectionListener;
\r
43 import org.eclipse.swt.graphics.Point;
\r
44 import org.eclipse.swt.layout.GridLayout;
\r
45 import org.eclipse.swt.widgets.Button;
\r
46 import org.eclipse.swt.widgets.Composite;
\r
47 import org.eclipse.swt.widgets.Control;
\r
48 import org.eclipse.swt.widgets.Event;
\r
49 import org.eclipse.swt.widgets.Label;
\r
50 import org.eclipse.swt.widgets.List;
\r
51 import org.eclipse.swt.widgets.Listener;
\r
52 import org.eclipse.swt.widgets.Shell;
\r
53 import org.eclipse.swt.widgets.Text;
\r
54 import org.simantics.Simantics;
\r
55 import org.simantics.databoard.Bindings;
\r
56 import org.simantics.databoard.util.URIStringUtils;
\r
57 import org.simantics.db.ReadGraph;
\r
58 import org.simantics.db.Resource;
\r
59 import org.simantics.db.WriteGraph;
\r
60 import org.simantics.db.common.NamedResource;
\r
61 import org.simantics.db.common.request.ObjectsWithType;
\r
62 import org.simantics.db.common.request.UnaryRead;
\r
63 import org.simantics.db.common.request.UniqueRead;
\r
64 import org.simantics.db.common.request.WriteResultRequest;
\r
65 import org.simantics.db.common.utils.Logger;
\r
66 import org.simantics.db.common.utils.Versions;
\r
67 import org.simantics.db.exception.CancelTransactionException;
\r
68 import org.simantics.db.exception.DatabaseException;
\r
69 import org.simantics.diagram.stubs.DiagramResource;
\r
70 import org.simantics.layer0.Layer0;
\r
71 import org.simantics.modeling.MigrateModel;
\r
72 import org.simantics.modeling.MigrateModel.MigrationOperation;
\r
73 import org.simantics.modeling.ModelingResources;
\r
74 import org.simantics.modeling.UserComponentMigration;
\r
75 import org.simantics.modeling.ui.Activator;
\r
76 import org.simantics.structural.stubs.StructuralResource2;
\r
77 import org.simantics.ui.workbench.dialogs.ResourceSelectionDialog3;
\r
78 import org.simantics.utils.datastructures.Pair;
\r
79 import org.simantics.utils.datastructures.Triple;
\r
80 import org.simantics.utils.strings.AlphanumComparator;
\r
82 import gnu.trove.map.hash.THashMap;
\r
83 import gnu.trove.set.hash.THashSet;
\r
84 import gnu.trove.set.hash.TIntHashSet;
\r
87 * @author Antti Villberg
\r
89 public class MigrateWizard extends Wizard {
\r
91 final String initial;
\r
93 MigratePage migratePage;
\r
95 IEclipsePreferences prefnode;
\r
97 public MigrateWizard(String initial) {
\r
99 this.initial = initial;
\r
101 setWindowTitle("Perform migration");
\r
102 setNeedsProgressMonitor(true);
\r
103 setForcePreviousAndNextButtons(false);
\r
104 setDialogSettings(Activator.getDefault().getDialogSettings());
\r
106 prefnode = InstanceScope.INSTANCE.getNode( "org.simantics.modeling.ui.wizard.MigrateWizard" );
\r
111 public void addPages() {
\r
112 migratePage = new MigratePage(initial);
\r
113 addPage(migratePage);
\r
117 public boolean canFinish() {
\r
118 // if (model.spec.name.isEmpty())
\r
124 public boolean performFinish() {
\r
126 int locationIndex = migratePage.locations.getSelectionIndex();
\r
127 if(locationIndex == -1) return true;
\r
129 if(migratePage.model == null || migratePage.model.instances.isEmpty()) return true;
\r
131 int[] sel = migratePage.instances.getSelectionIndices();
\r
132 TIntHashSet sels = new TIntHashSet();
\r
133 for(int i : sel) sels.add(i);
\r
135 Collection<MigrationOperation> ops = migratePage.model.sortedShownInstances;
\r
137 final ArrayList<MigrationOperation> result = new ArrayList<>();
\r
138 for(MigrationOperation op : ops) {
\r
139 if(sels.contains(index)) result.add(op);
\r
143 if(result.isEmpty()) return true;
\r
146 String[] report = { null };
\r
147 getContainer().run(true, true, monitor -> {
\r
148 SubMonitor mon = SubMonitor.convert(monitor, 1000);
\r
150 report[0] = Simantics.getSession().syncRequest(new WriteResultRequest<String>() {
\r
152 public String perform(WriteGraph graph) throws DatabaseException {
\r
153 graph.markUndoPoint();
\r
154 String report = UserComponentMigration.doMigration(mon.newChild(500, SubMonitor.SUPPRESS_NONE), graph, result);
\r
155 UserComponentMigration.doPostMigration(mon.newChild(500, SubMonitor.SUPPRESS_NONE), graph, result);
\r
156 mon.setTaskName("Committing Changes");
\r
161 } catch (DatabaseException e) {
\r
162 throw new InvocationTargetException(e);
\r
169 ReportDialog md = new ReportDialog(getShell(), report[0], 800, 500);
\r
173 } catch (InvocationTargetException e) {
\r
174 // Don't show user cancellations as errors.
\r
175 Throwable cause = e.getCause();
\r
176 if (!(cause instanceof CancelTransactionException || cause instanceof OperationCanceledException)) {
\r
177 Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
\r
178 "Migration failed, see Error Log for details.", e.getCause()));
\r
180 } catch (InterruptedException e) {
\r
181 Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
\r
182 "Migration interrupted, see Error Log for details.", e));
\r
187 static class ReportDialog extends MessageDialog {
\r
188 private final String report;
\r
189 private final int initialWidth;
\r
190 private final int initialHeight;
\r
192 public ReportDialog(Shell shell, String report, int width, int height) {
\r
194 "Migration report", null,
\r
196 MessageDialog.INFORMATION, new String[] { "Continue" }, 0);
\r
197 this.report = report;
\r
198 this.initialWidth = width;
\r
199 this.initialHeight = height;
\r
203 protected boolean isResizable() {
\r
208 protected Point getInitialSize() {
\r
209 return new Point(initialWidth, initialHeight);
\r
213 protected Control createCustomArea(Composite composite) {
\r
214 GridLayoutFactory.fillDefaults().applyTo(composite);
\r
215 Text text = new Text(composite, SWT.MULTI | SWT.V_SCROLL | SWT.READ_ONLY | SWT.BORDER);
\r
216 text.setText(report);
\r
217 GridDataFactory.fillDefaults().grab(true, true).applyTo(text);
\r
222 abstract static class SelectionAdapter implements SelectionListener {
\r
224 public void widgetDefaultSelected(SelectionEvent e) {
\r
229 class MigratePage extends WizardPage {
\r
233 MigrateModel model;
\r
236 Button browseSource;
\r
238 Button browseTarget;
\r
239 Label symbolsLabel;
\r
241 Label instanceLabel;
\r
242 Label locationsLabel;
\r
244 Composite buttonBar;
\r
245 Label instancesLabel;
\r
249 * ID of the location that has been previously selected by the user.
\r
250 * Used to prevent the location from being reset every time the user
\r
251 * makes a change in any of the other selections.
\r
253 * See first field of {@link MigrateModel#instances}.
\r
255 String previouslySelectedLocationId = null;
\r
257 public MigratePage(String initial) {
\r
258 super("Perform migration", "Perform migration", null);
\r
259 this.initial = initial;
\r
263 public void createControl(Composite parent) {
\r
264 Composite container = new Composite(parent, SWT.NONE);
\r
266 GridLayout layout = new GridLayout();
\r
267 layout.horizontalSpacing = 20;
\r
268 layout.verticalSpacing = 10;
\r
269 layout.numColumns = 10;
\r
270 container.setLayout(layout);
\r
273 new Label(container, SWT.NONE).setText("&Source:");
\r
274 source = new Text(container, SWT.BORDER);
\r
275 source.setText(initial);
\r
276 source.addModifyListener(new ModifyListener() {
\r
278 public void modifyText(ModifyEvent e) {
\r
280 refreshInstances();
\r
283 GridDataFactory.fillDefaults().grab(true, false).span(8, 1).applyTo(source);
\r
285 browseSource = new Button(container, SWT.NONE);
\r
286 browseSource.setText("&Browse");
\r
287 GridDataFactory.fillDefaults().grab(false, false).applyTo(browseSource);
\r
288 browseSource.addSelectionListener(new SelectionAdapter() {
\r
290 public void widgetSelected(SelectionEvent e_) {
\r
292 Map<String, Pair<String, ImageDescriptor>> map = Simantics.getSession().syncRequest(new BrowseSourceContentRequest(target.getText()));
\r
293 String uri = queryTargetSelection("Select Source Type", map);
\r
295 source.setText(uri);
\r
296 } catch (DatabaseException e) {
\r
297 Logger.defaultLogError(e);
\r
302 new Label(container, SWT.NONE).setText("&Target:");
\r
303 target = new Text(container, SWT.BORDER);
\r
304 target.setText(initial);
\r
305 target.addModifyListener(new ModifyListener() {
\r
307 public void modifyText(ModifyEvent e) {
\r
310 refreshInstances();
\r
313 GridDataFactory.fillDefaults().grab(true, false).span(8, 1).applyTo(target);
\r
315 browseTarget = new Button(container, SWT.NONE);
\r
316 browseTarget.setText("B&rowse");
\r
317 GridDataFactory.fillDefaults().grab(false, false).applyTo(browseTarget);
\r
318 browseTarget.addSelectionListener(new SelectionAdapter() {
\r
320 public void widgetSelected(SelectionEvent e_) {
\r
322 Map<String, Pair<String, ImageDescriptor>> map = Simantics.getSession().syncRequest(new BrowseTargetContentRequest(source.getText()));
\r
323 String uri = queryTargetSelection("Select Target Type", map);
\r
325 target.setText(uri);
\r
326 } catch (DatabaseException e) {
\r
327 Logger.defaultLogError(e);
\r
332 symbolsLabel = new Label(container, SWT.NONE);
\r
333 symbolsLabel.setText("Target &symbol:");
\r
334 GridDataFactory.fillDefaults().applyTo(symbolsLabel);
\r
336 symbols = new CCombo(container, SWT.BORDER | SWT.READ_ONLY);
\r
337 symbols.setVisibleItemCount(10);
\r
338 symbols.addSelectionListener(new SelectionAdapter() {
\r
340 public void widgetSelected(SelectionEvent e) {
\r
342 refreshInstances();
\r
345 GridDataFactory.fillDefaults().grab(true, false).span(9, 1).applyTo(symbols);
\r
347 instanceLabel = new Label(container, SWT.NONE);
\r
348 GridDataFactory.fillDefaults().grab(true, false).span(10, 1).applyTo(instanceLabel);
\r
349 instanceLabel.setText("");
\r
351 locationsLabel = new Label(container, SWT.NONE);
\r
352 locationsLabel.setText("&Locations:");
\r
353 locations = new CCombo(container, SWT.BORDER | SWT.READ_ONLY);
\r
354 locations.setVisibleItemCount(25);
\r
355 locations.addSelectionListener(new SelectionAdapter() {
\r
357 public void widgetSelected(SelectionEvent e) {
\r
358 int index = locations.getSelectionIndex();
\r
359 if (index >= 0 && index < model.instances.size()) {
\r
360 previouslySelectedLocationId = model.instances.get(index).first;
\r
362 refreshInstances();
\r
365 GridDataFactory.fillDefaults().grab(true, false).span(9, 1).applyTo(locations);
\r
367 instancesLabel = new Label(container, SWT.NONE);
\r
368 instancesLabel.setText("&Select instances to migrate:");
\r
369 GridDataFactory.fillDefaults().grab(true, false).span(10, 1).applyTo(instancesLabel);
\r
371 buttonBar = new Composite(container, SWT.NONE);
\r
372 RowLayoutFactory.fillDefaults().type(SWT.HORIZONTAL).applyTo(buttonBar);
\r
373 GridDataFactory.fillDefaults().grab(true, false).span(10, 1).applyTo(buttonBar);
\r
374 Button selectAll = new Button(buttonBar, SWT.PUSH);
\r
375 selectAll.setText("Select &All");
\r
376 Button selectNone = new Button(buttonBar, SWT.PUSH);
\r
377 selectNone.setText("Select &None");
\r
378 selectAll.addSelectionListener(new SelectionAdapter() {
\r
380 public void widgetSelected(SelectionEvent e) {
\r
381 instances.selectAll();
\r
384 selectNone.addSelectionListener(new SelectionAdapter() {
\r
386 public void widgetSelected(SelectionEvent e) {
\r
387 instances.deselectAll();
\r
391 instances = new List(container, SWT.MULTI | SWT.WRAP | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
\r
392 GridDataFactory.fillDefaults().grab(true, true).span(10, 1).applyTo(instances);
\r
393 instances.addListener(SWT.Modify, validateListener);
\r
397 refreshInstances();
\r
399 setControl(container);
\r
403 String queryTargetSelection(String title, Map<String, Pair<String, ImageDescriptor>> map) {
\r
404 Shell shell = source.getShell();
\r
405 ResourceSelectionDialog3<String> dialog = new ResourceSelectionDialog3<String>(shell, map, title, false) {
\r
407 protected IDialogSettings getBaseDialogSettings() {
\r
408 return Activator.getDefault().getDialogSettings();
\r
411 if (dialog.open() == Window.OK)
\r
412 return (String) dialog.getFirstResult();
\r
416 void refreshSymbols() {
\r
419 final String uri = target.getText();
\r
421 Collection<NamedResource> syms = Simantics.getSession().syncRequest(new UniqueRead<Collection<NamedResource>>() {
\r
424 public Collection<NamedResource> perform(ReadGraph graph) throws DatabaseException {
\r
426 Layer0 L0 = Layer0.getInstance(graph);
\r
427 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
428 ModelingResources MOD = ModelingResources.getInstance(graph);
\r
430 Set<NamedResource> result = new THashSet<>();
\r
431 Resource componentType = graph.getResource(uri);
\r
433 Set<Resource> potentialSymbols = new THashSet<>();
\r
434 potentialSymbols.addAll(graph.syncRequest(new ObjectsWithType(componentType, L0.ConsistsOf, DIA.ElementClass)));
\r
435 potentialSymbols.addAll(graph.getObjects(componentType, MOD.ComponentTypeToSymbol));
\r
437 for(Resource symbol : potentialSymbols) {
\r
438 if(!graph.hasStatement(symbol, MOD.SymbolToComponentType, componentType)) continue;
\r
439 String name = graph.getRelatedValue(symbol, L0.HasName, Bindings.STRING);
\r
440 if(graph.hasStatement(symbol, MOD.SymbolToComponentType, componentType))
\r
441 result.add(new NamedResource(name, symbol));
\r
444 return new ArrayList<>(result);
\r
450 symbols.removeAll();
\r
451 symbols.add("<retain symbol name>");
\r
452 for(NamedResource nr : syms) {
\r
453 symbols.add(nr.getName());
\r
455 symbols.setData(syms);
\r
458 if(syms.isEmpty()) {
\r
459 symbolsLabel.setVisible(false);
\r
460 symbols.setVisible(false);
\r
461 GridDataFactory.fillDefaults().exclude(true).applyTo(symbolsLabel);
\r
462 GridDataFactory.fillDefaults().exclude(true).grab(true, false).span(9, 1).applyTo(symbols);
\r
464 symbolsLabel.setVisible(true);
\r
465 symbols.setVisible(true);
\r
466 GridDataFactory.fillDefaults().applyTo(symbolsLabel);
\r
467 GridDataFactory.fillDefaults().grab(true, false).span(9, 1).applyTo(symbols);
\r
470 symbols.getParent().layout();
\r
472 } catch (DatabaseException e) {
\r
473 Logger.defaultLogError(e);
\r
477 void refreshModel() {
\r
478 final String sourceText = source.getText();
\r
479 final String targetText = target.getText();
\r
480 int symbolIndex = symbols.getSelectionIndex();
\r
481 Resource symbol = null;
\r
482 if(symbolIndex > 0) {
\r
483 @SuppressWarnings("unchecked")
\r
484 java.util.List<NamedResource> nrs = (java.util.List<NamedResource>)symbols.getData();
\r
485 symbol = nrs.get(symbolIndex-1).getResource();
\r
487 final Resource finalSymbol = symbol;
\r
490 model = Simantics.getSession().syncRequest(new UniqueRead<MigrateModel>() {
\r
492 public MigrateModel perform(ReadGraph graph) throws DatabaseException {
\r
493 Layer0 L0 = Layer0.getInstance(graph);
\r
494 StructuralResource2 STR = StructuralResource2.getInstance(graph);
\r
496 Resource source = graph.getPossibleResource(sourceText);
\r
497 if(source == null) return model;
\r
498 Resource target = graph.getPossibleResource(targetText);
\r
499 if(target == null) return model;
\r
501 if(graph.isInstanceOf(source, STR.ComponentType)) {
\r
502 return UserComponentMigration.getComponentTypeModel(graph, source, target, finalSymbol);
\r
503 } else if(graph.isInstanceOf(source, L0.SharedOntology)) {
\r
504 return UserComponentMigration.getSharedOntologyModel(graph, source, target);
\r
510 } catch (DatabaseException e) {
\r
511 Logger.defaultLogError(e);
\r
514 instances.removeAll();
\r
515 locations.removeAll();
\r
520 int preSelect = -1, i = 0;
\r
521 for (Triple<String,NamedResource,Collection<MigrationOperation>> r : model.instances) {
\r
522 locations.add(r.second.getName() + " (" + r.third.size() + " instances)");
\r
523 if (r.first.equals(previouslySelectedLocationId))
\r
525 if (preSelect < 0 && model.activeModels.contains(r.second.getResource()))
\r
529 if (locations.getItemCount() == 0) {
\r
530 locations.add("<no instances were found>");
\r
531 locations.select(0);
\r
533 locations.select(preSelect > -1 ? preSelect : 0);
\r
537 void refreshInstances() {
\r
540 for(Triple<String,NamedResource,Collection<MigrationOperation>> pair : model.instances) {
\r
541 toMigrate += pair.third.size();
\r
544 if(model.instanceCount == 0)
\r
545 instanceLabel.setText("No instances were found.");
\r
546 else if(model.instanceCount == 1) {
\r
547 if(toMigrate == 1) {
\r
548 instanceLabel.setText("1 migratable instance found.");
\r
550 instanceLabel.setText("1 instance found, but it cannot be migrated with current settings.");
\r
553 if(toMigrate < model.instanceCount) {
\r
554 if(toMigrate == 0) {
\r
555 instanceLabel.setText(model.instanceCount + " instances were found. None of them can be migrated with current settings.");
\r
557 instanceLabel.setText(model.instanceCount + " instances were found. " + (model.instanceCount-toMigrate) + " of them cannot be migrated with current settings.");
\r
560 instanceLabel.setText(model.instanceCount + " migratable instances found. ");
\r
564 instances.removeAll();
\r
569 if(toMigrate == 0) {
\r
570 locationsLabel.setVisible(false);
\r
571 locations.setVisible(false);
\r
572 GridDataFactory.fillDefaults().exclude(true).applyTo(locationsLabel);
\r
573 GridDataFactory.fillDefaults().exclude(true).grab(true, false).span(9, 1).applyTo(locations);
\r
575 locationsLabel.setVisible(true);
\r
576 locations.setVisible(true);
\r
577 GridDataFactory.fillDefaults().applyTo(locationsLabel);
\r
578 GridDataFactory.fillDefaults().grab(true, false).span(9, 1).applyTo(locations);
\r
581 if(!model.instances.isEmpty()) {
\r
583 int locationIndex = locations.getSelectionIndex();
\r
584 if(locationIndex == -1) return;
\r
586 model.sortedShownInstances = new ArrayList<>();
\r
587 for(MigrationOperation o : model.instances.get(locationIndex).third)
\r
588 model.sortedShownInstances.add(o);
\r
589 Collections.sort(model.sortedShownInstances, MIGRATION_OP_COMPARATOR);
\r
590 for(MigrationOperation o : model.sortedShownInstances) {
\r
591 String uri = o.toString();
\r
592 uri = uri.replace("http://Projects/Development%20Project/", "");
\r
593 uri = URIStringUtils.unescape(uri);
\r
594 instances.add(uri);
\r
599 if(model.sortedShownInstances.isEmpty()) {
\r
600 instancesLabel.setVisible(false);
\r
601 instances.setVisible(false);
\r
602 buttonBar.setVisible(false);
\r
603 GridDataFactory.fillDefaults().exclude(true).grab(true, false).span(9, 1).applyTo(instancesLabel);
\r
604 GridDataFactory.fillDefaults().exclude(true).grab(true, true).span(10, 1).applyTo(instances);
\r
605 GridDataFactory.fillDefaults().exclude(true).grab(true, false).span(10, 1).applyTo(buttonBar);
\r
607 GridDataFactory.fillDefaults().grab(true, false).span(9, 1).applyTo(instancesLabel);
\r
608 GridDataFactory.fillDefaults().grab(true, true).span(10, 1).applyTo(instances);
\r
609 GridDataFactory.fillDefaults().grab(true, false).span(10, 1).applyTo(buttonBar);
\r
610 instancesLabel.setVisible(true);
\r
611 instances.setVisible(true);
\r
612 buttonBar.setVisible(true);
\r
615 locations.getParent().layout();
\r
619 Listener validateListener = new Listener() {
\r
621 public void handleEvent(Event event) {
\r
622 switch (event.type) {
\r
625 case SWT.Selection:
\r
630 if (event.widget instanceof Text) {
\r
631 Text t = (Text) event.widget;
\r
640 private void validatePage() {
\r
642 setErrorMessage(null);
\r
643 setPageComplete(true);
\r
648 private static final Comparator<MigrationOperation> MIGRATION_OP_COMPARATOR = new Comparator<MigrateModel.MigrationOperation>() {
\r
650 public int compare(MigrationOperation o1, MigrationOperation o2) {
\r
651 return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(o1.instanceToMigrate.getName(), o2.instanceToMigrate.getName());
\r
655 private static abstract class BrowseContentRequest extends UnaryRead<String, Map<String, Pair<String, ImageDescriptor>>> {
\r
657 public BrowseContentRequest(String uri) {
\r
662 public Map<String, Pair<String, ImageDescriptor>> perform(ReadGraph graph) throws DatabaseException {
\r
663 Resource root = graph.getPossibleResource(parameter);
\r
667 Map<String, Pair<String, ImageDescriptor>> result = new THashMap<>();
\r
668 Collection<NamedResource> infos = getVersions(graph, root);
\r
669 for (NamedResource info : infos)
\r
670 result.put(graph.getURI(info.getResource()), Pair.<String,ImageDescriptor>make(Versions.getStandardPathNameString(graph, info.getResource()), null));
\r
675 protected abstract Collection<NamedResource> getVersions(ReadGraph graph, Resource root) throws DatabaseException;
\r
679 private static class BrowseSourceContentRequest extends BrowseContentRequest {
\r
680 public BrowseSourceContentRequest(String uri) {
\r
684 protected Collection<NamedResource> getVersions(ReadGraph graph, Resource root) throws DatabaseException {
\r
685 return Versions.getOlderVersions(graph, root);
\r
689 private static class BrowseTargetContentRequest extends BrowseContentRequest {
\r
690 public BrowseTargetContentRequest(String uri) {
\r
694 protected Collection<NamedResource> getVersions(ReadGraph graph, Resource root) throws DatabaseException {
\r
695 return Versions.getNewerVersions(graph, root);
\r