org.chromium.debug.ui/src/org/chromium/debug/ui/source/SourceNameMapperContainerDialogLogic.java
changeset 355 8726e95bcbba
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.chromium.debug.ui/src/org/chromium/debug/ui/source/SourceNameMapperContainerDialogLogic.java	Mon Jun 07 16:51:19 2010 -0700
@@ -0,0 +1,272 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.debug.ui.source;
+
+import static org.chromium.debug.ui.DialogUtils.createErrorOptional;
+import static org.chromium.debug.ui.DialogUtils.createOptional;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.chromium.debug.ui.DialogUtils.ExpressionProcessor;
+import org.chromium.debug.ui.DialogUtils.Message;
+import org.chromium.debug.ui.DialogUtils.MessagePriority;
+import org.chromium.debug.ui.DialogUtils.OkButtonControl;
+import org.chromium.debug.ui.DialogUtils.Optional;
+import org.chromium.debug.ui.DialogUtils.Updater;
+import org.chromium.debug.ui.DialogUtils.ValueConsumer;
+import org.chromium.debug.ui.DialogUtils.ValueProcessor;
+import org.chromium.debug.ui.DialogUtils.ValueSource;
+import org.chromium.debug.ui.source.SourceNameMapperContainerDialog.ConfigureButtonAction;
+import org.chromium.debug.ui.source.SourceNameMapperContainerDialog.ContainerStatusGroup;
+import org.chromium.debug.ui.source.SourceNameMapperContainerDialog.Elements;
+import org.chromium.debug.ui.source.SourceNameMapperContainerDialog.PresetFieldValues;
+import org.chromium.debug.ui.source.SourceNameMapperContainerDialog.Result;
+import org.eclipse.debug.core.sourcelookup.ISourceContainer;
+import org.eclipse.debug.core.sourcelookup.ISourceContainerType;
+import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * A separated logic of {@link SourceNameMapperContainerDialog}. It describes how data flows
+ * from input elements to the OK button with all necessary asserts. Basically it only uses
+ * {@link SourceNameMapperContainerDialog.Elements} interface from the dialog.
+ */
+abstract class SourceNameMapperContainerDialogLogic {
+  abstract Result getResult();
+  abstract void updateAll();
+
+  static SourceNameMapperContainerDialogLogic create(
+      final Elements elements, final ISourceLookupDirector director,
+      final PresetFieldValues initialParams) {
+    final Updater updater = new Updater();
+
+    final List<ValueSource<String>> warningSources = new ArrayList<ValueSource<String>>(2);
+
+    // Represents value entered as prefix.
+    final ValueSource<String> prefixEditor = new ValueSource<String>() {
+      public String getValue() {
+        return elements.getPrefixField().getText();
+      }
+      {
+        if (initialParams != null) {
+          elements.getPrefixField().setText(initialParams.getPrefix());
+        }
+        final ValueSource<String> updatableThis = this;
+        ModifyListener listener = new ModifyListener() {
+          public void modifyText(ModifyEvent e) {
+            updater.reportChanged(updatableThis);
+            updater.update();
+          }
+        };
+        elements.getPrefixField().addModifyListener(listener);
+      }
+    };
+
+    // Represents prefix value after it has been validated.
+    final ValueProcessor<Optional<String>> prefixValue = new ExpressionProcessor<String>(
+        Collections.<ValueSource<? extends Optional<?>>>emptyList()) {
+      @Override
+      protected Optional<String> calculateNormal() {
+        String prefix = prefixEditor.getValue();
+        Optional<String> result;
+        if (prefix == null || prefix.length() == 0) {
+          return createErrorOptional(new Message(
+              Messages.SourceNameMapperContainerDialog_ENTER_PREFIX,
+              MessagePriority.BLOCKING_INFO));
+        } else {
+          return createOptional(prefix);
+        }
+      }
+    };
+    updater.addConsumer(prefixValue, prefixEditor);
+
+    // Represents possible warning about prefix value having no trailing slash.
+    ValueProcessor<String> noSlashWarning = new ValueProcessor<String>() {
+      public void update(Updater updater) {
+        Optional<String> prefix = prefixValue.getValue();
+        String result;
+        if (prefix.isNormal() && !prefix.getNormal().endsWith("/")) { //$NON-NLS-1$
+          result = Messages.SourceNameMapperContainerDialog_PREFIX_NORMALLY_ENDS;
+        } else {
+          result = null;
+        }
+        setCurrentValue(result);
+        updater.reportChanged(this);
+      }
+    };
+    updater.addConsumer(noSlashWarning, prefixValue);
+    warningSources.add(noSlashWarning);
+
+    // Represents prefix rule example printer.
+    ValueConsumer prefixExample = new ValueConsumer() {
+      public void update(Updater updater) {
+        Optional<String> prefix = prefixValue.getValue();
+        String line1;
+        String line2;
+        if (prefix.isNormal()) {
+          String sampleFileName = Messages.SourceNameMapperContainerDialog_SAMPLE_FILE_NAME;
+          line1 = NLS.bind(Messages.SourceNameMapperContainerDialog_EXAMPLE_1,
+              prefix.getNormal() + sampleFileName);
+          line2 = NLS.bind(Messages.SourceNameMapperContainerDialog_EXAMPLE_2, sampleFileName);
+        } else {
+          line1 = ""; //$NON-NLS-1$
+          line2 = ""; //$NON-NLS-1$
+        }
+        elements.getPrefixExampleLine1Label().setText(line1);
+        elements.getPrefixExampleLine2Label().setText(line2);
+      }
+    };
+    updater.addConsumer(prefixExample, prefixValue);
+
+    // Represents container type combo box.
+    final ValueSource<ISourceContainerType> selectedTypeValue =
+        new ValueSource<ISourceContainerType>() {
+      public ISourceContainerType getValue() {
+        return elements.getContainerTypeCombo().getSelected();
+      }
+      {
+        if (initialParams != null) {
+          ISourceContainerType type = initialParams.getContainer().getType();
+          elements.getContainerTypeCombo().setSelected(type);
+        }
+        final ValueSource<ISourceContainerType> updatableThis = this;
+        SelectionListener listener = new SelectionAdapter() {
+          @Override
+          public void widgetSelected(SelectionEvent e) {
+            updater.reportChanged(updatableThis);
+            updater.update();
+          }
+        };
+        elements.getContainerTypeCombo().addSelectionListener(listener);
+      }
+    };
+
+    // Represents "Configure" button that acts like a container factory.
+    final ValueProcessor<ISourceContainer> containerFactoryButtonValue =
+        new ValueProcessor<ISourceContainer>() {
+      private ConfigureButtonAction preparedAction = null;
+      {
+        if (initialParams != null) {
+          setCurrentValue(initialParams.getContainer());
+        }
+        final ValueSource<ISourceContainer> valueSourceThis = this;
+        elements.getConfigureButton().addSelectionListener(new SelectionAdapter() {
+          @Override
+          public void widgetSelected(SelectionEvent e) {
+            if (preparedAction != null) {
+              ISourceContainer value = preparedAction.run(elements.getShell());
+              if (value != null) {
+                setCurrentValue(value);
+              }
+              updater.reportChanged(valueSourceThis);
+              updater.update();
+              updateAction();
+            }
+          }
+        });
+      }
+      public void update(Updater updater) {
+        if (getValue() != null && !getValue().getType().equals(selectedTypeValue.getValue())) {
+          setCurrentValue(null);
+          updater.reportChanged(this);
+        }
+        updateAction();
+      }
+      private void updateAction() {
+        preparedAction = SourceNameMapperContainerDialog.prepareConfigureAction(
+            selectedTypeValue.getValue(), getValue(), director);
+        elements.getConfigureButton().setEnabled(preparedAction != null);
+      }
+    };
+    updater.addConsumer(containerFactoryButtonValue, selectedTypeValue);
+
+    // Represents printer that shows type and name of the created container.
+    ValueConsumer showContainerTypeValue = new ValueConsumer() {
+      public void update(Updater updater) {
+        ISourceContainer container = containerFactoryButtonValue.getValue();
+        String status;
+        Image image;
+        String name;
+        boolean enabled;
+        if (container == null) {
+          status = Messages.SourceNameMapperContainerDialog_NOTHING_CONFIGURED;
+          name = ""; //$NON-NLS-1$
+          image = null;
+          enabled = false;
+        } else {
+          status = Messages.SourceNameMapperContainerDialog_CONFIGURED_CONTAINER;
+          ISourceContainerType type = container.getType();
+          name = container.getName();
+          image = DebugUITools.getSourceContainerImage(type.getId());
+          enabled = true;
+        }
+        ContainerStatusGroup group = elements.getContainerStatusGroup();
+        group.getStatusLabel().setText(status);
+        group.getTypeImageLabel().setImage(image);
+        group.getContainerNameLabel().setText(name);
+        group.setEnabled(enabled);
+        group.layout();
+      }
+    };
+    updater.addConsumer(showContainerTypeValue, containerFactoryButtonValue);
+
+    // Represents expression that constructs dialog window result.
+    final ValueProcessor<? extends Optional<Result>> resultValue =
+        new ExpressionProcessor<Result>(
+            Arrays.<ValueSource<? extends Optional<?>>>asList(prefixValue) ) {
+          @Override
+          protected Optional<Result> calculateNormal() {
+            final String prefix = prefixValue.getValue().getNormal();
+            final ISourceContainer container = containerFactoryButtonValue.getValue();
+            if (container == null) {
+              return createErrorOptional(
+                  new Message(Messages.SourceNameMapperContainerDialog_CONFIGURE_TARGET_CONTAINER,
+                      MessagePriority.BLOCKING_INFO));
+            }
+            Result result = new Result() {
+              public ISourceContainer getResultContainer() {
+                return container;
+              }
+              public String getResultPrefix() {
+                return prefix;
+              }
+            };
+            return createOptional(result);
+          }
+    };
+    updater.addConsumer(resultValue, prefixValue, containerFactoryButtonValue);
+
+    // Represents controller that updates state of OK button and error messages.
+    OkButtonControl okButtonControl = new OkButtonControl(resultValue, warningSources, elements);
+    updater.addConsumer(okButtonControl, okButtonControl.getDependencies());
+
+    return new SourceNameMapperContainerDialogLogic() {
+      @Override
+      Result getResult() {
+        Optional<Result> optional = resultValue.getValue();
+        if (optional.isNormal()) {
+          return optional.getNormal();
+        } else {
+          // Normally should not be reachable, because UI should have disabled OK button.
+          return null;
+        }
+      }
+      @Override
+      void updateAll() {
+        updater.updateAll();
+      }
+    };
+  }
+}