| /** |
| ******************************************************************************** |
| * Copyright (c) 2019-2021 Robert Bosch GmbH and others. |
| * |
| * This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Robert Bosch GmbH - initial API and implementation |
| ******************************************************************************** |
| */ |
| |
| package org.eclipse.app4mc.validation.ui; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.stream.Collectors; |
| |
| import org.eclipse.app4mc.validation.ui.provider.ProfileContentProvider; |
| import org.eclipse.app4mc.validation.ui.provider.ProfileLabelProvider; |
| import org.eclipse.app4mc.validation.util.CachedProfile; |
| import org.eclipse.jface.viewers.CheckboxTreeViewer; |
| import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; |
| import org.eclipse.jface.viewers.ILabelProvider; |
| import org.eclipse.jface.viewers.ITreeContentProvider; |
| import org.eclipse.jface.window.Window; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.RowLayout; |
| import org.eclipse.swt.widgets.Button; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Group; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.ui.dialogs.CheckedTreeSelectionDialog; |
| |
| public class ProfileDialog extends CheckedTreeSelectionDialog { |
| |
| private ProfileDialogSettings settings; |
| |
| private Button btnScopeFile; |
| private Button btnScopeFolder; |
| |
| public ProfileDialog(Shell parentShell, ProfileDialogSettings set) { |
| this(parentShell, new ProfileLabelProvider(), new ProfileContentProvider(), set); |
| } |
| |
| public ProfileDialog(Shell parentShell, ILabelProvider labelProvider, ITreeContentProvider contentProvider, ProfileDialogSettings set) { |
| super(parentShell, labelProvider, contentProvider); |
| |
| this.settings = (set != null) ? set : new ProfileDialogSettings(); |
| |
| initializeDialog(); |
| } |
| |
| @Override |
| protected void setReturnCode(int code) { |
| // handle settings - save UI content |
| if (code == Window.OK) { |
| settings.setDialogSuccess(true); |
| saveDialogResults(); |
| } |
| |
| super.setReturnCode(code); |
| } |
| |
| @Override |
| protected Control createDialogArea(Composite parent) { |
| Composite composite = (Composite) super.createDialogArea(parent); |
| |
| // create scope buttons |
| |
| Group grpScope = new Group(composite, SWT.NONE); |
| grpScope.setText("Scope"); |
| grpScope.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); |
| grpScope.setLayout(new RowLayout(SWT.HORIZONTAL)); |
| |
| btnScopeFile = new Button(grpScope, SWT.RADIO); |
| btnScopeFile.setText("Current file"); |
| |
| btnScopeFolder = new Button(grpScope, SWT.RADIO); |
| btnScopeFolder.setText("Folder"); |
| |
| // set selection of scope buttons |
| |
| String scope = settings.getScope(); |
| btnScopeFile.setSelection(scope.equals(ProfileDialogSettings.SCOPE_FILE)); |
| btnScopeFolder.setSelection(scope.equals(ProfileDialogSettings.SCOPE_FOLDER)); |
| |
| return composite; |
| } |
| |
| @Override |
| protected Label createMessageArea(Composite composite) { |
| Label label = new Label(composite, SWT.WRAP); |
| if (getMessage() != null) { |
| label.setText(getMessage()); |
| } |
| label.setFont(composite.getFont()); |
| GridData gd = new GridData(SWT.FILL, SWT.FILL, true, false); |
| gd.widthHint = 300; |
| label.setLayoutData(gd); |
| return label; |
| } |
| |
| @Override |
| protected CheckboxTreeViewer createTreeViewer(Composite parent) { |
| CheckboxTreeViewer treeViewer = super.createTreeViewer(parent); |
| ColumnViewerToolTipSupport.enableFor(treeViewer); |
| return treeViewer; |
| } |
| |
| private void initializeDialog() { |
| this.setContainerMode(true); |
| this.setMessage("Choose profiles"); |
| this.setTitle("Validations"); |
| this.setInput(settings); |
| |
| // set initial selection |
| List<CachedProfile> initialSelection = this.settings.getInitialSelection(); |
| setInitialElementSelections(initialSelection); |
| |
| setExpandedElements(initialSelection.stream().flatMap(cached -> getParents(cached).stream()).toArray()); |
| } |
| |
| private void saveDialogResults() { |
| Object[] dialogResults = getResult(); |
| if (dialogResults == null) { |
| return; |
| } |
| |
| // profiles |
| settings.setDialogResults(filterProfiles(dialogResults).stream() |
| .map(CachedProfile::getProfileClass) |
| .collect(Collectors.toList())); |
| |
| // scope |
| if (btnScopeFile.getSelection()) { |
| settings.setScope(ProfileDialogSettings.SCOPE_FILE); |
| } else if (btnScopeFolder.getSelection()) { |
| settings.setScope(ProfileDialogSettings.SCOPE_FOLDER); |
| } |
| } |
| |
| // some helper methods |
| |
| private static List<CachedProfile> filterProfiles(Object[] dialogResults) { |
| List<CachedProfile> selectedNodes = Arrays.stream(dialogResults) |
| .map(CachedProfile.class::cast) |
| .collect(Collectors.toList()); |
| HashSet<CachedProfile> nodesToRemove = new HashSet<>(); |
| |
| // 2. bottom up: parents with partially selected children must be removed |
| for (CachedProfile node : selectedNodes) { |
| if (!node.getCachedProfiles().isEmpty() && !nodesToRemove.contains(node)) { |
| Collection<CachedProfile> cachedProfiles = node.getCachedProfiles().values(); |
| if (cachedProfiles.stream().anyMatch(c -> !selectedNodes.contains(c))) { |
| nodesToRemove.add(node); |
| nodesToRemove.addAll(getParents(node)); |
| } |
| } |
| } |
| |
| // 3. top down: if node is selected then all sub nodes can be removed |
| for (CachedProfile node : selectedNodes) { |
| if (!node.getCachedProfiles().isEmpty() && !nodesToRemove.contains(node)) { |
| nodesToRemove.addAll(getChildren(node)); |
| } |
| } |
| |
| // finally remove the nodes |
| selectedNodes.removeAll(nodesToRemove); |
| |
| return selectedNodes; |
| } |
| |
| private static List<CachedProfile> getParents(CachedProfile node) { |
| ArrayList<CachedProfile> list = new ArrayList<>(); |
| for (CachedProfile parent = node.getParentProfile(); parent != null; parent = parent.getParentProfile()) { |
| list.add(parent); |
| } |
| return list; |
| } |
| |
| private static List<CachedProfile> getChildren(CachedProfile node) { |
| ArrayList<CachedProfile> list = new ArrayList<>(); |
| collectChildren(node, list); |
| return list; |
| } |
| |
| private static void collectChildren(CachedProfile node, Collection<CachedProfile> collection) { |
| if (!node.getCachedProfiles().isEmpty()) { |
| for (CachedProfile child : node.getCachedProfiles().values()) { |
| collection.add(child); |
| collectChildren(child, collection); |
| } |
| } |
| } |
| |
| } |