[UI-Dialogs] Revise ExtStatusDialog
- Add nullable annotations
- Add .clearStatus avoiding NPE
- Make use of cancel button by ProgressMonitorPart
Signed-off-by: Stephan Wahlbrink <sw@wahlbrink.eu>
diff --git a/ecommons/org.eclipse.statet.ecommons.runtime.core/src/org/eclipse/statet/ecommons/runtime/core/StatusChangeListener.java b/ecommons/org.eclipse.statet.ecommons.runtime.core/src/org/eclipse/statet/ecommons/runtime/core/StatusChangeListener.java
index 44c0068..eac5bd5 100644
--- a/ecommons/org.eclipse.statet.ecommons.runtime.core/src/org/eclipse/statet/ecommons/runtime/core/StatusChangeListener.java
+++ b/ecommons/org.eclipse.statet.ecommons.runtime.core/src/org/eclipse/statet/ecommons/runtime/core/StatusChangeListener.java
@@ -16,7 +16,10 @@
import org.eclipse.core.runtime.IStatus;
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+
+@NonNullByDefault
public interface StatusChangeListener {
diff --git a/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/ui/dialogs/DialogUtils.java b/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/ui/dialogs/DialogUtils.java
index 09759a3..1681d4b 100644
--- a/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/ui/dialogs/DialogUtils.java
+++ b/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/ui/dialogs/DialogUtils.java
@@ -35,6 +35,8 @@
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
+import org.eclipse.statet.ecommons.ui.swt.ControlEnableStates;
+
/**
* Util methods for dialogs
@@ -45,7 +47,7 @@
public static final int HISTORY_MAX= 25;
- private static final String[] EMPTY_ARRAY_SETTING= new String[0];
+ private static final @NonNull String[] EMPTY_ARRAY_SETTING= new @NonNull String[0];
public static IDialogSettings getDialogSettings(final Bundle bundle, final String dialogId) {
@@ -85,7 +87,7 @@
*/
public static void saveHistorySettings(final IDialogSettings settings, final String key,
final String newItem) {
- final String[] items= combineHistoryItems(settings.getArray(key), newItem);
+ final @NonNull String[] items= combineHistoryItems(settings.getArray(key), newItem);
settings.put(key, items);
}
@@ -95,7 +97,8 @@
* @param existingItems optional array of existing items
* @param newItem optional new item
*/
- public static String[] combineHistoryItems(final String[] existingItems, final String newItem) {
+ public static @NonNull String[] combineHistoryItems(
+ final @NonNull String @Nullable [] existingItems, final @Nullable String newItem) {
final LinkedHashSet<String> history= new LinkedHashSet<>(HISTORY_MAX);
if (newItem != null && newItem.length() > 0) {
history.add(newItem);
@@ -108,7 +111,7 @@
return history.toArray(new @NonNull String[history.size()]);
}
- public static String[] noNull(final String @Nullable [] array) {
+ public static @NonNull String[] noNull(final @NonNull String @Nullable [] array) {
return (array != null) ? array : EMPTY_ARRAY_SETTING;
}
@@ -117,8 +120,7 @@
* Recursively enables/disables all controls and their children.
* {@link Control#setEnabled(boolean)}
*
- * See {@link org.eclipse.jface.dialogs.ControlEnableState ControlEnableState}
- * if saving state is required.
+ * See {@link ControlEnableStates} if saving state is required.
*
* @param control list of controls
* @param exceptions
@@ -126,17 +128,14 @@
*/
public static void setEnabled(final List<? extends Control> controls,
final @Nullable List<? extends Control> exceptions, final boolean enable) {
- for (final Control control : controls) {
+ for (final var control : controls) {
if ((exceptions != null && exceptions.contains(control))) {
continue;
}
control.setEnabled(enable);
if (control instanceof Composite) {
- final Composite c= (Composite) control;
- final Control[] children= c.getChildren();
- if (children.length > 0) {
- setEnabled(children, exceptions, enable);
- }
+ final var composite= (Composite) control;
+ setEnabled(ImCollections.newList(composite.getChildren()), exceptions, enable);
}
}
}
@@ -145,14 +144,13 @@
* Recursively enables/disables all controls and their children.
* {@link Control#setEnabled(boolean)}
*
- * See {@link org.eclipse.jface.dialogs.ControlEnableState ControlEnableState}
- * if saving state is required.
+ * See {@link ControlEnableStates} if saving state is required.
*
* @param control array of controls
* @param exceptions
* @param enable
*/
- public static void setEnabled(final Control[] controls,
+ public static void setEnabled(final @NonNull Control[] controls,
final @Nullable List<? extends Control> exceptions, final boolean enable) {
setEnabled(ImCollections.newList(controls), exceptions, enable);
}
@@ -161,8 +159,7 @@
* Recursively enables/disables all controls and their children.
* {@link Control#setEnabled(boolean)}
*
- * See {@link org.eclipse.jface.dialogs.ControlEnableState ControlEnableState}
- * if saving state is required.
+ * See {@link ControlEnableStates} if saving state is required.
*
* @param control a control
* @param exceptions
@@ -184,35 +181,19 @@
*/
public static void setVisible(final List<? extends Control> controls,
final @Nullable List<? extends Control> exceptions, final boolean enable) {
- for (final Control control : controls) {
+ for (final var control : controls) {
if ((exceptions != null && exceptions.contains(control))) {
continue;
}
control.setVisible(enable);
if (control instanceof Composite) {
- final Composite c= (Composite) control;
- final Control[] children= c.getChildren();
- if (children.length > 0) {
- setVisible(children, exceptions, enable);
- }
+ final var composite= (Composite)control;
+ setVisible(ImCollections.newList(composite.getChildren()), exceptions, enable);
}
}
}
/**
- * Recursively sets visible/invisible to all controls and their children.
- * {@link Control#setVisible(boolean)}
- *
- * @param control array of controls
- * @param exceptions
- * @param enable
- */
- public static void setVisible(final Control[] controls,
- final @Nullable List<? extends Control> exceptions, final boolean enable) {
- setVisible(ImCollections.newList(controls), exceptions, enable);
- }
-
- /**
* Recursively sets visible/invisible to the control and its children.
* {@link Control#setVisible(boolean)}
*
@@ -230,7 +211,7 @@
int closest= Integer.MAX_VALUE;
final Point toFind= Geometry.centerPoint(rectangle);
- final Monitor[] monitors= toSearch.getMonitors();
+ final var monitors= toSearch.getMonitors();
Monitor result= monitors[0];
for (int idx= 0; idx < monitors.length; idx++) {
diff --git a/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/ui/dialogs/ExtStatusDialog.java b/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/ui/dialogs/ExtStatusDialog.java
index 2a1dcee..8e6c0a7 100644
--- a/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/ui/dialogs/ExtStatusDialog.java
+++ b/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/ui/dialogs/ExtStatusDialog.java
@@ -14,19 +14,23 @@
package org.eclipse.statet.ecommons.ui.dialogs;
+import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
+import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullLateInit;
+
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
-import org.eclipse.jface.dialogs.ControlEnableState;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.StatusDialog;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.operation.ModalContext;
+import org.eclipse.jface.util.Policy;
+import org.eclipse.jface.util.Util;
import org.eclipse.jface.wizard.ProgressMonitorPart;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
@@ -38,17 +42,25 @@
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+import org.eclipse.statet.jcommons.lang.Nullable;
+
import org.eclipse.statet.ecommons.databinding.jface.DataBindingSupport;
import org.eclipse.statet.ecommons.runtime.core.StatusChangeListener;
+import org.eclipse.statet.ecommons.ui.swt.ControlEnableStates;
import org.eclipse.statet.ecommons.ui.util.LayoutUtils;
+@NonNullByDefault
public class ExtStatusDialog extends StatusDialog implements IRunnableContext {
- protected final static int WITH_RUNNABLE_CONTEXT = 1 << 0;
- protected final static int WITH_DATABINDING_CONTEXT = 1 << 1;
- protected final static int SHOW_INITIAL_STATUS = 1 << 2;
+ protected static final int WITH_RUNNABLE_CONTEXT= 1 << 0;
+ protected static final int WITH_DATABINDING_CONTEXT= 1 << 1;
+ protected static final int SHOW_INITIAL_STATUS= 1 << 2;
+
+ private static final IStatus NO_STATUS= new Status(IStatus.OK, Policy.JFACE, IStatus.OK,
+ Util.ZERO_LENGTH_STRING, null );
public class StatusUpdater implements StatusChangeListener {
@@ -61,37 +73,43 @@
}
- private final int fOptions;
+ private final int options;
- private Composite fProgressComposite;
- private ProgressMonitorPart fProgressMonitorPart;
- private Button fProgressMonitorCancelButton;
- private int fActiveRunningOperations;
+ /*- WITH_RUNNABLE_CONTEXT -*/
- private Control fProgressLastFocusControl;
- private ControlEnableState fProgressLastContentEnableState;
- private Control[] fProgressLastButtonControls;
- private boolean[] fProgressLastButtonEnableStates;
+ private Composite progressComposite= nonNullLateInit();
+ private ProgressMonitorPart progressMonitorPart= nonNullLateInit();
- protected DataBindingSupport fDataBinding;
+ private int activeRunningOperations;
+
+ private @Nullable Control progressLastFocusControl;
+ private @Nullable ControlEnableStates progressLastContentEnableState;
+
+
+ /*- WITH_DATABINDING_CONTEXT -*/
+
+ private DataBindingSupport dataBinding= nonNullLateInit();
/**
* @see StatusDialog#StatusDialog(Shell)
*/
- public ExtStatusDialog(final Shell parent) {
+ public ExtStatusDialog(final @Nullable Shell parent) {
this(parent, 0);
}
/**
* @see StatusDialog#StatusDialog(Shell)
*
- * @param withRunnableContext create elements to provide {@link IRunnableContext}
+ * @param options
+ * @see #WITH_RUNNABLE_CONTEXT
+ * @see #WITH_DATABINDING_CONTEXT
+ * @see #SHOW_INITIAL_STATUS
*/
- public ExtStatusDialog(final Shell parent, final int options) {
+ public ExtStatusDialog(final @Nullable Shell parent, final int options) {
super(parent);
- fOptions = options;
+ this.options= options;
}
@@ -102,8 +120,8 @@
@Override
protected Point getInitialSize() {
- final Point savedSize = super.getInitialSize();
- final Point minSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT);
+ final Point savedSize= super.getInitialSize();
+ final Point minSize= getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT);
return new Point(Math.max(savedSize.x, minSize.x), Math.max(savedSize.y, minSize.y));
}
@@ -111,47 +129,47 @@
public void create() {
// E-3.6 Eclipse bug fixed?
super.create();
- final Button button = getButton(IDialogConstants.OK_ID);
- final Shell shell = getShell();
+ final Button button= getButton(IDialogConstants.OK_ID);
+ final Shell shell= getShell();
if (button != null && shell != null && !shell.isDisposed()) {
shell.setDefaultButton(button);
}
- if ((fOptions & WITH_DATABINDING_CONTEXT) != 0) {
+ if ((this.options & WITH_DATABINDING_CONTEXT) != 0) {
initBindings();
}
}
protected void initBindings() {
- final DataBindingSupport databinding = new DataBindingSupport(getDialogArea());
+ final DataBindingSupport databinding= new DataBindingSupport(getDialogArea());
addBindings(databinding);
databinding.installStatusListener(new StatusUpdater());
- if ((fOptions & SHOW_INITIAL_STATUS) == 0) {
- final IStatus status = getStatus();
+ if ((this.options & SHOW_INITIAL_STATUS) == 0) {
+ final IStatus status= getStatus();
updateStatus(Status.OK_STATUS);
updateButtonsEnableState(status);
}
- fDataBinding = databinding;
+ this.dataBinding= databinding;
}
protected void addBindings(final DataBindingSupport db) {
}
protected DataBindingSupport getDataBinding() {
- return fDataBinding;
+ return this.dataBinding;
}
@Override
protected Control createButtonBar(final Composite parent) {
- final Composite composite = (Composite) super.createButtonBar(parent);
- final GridLayout layout = (GridLayout) composite.getLayout();
- layout.verticalSpacing = 0;
+ final Composite composite= (Composite)super.createButtonBar(parent);
+ final GridLayout layout= (GridLayout)composite.getLayout();
+ layout.verticalSpacing= 0;
- if ((fOptions & WITH_RUNNABLE_CONTEXT) != 0) {
- final Composite monitorComposite = createMonitorComposite(composite);
- final Control[] children = composite.getChildren();
- layout.numColumns = 3;
- ((GridData) children[0].getLayoutData()).horizontalSpan++;
+ if ((this.options & WITH_RUNNABLE_CONTEXT) != 0) {
+ final Composite monitorComposite= createMonitorComposite(composite);
+ final Control[] children= composite.getChildren();
+ layout.numColumns= 3;
+ ((GridData)children[0].getLayoutData()).horizontalSpan++;
monitorComposite.moveBelow(children[1]);
monitorComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
}
@@ -160,91 +178,100 @@
}
private Composite createMonitorComposite(final Composite parent) {
- fProgressComposite = new Composite(parent, SWT.NULL);
- final GridLayout layout = LayoutUtils.newCompositeGrid(2);
- layout.marginLeft = LayoutUtils.defaultHMargin();
- fProgressComposite.setLayout(layout);
+ this.progressComposite= new Composite(parent, SWT.NULL);
+ final GridLayout layout= LayoutUtils.newCompositeGrid(2);
+ layout.marginLeft= LayoutUtils.defaultHMargin();
+ this.progressComposite.setLayout(layout);
- fProgressMonitorPart = new ProgressMonitorPart(fProgressComposite, null);
- fProgressMonitorPart.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
- fProgressMonitorCancelButton = createButton(fProgressComposite, 1000, IDialogConstants.CANCEL_LABEL, true);
+ this.progressMonitorPart= new ProgressMonitorPart(this.progressComposite, null, true);
+ this.progressMonitorPart.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
- Dialog.applyDialogFont(fProgressComposite);
- fProgressComposite.setVisible(false);
- return fProgressComposite;
+ Dialog.applyDialogFont(this.progressComposite);
+ this.progressComposite.setVisible(false);
+ return this.progressComposite;
}
+
@Override
- public void run(final boolean fork, final boolean cancelable, final IRunnableWithProgress runnable) throws InvocationTargetException, InterruptedException {
- if ((fOptions & WITH_RUNNABLE_CONTEXT) == 0) {
+ public void run(final boolean fork, final boolean cancelable,
+ final IRunnableWithProgress runnable) throws InvocationTargetException, InterruptedException {
+ if ((this.options & WITH_RUNNABLE_CONTEXT) == 0) {
throw new UnsupportedOperationException();
}
if (getShell() != null && getShell().isVisible()) {
- if (fActiveRunningOperations == 0) {
+ if (this.activeRunningOperations == 0) {
// Save control state
- fProgressLastFocusControl = getShell().getDisplay().getFocusControl();
- if (fProgressLastFocusControl != null && fProgressLastFocusControl.getShell() != getShell()) {
- fProgressLastFocusControl = null;
+ Control focusControl= getShell().getDisplay().getFocusControl();
+ if (focusControl != null && focusControl.getShell() != getShell()) {
+ focusControl= null;
}
+ this.progressLastFocusControl= focusControl;
- fProgressLastContentEnableState = ControlEnableState.disable(getDialogArea());
- final List<Control> buttons= new ArrayList<>();
+ final List<Control> disable= new ArrayList<>();
+ disable.add(nonNullAssert(getDialogArea()));
for (final Control child : getButton(IDialogConstants.OK_ID).getParent().getChildren()) {
if (child instanceof Button) {
- buttons.add(child);
+ disable.add(child);
}
}
- fProgressLastButtonControls = buttons.toArray(new Control[buttons.size()]);
- fProgressLastButtonEnableStates = new boolean[fProgressLastButtonControls.length];
- for (int i = 0; i < fProgressLastButtonControls.length; i++) {
- fProgressLastButtonEnableStates[i] = fProgressLastButtonControls[i].getEnabled();
- fProgressLastButtonControls[i].setEnabled(false);
- }
+ this.progressLastContentEnableState= ControlEnableStates.disable(disable);
// Enable monitor
- fProgressMonitorCancelButton.setEnabled(cancelable);
- fProgressMonitorPart.attachToCancelComponent(fProgressMonitorCancelButton);
- fProgressComposite.setVisible(true);
- fProgressMonitorCancelButton.setFocus();
-
+ this.progressMonitorPart.attachToCancelComponent(null);
+ this.progressComposite.setVisible(true);
}
- fActiveRunningOperations++;
+ this.activeRunningOperations++;
try {
- ModalContext.run(runnable, fork, fProgressMonitorPart, getShell().getDisplay());
+ ModalContext.run(runnable, fork, this.progressMonitorPart, getShell().getDisplay());
}
finally {
- fActiveRunningOperations--;
+ this.activeRunningOperations--;
- if (fActiveRunningOperations == 0 && getShell() != null) {
- fProgressComposite.setVisible(false);
- fProgressLastContentEnableState.restore();
- for (int i = 0; i < fProgressLastButtonControls.length; i++) {
- fProgressLastButtonControls[i].setEnabled(fProgressLastButtonEnableStates[i]);
+ if (this.activeRunningOperations == 0 && getShell() != null) {
+ this.progressComposite.setVisible(false);
+ this.progressMonitorPart.removeFromCancelComponent(null);
+
+ final ControlEnableStates contentEnableState= this.progressLastContentEnableState;
+ if (contentEnableState != null) {
+ this.progressLastContentEnableState= null;
+ contentEnableState.restore();
}
- fProgressMonitorPart.removeFromCancelComponent(fProgressMonitorCancelButton);
- if (fProgressLastFocusControl != null) {
- fProgressLastFocusControl.setFocus();
+ final Control focusControl= this.progressLastFocusControl;
+ if (focusControl != null) {
+ this.progressLastFocusControl= null;
+ focusControl.setFocus();
}
}
}
- }
+ }
else {
PlatformUI.getWorkbench().getProgressService().run(fork, cancelable, runnable);
}
}
+ protected boolean isOperationRunning() {
+ return (this.activeRunningOperations > 0);
+ }
+
+
+ protected void clearStatus() {
+ updateStatus(NO_STATUS);
+ }
+
@Override
protected void updateButtonsEnableState(final IStatus status) {
- super.updateButtonsEnableState(status);
- if (fActiveRunningOperations > 0) {
- final Button okButton = getButton(IDialogConstants.OK_ID);
- for (int i = 0; i < fProgressLastButtonControls.length; i++) {
- if (fProgressLastButtonControls[i] == okButton) {
- fProgressLastButtonEnableStates[i] = okButton.isEnabled();
- }
+ if (isOperationRunning()) {
+ final ControlEnableStates contentEnableState= this.progressLastContentEnableState;
+ final Button okButton= getButton(IDialogConstants.OK_ID);
+ if (contentEnableState != null
+ && okButton != null && !okButton.isDisposed() ) {
+ contentEnableState.updateState(okButton, false, !status.matches(IStatus.ERROR));
}
}
+ else {
+ super.updateButtonsEnableState(status);
+ }
}
}
diff --git a/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/ui/swt/ControlEnableStates.java b/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/ui/swt/ControlEnableStates.java
new file mode 100644
index 0000000..b8a4284
--- /dev/null
+++ b/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/ui/swt/ControlEnableStates.java
@@ -0,0 +1,180 @@
+/*=============================================================================#
+ # Copyright (c) 2021 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.ecommons.ui.swt;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+import org.eclipse.statet.jcommons.collections.ImCollection;
+import org.eclipse.statet.jcommons.collections.ImCollections;
+import org.eclipse.statet.jcommons.collections.ImIdentityList;
+import org.eclipse.statet.jcommons.collections.ImList;
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+import org.eclipse.statet.jcommons.lang.Nullable;
+
+
+/**
+ * Helper class to save the enable/disable state of controls including their children.
+ */
+@NonNullByDefault
+public class ControlEnableStates {
+
+
+ public static ControlEnableStates disable(final Collection<Control> controls,
+ final Collection<Control> exceptions) {
+ return new ControlEnableStates(
+ ImCollections.toList(controls), ImCollections.toIdentityList(exceptions),
+ false );
+ }
+
+ public static ControlEnableStates disable(final Collection<Control> controls) {
+ return new ControlEnableStates(
+ ImCollections.toList(controls), ImCollections.emptyIdentityList(),
+ false );
+ }
+
+ public static ControlEnableStates disable(final Control control,
+ final Collection<Control> exceptions) {
+ return new ControlEnableStates(
+ ImCollections.newList(control), ImCollections.toIdentityList(exceptions),
+ false );
+ }
+
+ public static ControlEnableStates disable(final Control control) {
+ return new ControlEnableStates(
+ ImCollections.newList(control), ImCollections.emptyIdentityList(),
+ false );
+ }
+
+ public static ControlEnableStates enable(final Collection<Control> controls,
+ final Collection<Control> exceptions) {
+ return new ControlEnableStates(
+ ImCollections.toList(controls), ImCollections.toIdentityList(exceptions),
+ true );
+ }
+
+ public static ControlEnableStates enable(final Collection<Control> controls) {
+ return new ControlEnableStates(
+ ImCollections.toList(controls), ImCollections.emptyIdentityList(),
+ true );
+ }
+
+ public static ControlEnableStates enable(final Control control,
+ final Collection<Control> exceptions) {
+ return new ControlEnableStates(
+ ImCollections.newList(control), ImCollections.toIdentityList(exceptions),
+ true );
+ }
+
+ public static ControlEnableStates enable(final Control control) {
+ return new ControlEnableStates(
+ ImCollections.newList(control), ImCollections.emptyIdentityList(),
+ true );
+ }
+
+
+ private static class State {
+
+ protected final Control control;
+
+ protected boolean enabled;
+
+ public State(final Control control, final boolean enabled) {
+ this.control= control;
+ this.enabled= enabled;
+ }
+
+ }
+
+
+ private final ImIdentityList<Control> exceptions;
+
+ private final ImList<State> states;
+
+
+ private ControlEnableStates(
+ final ImList<Control> controls, final ImIdentityList<Control> exceptions,
+ final boolean enabled) {
+ this.exceptions= exceptions;
+ final List<State> states= new ArrayList<>();
+ init(controls, enabled, states);
+ this.states= ImCollections.toList(states);
+ }
+
+
+ private void init(
+ final ImList<? extends Control> controls, final boolean enabled,
+ final List<State> states) {
+ for (final var control : controls) {
+ if (this.exceptions.contains(control)) {
+ continue;
+ }
+ if (control instanceof Composite) {
+ final var composite= (Composite)control;
+ init(ImCollections.newList(composite.getChildren()), enabled, states);
+ }
+ states.add(new State(control, control.getEnabled()));
+ control.setEnabled(enabled);
+ }
+ }
+
+ private @Nullable State getState(final Control control) {
+ for (final var state : this.states) {
+ if (state.control == control) {
+ return state;
+ }
+ }
+ return null;
+ }
+
+
+ public void updateState(final ImCollection<? extends Control> controls, final boolean recursively,
+ final boolean enabled) {
+ for (final var control : controls) {
+ if (this.exceptions.contains(control)) {
+ continue;
+ }
+ final var state= getState(control);
+ if (state == null) {
+ continue;
+ }
+ if (recursively && control instanceof Composite) {
+ final var composite= (Composite)control;
+ updateState(ImCollections.newList(composite.getChildren()), recursively, enabled);
+ }
+ state.enabled= enabled;
+ }
+ }
+
+ public void updateState(final Control control, final boolean recursively,
+ final boolean enabled) {
+ updateState(ImCollections.newList(control), recursively, enabled);
+ }
+
+
+ public void restore() {
+ for (final var state : this.states) {
+ if (state.control.isDisposed()) {
+ continue;
+ }
+ state.control.setEnabled(state.enabled);
+ }
+ }
+
+}