@Override
  protected void doCreateControls(Composite container, DataBindingContext dbc) {
    GridLayoutFactory.fillDefaults().margins(10, 10).applyTo(container);

    Group labelsGroup = new Group(container, SWT.NONE);
    labelsGroup.setText("Labels");
    GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(labelsGroup);
    GridLayoutFactory.fillDefaults().numColumns(2).margins(6, 6).applyTo(labelsGroup);
    Composite tableContainer = new Composite(labelsGroup, SWT.NONE);

    this.viewer = createTable(tableContainer);
    GridDataFactory.fillDefaults()
        .span(1, 5)
        .align(SWT.FILL, SWT.FILL)
        .grab(true, true)
        .applyTo(tableContainer);
    ValueBindingBuilder.bind(ViewerProperties.singleSelection().observe(viewer))
        .to(BeanProperties.value(IResourceLabelsPageModel.PROPERTY_SELECTED_LABEL).observe(model))
        .in(dbc);
    viewer.setContentProvider(new ObservableListContentProvider());
    viewer.setInput(BeanProperties.list(IResourceLabelsPageModel.PROPERTY_LABELS).observe(model));

    Button addButton = new Button(labelsGroup, SWT.PUSH);
    GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).applyTo(addButton);
    addButton.setText("Add");
    addButton.addSelectionListener(onAdd());

    Button editExistingButton = new Button(labelsGroup, SWT.PUSH);
    GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).applyTo(editExistingButton);
    editExistingButton.setText("Edit");
    editExistingButton.addSelectionListener(onEdit());
    ValueBindingBuilder.bind(WidgetProperties.enabled().observe(editExistingButton))
        .notUpdatingParticipant()
        .to(BeanProperties.value(IResourceLabelsPageModel.PROPERTY_SELECTED_LABEL).observe(model))
        .converting(new IsNotNullOrReadOnlyBooleanConverter())
        .in(dbc);

    Button removeButton = new Button(labelsGroup, SWT.PUSH);
    GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).applyTo(removeButton);
    removeButton.setText("Remove");
    removeButton.addSelectionListener(onRemove());
    ValueBindingBuilder.bind(WidgetProperties.enabled().observe(removeButton))
        .notUpdatingParticipant()
        .to(BeanProperties.value(IResourceLabelsPageModel.PROPERTY_SELECTED_LABEL).observe(model))
        .converting(new IsNotNullOrReadOnlyBooleanConverter())
        .in(dbc);
  }
  @SuppressWarnings({"unchecked", "rawtypes"})
  @Override
  protected void doCreateControls(final Composite parent, DataBindingContext dbc) {
    GridLayoutFactory.fillDefaults().numColumns(3).margins(10, 10).applyTo(parent);

    // userdoc link (JBIDE-20401)
    this.userdocLink = new StyledText(parent, SWT.WRAP); // text set in #showHideUserdocLink
    GridDataFactory.fillDefaults().align(SWT.LEFT, SWT.CENTER).span(3, 1).applyTo(userdocLink);
    showHideUserdocLink();
    IObservableValue userdocUrlObservable =
        BeanProperties.value(ConnectionWizardPageModel.PROPERTY_USERDOCURL).observe(pageModel);
    StyledTextUtils.emulateLinkAction(userdocLink, r -> onUserdocLinkClicked(userdocUrlObservable));
    userdocUrlObservable.addValueChangeListener(
        new IValueChangeListener() {

          @Override
          public void handleValueChange(ValueChangeEvent event) {
            showHideUserdocLink();
          }
        });

    IObservableValue connectionFactoryObservable =
        BeanProperties.value(ConnectionWizardPageModel.PROPERTY_CONNECTION_FACTORY)
            .observe(pageModel);

    // filler
    Label fillerLabel = new Label(parent, SWT.NONE);
    GridDataFactory.fillDefaults().span(3, 3).hint(SWT.DEFAULT, 6).applyTo(fillerLabel);

    // existing connections combo
    Label connectionLabel = new Label(parent, SWT.NONE);
    connectionLabel.setText("Connection:");
    GridDataFactory.fillDefaults()
        .align(SWT.LEFT, SWT.CENTER)
        .hint(100, SWT.DEFAULT)
        .applyTo(connectionLabel);
    Combo connectionCombo = new Combo(parent, SWT.DEFAULT);
    GridDataFactory.fillDefaults()
        .span(2, 1)
        .align(SWT.FILL, SWT.CENTER)
        .grab(true, false)
        .applyTo(connectionCombo);
    ComboViewer connectionComboViewer = new ComboViewer(connectionCombo);
    connectionComboViewer.setContentProvider(ArrayContentProvider.getInstance());
    connectionComboViewer.setLabelProvider(new ConnectionColumLabelProvider());
    connectionComboViewer.setInput(pageModel.getAllConnections());
    Binding selectedConnectionBinding =
        ValueBindingBuilder.bind(ViewerProperties.singleSelection().observe(connectionComboViewer))
            .validatingAfterGet(
                new IsNotNullValidator(
                    ValidationStatus.cancel("You have to select or create a new connection.")))
            .to(
                BeanProperties.value(
                        ConnectionWizardPageModel.PROPERTY_SELECTED_CONNECTION, IConnection.class)
                    .observe(pageModel))
            .in(dbc);
    ControlDecorationSupport.create(
        selectedConnectionBinding,
        SWT.LEFT | SWT.TOP,
        null,
        new RequiredControlDecorationUpdater());

    // server type
    Label connectionFactoryLabel = new Label(parent, SWT.NONE);
    connectionFactoryLabel.setText("Server type:");
    GridDataFactory.fillDefaults()
        .align(SWT.LEFT, SWT.CENTER)
        .hint(100, SWT.DEFAULT)
        .applyTo(connectionFactoryLabel);
    Combo connectionFactoryCombo = new Combo(parent, SWT.DEFAULT);
    GridDataFactory.fillDefaults()
        .span(2, 1)
        .align(SWT.FILL, SWT.CENTER)
        .grab(true, false)
        .applyTo(connectionFactoryCombo);
    ComboViewer connectionFactoriesViewer = new ComboViewer(connectionFactoryCombo);
    connectionFactoriesViewer.setContentProvider(ArrayContentProvider.getInstance());
    connectionFactoriesViewer.setLabelProvider(
        new ColumnLabelProvider() {

          @Override
          public String getText(Object element) {
            if (!(element instanceof IConnectionFactory)) {
              return element.toString();
            } else {
              return ((IConnectionFactory) element).getName();
            }
          }
        });
    connectionFactoriesViewer.setInput(pageModel.getAllConnectionFactories());
    final IViewerObservableValue selectedServerType =
        ViewerProperties.singleSelection().observe(connectionFactoriesViewer);
    ValueBindingBuilder.bind(selectedServerType).to(connectionFactoryObservable).in(dbc);

    // server
    Button useDefaultServerCheckbox = new Button(parent, SWT.CHECK);
    useDefaultServerCheckbox.setText("Use default server");
    GridDataFactory.fillDefaults()
        .span(3, 1)
        .align(SWT.FILL, SWT.FILL)
        .applyTo(useDefaultServerCheckbox);
    ValueBindingBuilder.bind(WidgetProperties.selection().observe(useDefaultServerCheckbox))
        .to(
            BeanProperties.value(
                    ConnectionWizardPageModel.PROPERTY_USE_DEFAULT_HOST, IConnection.class)
                .observe(pageModel))
        .in(dbc);

    IObservableValue hasDefaultHostObservable =
        BeanProperties.value(ConnectionWizardPageModel.PROPERTY_HAS_DEFAULT_HOST)
            .observe(pageModel);
    ValueBindingBuilder.bind(WidgetProperties.enabled().observe(useDefaultServerCheckbox))
        .notUpdating(hasDefaultHostObservable)
        .in(dbc);

    Label serverLabel = new Label(parent, SWT.NONE);
    serverLabel.setText("Server:");
    GridDataFactory.fillDefaults()
        .align(SWT.LEFT, SWT.CENTER)
        .hint(100, SWT.DEFAULT)
        .applyTo(serverLabel);
    Combo serversCombo = new Combo(parent, SWT.BORDER);
    ComboViewer serversViewer = new ComboViewer(serversCombo);
    serversViewer.setContentProvider(new ObservableListContentProvider());
    serversViewer.setInput(
        BeanProperties.list(ConnectionWizardPageModel.PROPERTY_ALL_HOSTS).observe(pageModel));
    GridDataFactory.fillDefaults()
        .align(SWT.FILL, SWT.FILL)
        .grab(true, false)
        .applyTo(serversCombo);
    final IObservableValue serverUrlObservable = WidgetProperties.text().observe(serversCombo);
    serversCombo.addFocusListener(onServerFocusLost(serverUrlObservable));
    ValueBindingBuilder.bind(serverUrlObservable)
        .converting(new TrimTrailingSlashConverter())
        .to(BeanProperties.value(ConnectionWizardPageModel.PROPERTY_HOST).observe(pageModel))
        .in(dbc);

    MultiValidator serverUrlValidator =
        new MultiValidator() {

          @Override
          protected IStatus validate() {
            Object value = serverUrlObservable.getValue();
            if (!(value instanceof String) || StringUtils.isEmpty((String) value)) {
              return ValidationStatus.cancel("Please provide an OpenShift server url.");
            } else if (!UrlUtils.isValid((String) value)) {
              return ValidationStatus.error("Please provide a valid OpenShift server url.");
            }
            return ValidationStatus.ok();
          }
        };
    ControlDecorationSupport.create(
        serverUrlValidator, SWT.LEFT | SWT.TOP, null, new RequiredControlDecorationUpdater());
    dbc.addValidationStatusProvider(serverUrlValidator);

    ValueBindingBuilder.bind(WidgetProperties.enabled().observe(serversCombo))
        .notUpdatingParticipant()
        .to(
            BeanProperties.value(ConnectionWizardPageModel.PROPERTY_USE_DEFAULT_HOST)
                .observe(pageModel))
        .converting(new InvertingBooleanConverter())
        .in(dbc);

    // connect error
    dbc.addValidationStatusProvider(
        new MultiValidator() {
          IObservableValue observable =
              BeanProperties.value(
                      ConnectionWizardPageModel.PROPERTY_CONNECTED_STATUS, IStatus.class)
                  .observe(pageModel);

          @Override
          protected IStatus validate() {
            return (IStatus) observable.getValue();
          }
        });

    // connection editors
    Group authenticationDetailsGroup = new Group(parent, SWT.NONE);
    authenticationDetailsGroup.setText("Authentication");
    GridDataFactory.fillDefaults()
        .align(SWT.FILL, SWT.FILL)
        .span(3, 1)
        .applyTo(authenticationDetailsGroup);
    GridLayoutFactory.fillDefaults().margins(0, 0).applyTo(authenticationDetailsGroup);
    // additional nesting required because of https://bugs.eclipse.org/bugs/show_bug.cgi?id=478618
    Composite authenticationDetailsContainer = new Composite(authenticationDetailsGroup, SWT.None);
    GridDataFactory.fillDefaults()
        .align(SWT.FILL, SWT.FILL)
        .grab(true, true)
        .applyTo(authenticationDetailsContainer);
    this.connectionEditors =
        new ConnectionEditorsStackedView(
            connectionFactoryObservable, this, authenticationDetailsContainer, dbc);
    connectionEditors.createControls();

    // adv editors
    Composite advEditorContainer = new Composite(parent, SWT.NONE);
    GridLayoutFactory.fillDefaults().margins(0, 0).applyTo(authenticationDetailsGroup);
    GridDataFactory.fillDefaults()
        .align(SWT.FILL, SWT.FILL)
        .span(3, 1)
        .grab(true, true)
        .applyTo(advEditorContainer);
    this.advConnectionEditors =
        new AdvancedConnectionEditorsStackedView(
            connectionFactoryObservable, pageModel, advEditorContainer, dbc);
    advConnectionEditors.createControls();
  }
  @Override
  protected void doCreateControls(Composite parent, DataBindingContext dbc) {
    GridLayoutFactory.fillDefaults().margins(6, 6).applyTo(parent);
    Composite container = new Composite(parent, SWT.NONE);
    GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, false).applyTo(container);
    GridLayoutFactory.fillDefaults().numColumns(3).applyTo(container);

    // label
    final Label filePatternLabel = new Label(container, SWT.NONE);
    filePatternLabel.setText("Tail options:");
    GridDataFactory.fillDefaults()
        .align(SWT.LEFT, SWT.CENTER)
        .grab(false, false)
        .applyTo(filePatternLabel);
    // input text field
    final Text filePatternText = new Text(container, SWT.BORDER);
    GridDataFactory.fillDefaults()
        .align(SWT.FILL, SWT.CENTER)
        .span(1, 1)
        .grab(true, false)
        .applyTo(filePatternText);
    final IObservableValue filePatternTextObservable =
        WidgetProperties.text(SWT.Modify).observe(filePatternText);
    final IObservableValue filePatternModelObservable =
        BeanProperties.value(TailFilesWizardPageModel.PROPERTY_FILE_PATTERN).observe(pageModel);
    ValueBindingBuilder.bind(filePatternTextObservable).to(filePatternModelObservable).in(dbc);
    // reset button (in case user inputs something and wants/needs to revert)
    final Button resetButton = new Button(container, SWT.PUSH);
    resetButton.setText("Reset");
    GridDataFactory.fillDefaults()
        .hint(100, SWT.DEFAULT)
        .span(1, 1)
        .align(SWT.FILL, SWT.CENTER)
        .grab(false, false)
        .applyTo(resetButton);
    resetButton.addSelectionListener(
        new SelectionAdapter() {
          @Override
          public void widgetSelected(SelectionEvent e) {
            pageModel.resetFilePattern();
          }
        });

    // gears selection container
    final Composite gearsSelectionContainer = new Composite(container, SWT.NONE);
    GridDataFactory.fillDefaults()
        .align(SWT.FILL, SWT.TOP)
        .grab(true, false)
        .span(3, 1)
        .applyTo(gearsSelectionContainer);
    GridLayoutFactory.fillDefaults().numColumns(2).applyTo(gearsSelectionContainer);
    // enable tail logs on all gears at the same time
    final Label selectGearsLabel = new Label(gearsSelectionContainer, SWT.NONE);
    selectGearsLabel.setText("Please, select the gears on which you want to tail files:");
    GridDataFactory.fillDefaults()
        .align(SWT.LEFT, SWT.CENTER)
        .grab(true, false)
        .span(2, 1)
        .applyTo(selectGearsLabel);

    final Composite tableContainer = new Composite(gearsSelectionContainer, SWT.NONE);
    GridDataFactory.fillDefaults()
        .align(SWT.FILL, SWT.FILL)
        .grab(true, true)
        .span(1, 2)
        .applyTo(tableContainer);
    this.viewer = createTable(tableContainer);
    dbc.bindSet(
        ViewerProperties.checkedElements(IGearGroup.class).observe(viewer),
        BeanProperties.set(TailFilesWizardPageModel.PROPERTY_SELECTED_GEAR_GROUPS)
            .observe(pageModel));
    final Button selectAllButton = new Button(gearsSelectionContainer, SWT.PUSH);
    selectAllButton.setText("Select all");
    selectAllButton.addSelectionListener(
        new SelectionAdapter() {
          @Override
          public void widgetSelected(SelectionEvent e) {
            pageModel.selectAllGears();
          }
        });
    GridDataFactory.fillDefaults()
        .hint(100, SWT.DEFAULT)
        .align(SWT.FILL, SWT.TOP)
        .grab(false, false)
        .applyTo(selectAllButton);
    final Button deselectAllButton = new Button(gearsSelectionContainer, SWT.PUSH);
    deselectAllButton.setText("Deselect all");
    deselectAllButton.addSelectionListener(
        new SelectionAdapter() {
          @Override
          public void widgetSelected(SelectionEvent e) {
            pageModel.deselectAllGears();
          }
        });

    GridDataFactory.fillDefaults()
        .hint(100, SWT.DEFAULT)
        .align(SWT.FILL, SWT.TOP)
        .grab(false, false)
        .applyTo(deselectAllButton);
  }