-/*******************************************************************************\r
- * Copyright (c) 2012 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.modeling.ui.actions;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Arrays;\r
-import java.util.Collection;\r
-import java.util.Collections;\r
-import java.util.HashSet;\r
-import java.util.List;\r
-import java.util.Set;\r
-import java.util.concurrent.atomic.AtomicReference;\r
-\r
-import org.eclipse.jface.dialogs.Dialog;\r
-import org.eclipse.jface.dialogs.IInputValidator;\r
-import org.eclipse.jface.dialogs.InputDialog;\r
-import org.eclipse.jface.dialogs.MessageDialog;\r
-import org.eclipse.jface.viewers.ICheckStateProvider;\r
-import org.eclipse.jface.viewers.IStructuredContentProvider;\r
-import org.eclipse.jface.viewers.LabelProvider;\r
-import org.eclipse.jface.viewers.Viewer;\r
-import org.eclipse.swt.widgets.Shell;\r
-import org.eclipse.ui.PlatformUI;\r
-import org.simantics.Simantics;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.WriteGraph;\r
-import org.simantics.db.common.request.PossibleIndexRoot;\r
-import org.simantics.db.common.request.UniqueRead;\r
-import org.simantics.db.common.request.WriteRequest;\r
-import org.simantics.db.common.utils.NameUtils;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.layer0.adapter.ActionFactory;\r
-import org.simantics.db.layer0.adapter.ActionFactory2;\r
-import org.simantics.db.request.Read;\r
-import org.simantics.diagram.stubs.DiagramResource;\r
-import org.simantics.modeling.AssignSymbolGroupRequest;\r
-import org.simantics.modeling.GetSymbolGroups;\r
-import org.simantics.modeling.NewSymbolGroupRequest;\r
-import org.simantics.utils.strings.AlphanumComparator;\r
-import org.simantics.utils.ui.ErrorLogger;\r
-import org.simantics.utils.ui.dialogs.ShowMessage;\r
-\r
-/**\r
- * @author Hannu Niemistö\r
- * @author Tuukka Lehtonen <tuukka.lehtonen@semantum.fi>\r
- */\r
-public class AssignSymbolGroup implements ActionFactory, ActionFactory2 {\r
-\r
- @Override\r
- public Runnable create(Collection<?> targets) {\r
- final ArrayList<Resource> resources = new ArrayList<Resource>();\r
- for (Object target : targets) {\r
- if (!(target instanceof Resource))\r
- return null;\r
- resources.add((Resource) target);\r
- }\r
- return new Runnable() {\r
- @Override\r
- public void run() {\r
- assignGroups(resources);\r
- \r
- }\r
- };\r
- }\r
-\r
- @Override\r
- public Runnable create(Object target) {\r
- if(!(target instanceof Resource))\r
- return null;\r
- final Resource symbol = (Resource)target;\r
- return new Runnable() {\r
- @Override\r
- public void run() {\r
- assignGroups(Collections.singletonList(symbol));\r
- }\r
- };\r
- }\r
-\r
- private static final SymbolGroup[] NO_SYMBOL_GROUPS = new SymbolGroup[0];\r
-\r
- static enum Tristate {\r
- NONE, SOME, ALL;\r
-\r
- public static Tristate add(Tristate current, boolean next) {\r
- if (current == null)\r
- return next ? ALL : NONE;\r
- switch (current) {\r
- case ALL: return next ? ALL : SOME; \r
- case SOME: return next ? SOME : SOME;\r
- case NONE: return next ? SOME : NONE;\r
- default: return NONE;\r
- }\r
- }\r
- }\r
-\r
- private static class SymbolGroup implements Comparable<SymbolGroup> {\r
- Resource resource;\r
- String name;\r
- Tristate originallySelected;\r
- Tristate selected;\r
-\r
- public SymbolGroup(Resource resource, String name, Tristate originallySelected, Tristate selected) {\r
- super();\r
- this.resource = resource;\r
- this.name = name;\r
- this.originallySelected = originallySelected;\r
- this.selected = selected;\r
- }\r
-\r
- @Override\r
- public int compareTo(SymbolGroup o) {\r
- return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(name, o.name);\r
- }\r
-\r
- @Override\r
- public String toString() {\r
- return getClass().getSimpleName() + "[name=" + name\r
- + ", originally selected=" + originallySelected\r
- + ", selected=" + selected + "]";\r
- }\r
- }\r
-\r
- private static class ContentProviderImpl implements IStructuredContentProvider { \r
- @Override\r
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {\r
- }\r
-\r
- @Override\r
- public void dispose() {\r
- }\r
-\r
- @Override\r
- public Object[] getElements(Object inputElement) {\r
- return (Object[])inputElement;\r
- }\r
- };\r
-\r
- private static class LabelProviderImpl extends LabelProvider {\r
- @Override\r
- public String getText(Object element) {\r
- return ((SymbolGroup)element).name;\r
- }\r
- }\r
-\r
- private static class CheckStateProviderImpl implements ICheckStateProvider {\r
- @Override\r
- public boolean isChecked(Object element) {\r
- return ((SymbolGroup) element).selected != Tristate.NONE;\r
- }\r
- @Override\r
- public boolean isGrayed(Object element) {\r
- return ((SymbolGroup) element).selected == Tristate.SOME;\r
- }\r
- }\r
-\r
- private static Resource getCommonModel(final Collection<Resource> symbols) {\r
- try {\r
- return Simantics.sync(new UniqueRead<Resource>() {\r
- @Override\r
- public Resource perform(ReadGraph graph) throws DatabaseException {\r
- return getPossibleIndexRoot(graph, symbols);\r
- }\r
- });\r
- } catch (DatabaseException e) {\r
- ErrorLogger.defaultLogError(e);\r
- return null;\r
- }\r
- }\r
-\r
- private static Resource getPossibleIndexRoot(ReadGraph g, Collection<Resource> symbols) throws DatabaseException {\r
- Resource model = null;\r
- for (Resource symbol : symbols) {\r
- Resource m = getIndexRootOf(g, symbol);\r
- if (m == null)\r
- return null;\r
- if (model == null)\r
- model = m;\r
- else if (!model.equals(m))\r
- return null;\r
- }\r
- return model;\r
- }\r
-\r
- private static Resource getIndexRootOf(ReadGraph g, Resource symbol) throws DatabaseException {\r
- return g.syncRequest(new PossibleIndexRoot(symbol));\r
- }\r
-\r
- private static SymbolGroup[] getSymbolGroups(final Collection<Resource> symbols) {\r
- try {\r
- return Simantics.getSession().syncRequest(new Read<SymbolGroup[]>() {\r
- @Override\r
- public SymbolGroup[] perform(ReadGraph g) throws DatabaseException {\r
- return getSymbolGroups(g, symbols);\r
- }\r
- });\r
- } catch(DatabaseException e) {\r
- e.printStackTrace();\r
- return NO_SYMBOL_GROUPS;\r
- }\r
- }\r
-\r
- private static SymbolGroup[] getSymbolGroups(ReadGraph g, Collection<Resource> symbols) throws DatabaseException {\r
- Resource model = getPossibleIndexRoot(g, symbols);\r
- if (model == null)\r
- return NO_SYMBOL_GROUPS;\r
- // All symbols have same model.\r
- // Resolve the symbol group selection states now.\r
- ArrayList<SymbolGroup> result = new ArrayList<SymbolGroup>();\r
- DiagramResource DIA = DiagramResource.getInstance(g);\r
- for (Resource library : GetSymbolGroups.getSymbolGroups(g, model)) {\r
- Tristate selected = getLibrarySelectionState(g, library, symbols, DIA);\r
- selected = selected != null ? selected : Tristate.NONE;\r
- result.add( new SymbolGroup(\r
- library,\r
- NameUtils.getSafeLabel(g, library),\r
- selected,\r
- selected) );\r
- }\r
- //System.out.println("result: " + EString.implode(result));\r
- Collections.sort(result);\r
- //System.out.println("sorted result: " + EString.implode(result));\r
- return result.toArray(new SymbolGroup[result.size()]);\r
- }\r
-\r
- protected static Tristate getLibrarySelectionState(ReadGraph graph, Resource library,\r
- Collection<Resource> symbols, DiagramResource DIA) throws DatabaseException {\r
- Tristate selected = null;\r
- for (Resource symbol : symbols) {\r
- selected = Tristate.add(selected, graph.hasStatement(library, DIA.HasSymbol, symbol));\r
- }\r
- return selected != null ? selected : Tristate.NONE;\r
- }\r
-\r
- private static SymbolGroup[] selectedElements(SymbolGroup[] symbolGroups) {\r
- int count = 0;\r
- for(SymbolGroup g : symbolGroups)\r
- if(g.selected != Tristate.NONE)\r
- ++count;\r
- SymbolGroup[] result = new SymbolGroup[count];\r
- count = 0;\r
- for(SymbolGroup g : symbolGroups)\r
- if(g.selected != Tristate.NONE)\r
- result[count++] = g;\r
- return result;\r
- }\r
-\r
- public void assignGroups(final Collection<Resource> symbols) {\r
- if (symbols.isEmpty())\r
- return;\r
-\r
- final Resource model = getCommonModel(symbols);\r
- if (model == null) {\r
- ShowMessage.showInformation("Same Model Required", "All the selected symbols must be from within the same model.");\r
- return;\r
- }\r
-\r
- final AtomicReference<SymbolGroup[]> groups =\r
- new AtomicReference<SymbolGroup[]>( getSymbolGroups(symbols) );\r
-\r
- StringBuilder message = new StringBuilder();\r
- message.append("Select symbol groups the selected ");\r
- if (symbols.size() > 1)\r
- message.append(symbols.size()).append(" symbols are shown in.");\r
- else\r
- message.append("symbol is shown in.");\r
-\r
- AssignSymbolGroupsDialog dialog = new AssignSymbolGroupsDialog(\r
- PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),\r
- groups.get(),\r
- new ContentProviderImpl(), \r
- new LabelProviderImpl(), \r
- new CheckStateProviderImpl(),\r
- message.toString()) {\r
-\r
- @Override\r
- protected void checkStateChanged(Object[] elements, boolean checked) {\r
- for (Object _g : elements) {\r
- SymbolGroup g = (SymbolGroup) _g;\r
- g.selected = checked ? Tristate.ALL : Tristate.NONE;\r
- // Refresh checked states through provider.\r
- listViewer.refresh();\r
- }\r
- }\r
-\r
- @Override\r
- protected void newAction() {\r
- SymbolGroup newGroup = newSymbolGroup(getShell(), model, (SymbolGroup[])inputElement);\r
- if (newGroup != null) {\r
- // Select the new library by default.\r
- newGroup.selected = Tristate.ALL;\r
-\r
- SymbolGroup[] newGroups = (SymbolGroup[]) inputElement;\r
- newGroups = Arrays.copyOf(newGroups, newGroups.length+1);\r
- newGroups[newGroups.length-1] = newGroup;\r
- Arrays.sort(newGroups);\r
- listViewer.setInput(newGroups);\r
- inputElement = newGroups;\r
- groups.set(newGroups);\r
- }\r
- }\r
-\r
- @Override\r
- protected void deleteAction(Object[] array) {\r
- SymbolGroup[] groupsToRemove = Arrays.copyOf(array, array.length, SymbolGroup[].class);\r
- if (removeSymbolGroups(getShell(), groupsToRemove)) {\r
- listViewer.remove(groupsToRemove);\r
- Set<SymbolGroup> removedGroups = new HashSet<SymbolGroup>();\r
- for (SymbolGroup removed : groupsToRemove)\r
- removedGroups.add(removed);\r
- List<SymbolGroup> newGroups = new ArrayList<SymbolGroup>(groups.get().length);\r
- for (SymbolGroup old : groups.get()) {\r
- if (!removedGroups.contains(old))\r
- newGroups.add(old);\r
- }\r
- groups.set( newGroups.toArray(NO_SYMBOL_GROUPS) );\r
- }\r
- }\r
- };\r
- dialog.setTitle("Symbol Group Assignments");\r
- dialog.setInitialSelections(selectedElements(groups.get()));\r
- if (dialog.open() == Dialog.OK) {\r
- final ArrayList<SymbolGroup> added = new ArrayList<SymbolGroup>();\r
- final ArrayList<SymbolGroup> removed = new ArrayList<SymbolGroup>();\r
- for (SymbolGroup g : groups.get()) {\r
- if (g.selected != g.originallySelected && g.selected == Tristate.ALL)\r
- added.add(g);\r
- if (g.selected != g.originallySelected && g.selected == Tristate.NONE)\r
- removed.add(g);\r
- }\r
- if (!added.isEmpty() || !removed.isEmpty()) {\r
- ArrayList<Resource> addedSymbolGroups = new ArrayList<Resource>();\r
- ArrayList<Resource> removedSymbolGroups = new ArrayList<Resource>();\r
- for (SymbolGroup group : added)\r
- addedSymbolGroups.add(group.resource);\r
- for (SymbolGroup group : removed)\r
- removedSymbolGroups.add(group.resource);\r
- Simantics.getSession().asyncRequest(new AssignSymbolGroupRequest(addedSymbolGroups, removedSymbolGroups, symbols));\r
- }\r
- }\r
- }\r
-\r
- private static SymbolGroup newSymbolGroup(Shell shell, Resource model, final SymbolGroup[] oldGroups) {\r
- InputDialog dialog = new InputDialog(shell,\r
- "New Symbol Group",\r
- "Write the name of the new symbol group.",\r
- "NewSymbolGroup",\r
- new IInputValidator() {\r
- @Override\r
- public String isValid(String newText) {\r
- newText = newText.trim();\r
- if (newText.isEmpty())\r
- return "The name must be non-empty.";\r
- for (SymbolGroup g : oldGroups)\r
- if (newText.equals(g.name))\r
- return "A symbol group with that name already exists.";\r
- return null;\r
- }\r
- }\r
- );\r
- if (dialog.open() == Dialog.OK) {\r
- String name = dialog.getValue();\r
- try {\r
- NewSymbolGroupRequest request = new NewSymbolGroupRequest(name, model);\r
- Resource symbolGroup = Simantics.getSession().syncRequest(request);\r
- if (symbolGroup == null)\r
- return null;\r
- return new SymbolGroup(symbolGroup, name, Tristate.NONE, Tristate.NONE);\r
- } catch (DatabaseException e) {\r
- ErrorLogger.defaultLogError(e);\r
- return null;\r
- }\r
- }\r
- return null;\r
- }\r
-\r
- private boolean removeSymbolGroups(Shell shell, final SymbolGroup[] groups) {\r
- if (groups.length == 0)\r
- return false;\r
- String message;\r
- if (groups.length == 1)\r
- message = "Are you sure you want to remove symbol group '" + groups[0].name + "' ?";\r
- else\r
- message = "Are you sure you want to remove " + groups.length + " symbol groups?";\r
- MessageDialog dialog = \r
- new MessageDialog(shell, "Confirm removal", null, message, MessageDialog.QUESTION, new String[] { "OK", "Cancel" }, 0);\r
- if (dialog.open() == Dialog.OK) {\r
- Simantics.getSession().asyncRequest(new WriteRequest() {\r
- @Override\r
- public void perform(WriteGraph graph) throws DatabaseException {\r
- for (SymbolGroup group : groups)\r
- graph.deny(group.resource);\r
- }\r
- });\r
- return true;\r
- }\r
- else\r
- return false;\r
- }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2012 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.modeling.ui.actions;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ICheckStateProvider;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+import org.simantics.Simantics;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.request.PossibleIndexRoot;
+import org.simantics.db.common.request.UniqueRead;
+import org.simantics.db.common.request.WriteRequest;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.adapter.ActionFactory;
+import org.simantics.db.layer0.adapter.ActionFactory2;
+import org.simantics.db.request.Read;
+import org.simantics.diagram.stubs.DiagramResource;
+import org.simantics.modeling.AssignSymbolGroupRequest;
+import org.simantics.modeling.GetSymbolGroups;
+import org.simantics.modeling.NewSymbolGroupRequest;
+import org.simantics.utils.strings.AlphanumComparator;
+import org.simantics.utils.ui.ErrorLogger;
+import org.simantics.utils.ui.dialogs.ShowMessage;
+
+/**
+ * @author Hannu Niemistö
+ * @author Tuukka Lehtonen <tuukka.lehtonen@semantum.fi>
+ */
+public class AssignSymbolGroup implements ActionFactory, ActionFactory2 {
+
+ @Override
+ public Runnable create(Collection<?> targets) {
+ final ArrayList<Resource> resources = new ArrayList<Resource>();
+ for (Object target : targets) {
+ if (!(target instanceof Resource))
+ return null;
+ resources.add((Resource) target);
+ }
+ return new Runnable() {
+ @Override
+ public void run() {
+ assignGroups(resources);
+
+ }
+ };
+ }
+
+ @Override
+ public Runnable create(Object target) {
+ if(!(target instanceof Resource))
+ return null;
+ final Resource symbol = (Resource)target;
+ return new Runnable() {
+ @Override
+ public void run() {
+ assignGroups(Collections.singletonList(symbol));
+ }
+ };
+ }
+
+ private static final SymbolGroup[] NO_SYMBOL_GROUPS = new SymbolGroup[0];
+
+ static enum Tristate {
+ NONE, SOME, ALL;
+
+ public static Tristate add(Tristate current, boolean next) {
+ if (current == null)
+ return next ? ALL : NONE;
+ switch (current) {
+ case ALL: return next ? ALL : SOME;
+ case SOME: return next ? SOME : SOME;
+ case NONE: return next ? SOME : NONE;
+ default: return NONE;
+ }
+ }
+ }
+
+ private static class SymbolGroup implements Comparable<SymbolGroup> {
+ Resource resource;
+ String name;
+ Tristate originallySelected;
+ Tristate selected;
+
+ public SymbolGroup(Resource resource, String name, Tristate originallySelected, Tristate selected) {
+ super();
+ this.resource = resource;
+ this.name = name;
+ this.originallySelected = originallySelected;
+ this.selected = selected;
+ }
+
+ @Override
+ public int compareTo(SymbolGroup o) {
+ return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(name, o.name);
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "[name=" + name
+ + ", originally selected=" + originallySelected
+ + ", selected=" + selected + "]";
+ }
+ }
+
+ private static class ContentProviderImpl implements IStructuredContentProvider {
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public Object[] getElements(Object inputElement) {
+ return (Object[])inputElement;
+ }
+ };
+
+ private static class LabelProviderImpl extends LabelProvider {
+ @Override
+ public String getText(Object element) {
+ return ((SymbolGroup)element).name;
+ }
+ }
+
+ private static class CheckStateProviderImpl implements ICheckStateProvider {
+ @Override
+ public boolean isChecked(Object element) {
+ return ((SymbolGroup) element).selected != Tristate.NONE;
+ }
+ @Override
+ public boolean isGrayed(Object element) {
+ return ((SymbolGroup) element).selected == Tristate.SOME;
+ }
+ }
+
+ private static Resource getCommonModel(final Collection<Resource> symbols) {
+ try {
+ return Simantics.sync(new UniqueRead<Resource>() {
+ @Override
+ public Resource perform(ReadGraph graph) throws DatabaseException {
+ return getPossibleIndexRoot(graph, symbols);
+ }
+ });
+ } catch (DatabaseException e) {
+ ErrorLogger.defaultLogError(e);
+ return null;
+ }
+ }
+
+ private static Resource getPossibleIndexRoot(ReadGraph g, Collection<Resource> symbols) throws DatabaseException {
+ Resource model = null;
+ for (Resource symbol : symbols) {
+ Resource m = getIndexRootOf(g, symbol);
+ if (m == null)
+ return null;
+ if (model == null)
+ model = m;
+ else if (!model.equals(m))
+ return null;
+ }
+ return model;
+ }
+
+ private static Resource getIndexRootOf(ReadGraph g, Resource symbol) throws DatabaseException {
+ return g.syncRequest(new PossibleIndexRoot(symbol));
+ }
+
+ private static SymbolGroup[] getSymbolGroups(final Collection<Resource> symbols) {
+ try {
+ return Simantics.getSession().syncRequest(new Read<SymbolGroup[]>() {
+ @Override
+ public SymbolGroup[] perform(ReadGraph g) throws DatabaseException {
+ return getSymbolGroups(g, symbols);
+ }
+ });
+ } catch(DatabaseException e) {
+ e.printStackTrace();
+ return NO_SYMBOL_GROUPS;
+ }
+ }
+
+ private static SymbolGroup[] getSymbolGroups(ReadGraph g, Collection<Resource> symbols) throws DatabaseException {
+ Resource model = getPossibleIndexRoot(g, symbols);
+ if (model == null)
+ return NO_SYMBOL_GROUPS;
+ // All symbols have same model.
+ // Resolve the symbol group selection states now.
+ ArrayList<SymbolGroup> result = new ArrayList<SymbolGroup>();
+ DiagramResource DIA = DiagramResource.getInstance(g);
+ for (Resource library : GetSymbolGroups.getSymbolGroups(g, model)) {
+ Tristate selected = getLibrarySelectionState(g, library, symbols, DIA);
+ selected = selected != null ? selected : Tristate.NONE;
+ result.add( new SymbolGroup(
+ library,
+ NameUtils.getSafeLabel(g, library),
+ selected,
+ selected) );
+ }
+ //System.out.println("result: " + EString.implode(result));
+ Collections.sort(result);
+ //System.out.println("sorted result: " + EString.implode(result));
+ return result.toArray(new SymbolGroup[result.size()]);
+ }
+
+ protected static Tristate getLibrarySelectionState(ReadGraph graph, Resource library,
+ Collection<Resource> symbols, DiagramResource DIA) throws DatabaseException {
+ Tristate selected = null;
+ for (Resource symbol : symbols) {
+ selected = Tristate.add(selected, graph.hasStatement(library, DIA.HasSymbol, symbol));
+ }
+ return selected != null ? selected : Tristate.NONE;
+ }
+
+ private static SymbolGroup[] selectedElements(SymbolGroup[] symbolGroups) {
+ int count = 0;
+ for(SymbolGroup g : symbolGroups)
+ if(g.selected != Tristate.NONE)
+ ++count;
+ SymbolGroup[] result = new SymbolGroup[count];
+ count = 0;
+ for(SymbolGroup g : symbolGroups)
+ if(g.selected != Tristate.NONE)
+ result[count++] = g;
+ return result;
+ }
+
+ public void assignGroups(final Collection<Resource> symbols) {
+ if (symbols.isEmpty())
+ return;
+
+ final Resource model = getCommonModel(symbols);
+ if (model == null) {
+ ShowMessage.showInformation("Same Model Required", "All the selected symbols must be from within the same model.");
+ return;
+ }
+
+ final AtomicReference<SymbolGroup[]> groups =
+ new AtomicReference<SymbolGroup[]>( getSymbolGroups(symbols) );
+
+ StringBuilder message = new StringBuilder();
+ message.append("Select symbol groups the selected ");
+ if (symbols.size() > 1)
+ message.append(symbols.size()).append(" symbols are shown in.");
+ else
+ message.append("symbol is shown in.");
+
+ AssignSymbolGroupsDialog dialog = new AssignSymbolGroupsDialog(
+ PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
+ groups.get(),
+ new ContentProviderImpl(),
+ new LabelProviderImpl(),
+ new CheckStateProviderImpl(),
+ message.toString()) {
+
+ @Override
+ protected void checkStateChanged(Object[] elements, boolean checked) {
+ for (Object _g : elements) {
+ SymbolGroup g = (SymbolGroup) _g;
+ g.selected = checked ? Tristate.ALL : Tristate.NONE;
+ // Refresh checked states through provider.
+ listViewer.refresh();
+ }
+ }
+
+ @Override
+ protected void newAction() {
+ SymbolGroup newGroup = newSymbolGroup(getShell(), model, (SymbolGroup[])inputElement);
+ if (newGroup != null) {
+ // Select the new library by default.
+ newGroup.selected = Tristate.ALL;
+
+ SymbolGroup[] newGroups = (SymbolGroup[]) inputElement;
+ newGroups = Arrays.copyOf(newGroups, newGroups.length+1);
+ newGroups[newGroups.length-1] = newGroup;
+ Arrays.sort(newGroups);
+ listViewer.setInput(newGroups);
+ inputElement = newGroups;
+ groups.set(newGroups);
+ }
+ }
+
+ @Override
+ protected void deleteAction(Object[] array) {
+ SymbolGroup[] groupsToRemove = Arrays.copyOf(array, array.length, SymbolGroup[].class);
+ if (removeSymbolGroups(getShell(), groupsToRemove)) {
+ listViewer.remove(groupsToRemove);
+ Set<SymbolGroup> removedGroups = new HashSet<SymbolGroup>();
+ for (SymbolGroup removed : groupsToRemove)
+ removedGroups.add(removed);
+ List<SymbolGroup> newGroups = new ArrayList<SymbolGroup>(groups.get().length);
+ for (SymbolGroup old : groups.get()) {
+ if (!removedGroups.contains(old))
+ newGroups.add(old);
+ }
+ groups.set( newGroups.toArray(NO_SYMBOL_GROUPS) );
+ }
+ }
+ };
+ dialog.setTitle("Symbol Group Assignments");
+ dialog.setInitialSelections(selectedElements(groups.get()));
+ if (dialog.open() == Dialog.OK) {
+ final ArrayList<SymbolGroup> added = new ArrayList<SymbolGroup>();
+ final ArrayList<SymbolGroup> removed = new ArrayList<SymbolGroup>();
+ for (SymbolGroup g : groups.get()) {
+ if (g.selected != g.originallySelected && g.selected == Tristate.ALL)
+ added.add(g);
+ if (g.selected != g.originallySelected && g.selected == Tristate.NONE)
+ removed.add(g);
+ }
+ if (!added.isEmpty() || !removed.isEmpty()) {
+ ArrayList<Resource> addedSymbolGroups = new ArrayList<Resource>();
+ ArrayList<Resource> removedSymbolGroups = new ArrayList<Resource>();
+ for (SymbolGroup group : added)
+ addedSymbolGroups.add(group.resource);
+ for (SymbolGroup group : removed)
+ removedSymbolGroups.add(group.resource);
+ Simantics.getSession().asyncRequest(new AssignSymbolGroupRequest(addedSymbolGroups, removedSymbolGroups, symbols));
+ }
+ }
+ }
+
+ private static SymbolGroup newSymbolGroup(Shell shell, Resource model, final SymbolGroup[] oldGroups) {
+ InputDialog dialog = new InputDialog(shell,
+ "New Symbol Group",
+ "Write the name of the new symbol group.",
+ "NewSymbolGroup",
+ new IInputValidator() {
+ @Override
+ public String isValid(String newText) {
+ newText = newText.trim();
+ if (newText.isEmpty())
+ return "The name must be non-empty.";
+ for (SymbolGroup g : oldGroups)
+ if (newText.equals(g.name))
+ return "A symbol group with that name already exists.";
+ return null;
+ }
+ }
+ );
+ if (dialog.open() == Dialog.OK) {
+ String name = dialog.getValue();
+ try {
+ NewSymbolGroupRequest request = new NewSymbolGroupRequest(name, model);
+ Resource symbolGroup = Simantics.getSession().syncRequest(request);
+ if (symbolGroup == null)
+ return null;
+ return new SymbolGroup(symbolGroup, name, Tristate.NONE, Tristate.NONE);
+ } catch (DatabaseException e) {
+ ErrorLogger.defaultLogError(e);
+ return null;
+ }
+ }
+ return null;
+ }
+
+ private boolean removeSymbolGroups(Shell shell, final SymbolGroup[] groups) {
+ if (groups.length == 0)
+ return false;
+ String message;
+ if (groups.length == 1)
+ message = "Are you sure you want to remove symbol group '" + groups[0].name + "' ?";
+ else
+ message = "Are you sure you want to remove " + groups.length + " symbol groups?";
+ MessageDialog dialog =
+ new MessageDialog(shell, "Confirm removal", null, message, MessageDialog.QUESTION, new String[] { "OK", "Cancel" }, 0);
+ if (dialog.open() == Dialog.OK) {
+ Simantics.getSession().asyncRequest(new WriteRequest() {
+ @Override
+ public void perform(WriteGraph graph) throws DatabaseException {
+ for (SymbolGroup group : groups)
+ graph.deny(group.resource);
+ }
+ });
+ return true;
+ }
+ else
+ return false;
+ }
+
+}