/**
  * Create the sash with right control on the right. Note that this method assumes GridData for the
  * layout data of the rightControl.
  *
  * @param composite
  * @param rightControl
  * @return Sash
  * @since 3.1
  */
 protected Sash createSash(final Composite composite, final Control rightControl) {
   final Sash sash = new Sash(composite, SWT.VERTICAL);
   sash.setLayoutData(new GridData(GridData.FILL_VERTICAL));
   sash.setBackground(composite.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
   // the following listener resizes the tree control based on sash deltas.
   // If necessary, it will also grow/shrink the dialog.
   sash.addListener(
       SWT.Selection,
       event -> {
         if (event.detail == SWT.DRAG) {
           return;
         }
         int shift = event.x - sash.getBounds().x;
         GridData data = (GridData) rightControl.getLayoutData();
         int newWidthHint = data.widthHint + shift;
         if (newWidthHint < 20) {
           return;
         }
         Point computedSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT);
         Point currentSize = getShell().getSize();
         // if the dialog wasn't of a custom size we know we can shrink
         // it if necessary based on sash movement.
         boolean customSize = !computedSize.equals(currentSize);
         data.widthHint = newWidthHint;
         setLastTreeWidth(newWidthHint);
         composite.layout(true);
         // recompute based on new widget size
         computedSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT);
         // if the dialog was of a custom size then increase it only if
         // necessary.
         if (customSize) {
           computedSize.x = Math.max(computedSize.x, currentSize.x);
         }
         computedSize.y = Math.max(computedSize.y, currentSize.y);
         if (computedSize.equals(currentSize)) {
           return;
         }
         setShellSize(computedSize.x, computedSize.y);
         lastShellSize = getShell().getSize();
       });
   return sash;
 }
  /**
   * Shows the preference page corresponding to the given preference node. Does nothing if that page
   * is already current.
   *
   * @param node the preference node, or <code>null</code> if none
   * @return <code>true</code> if the page flip was successful, and <code>false</code> is
   *     unsuccessful
   */
  protected boolean showPage(IPreferenceNode node) {
    if (node == null) {
      return false;
    }
    // Create the page if nessessary
    if (node.getPage() == null) {
      createPage(node);
    }
    if (node.getPage() == null) {
      return false;
    }
    IPreferencePage newPage = getPage(node);
    if (newPage == currentPage) {
      return true;
    }
    if (currentPage != null) {
      if (!currentPage.okToLeave()) {
        return false;
      }
    }
    IPreferencePage oldPage = currentPage;
    currentPage = newPage;
    // Set the new page's container
    currentPage.setContainer(this);
    // Ensure that the page control has been created
    // (this allows lazy page control creation)
    if (currentPage.getControl() == null) {
      final boolean[] failed = {false};
      SafeRunnable.run(
          new ISafeRunnable() {
            @Override
            public void handleException(Throwable e) {
              failed[0] = true;
            }

            @Override
            public void run() {
              createPageControl(currentPage, pageContainer);
            }
          });
      if (failed[0]) {
        return false;
      }
      // the page is responsible for ensuring the created control is
      // accessable
      // via getControl.
      Assert.isNotNull(currentPage.getControl());
    }
    // Force calculation of the page's description label because
    // label can be wrapped.
    final Point[] size = new Point[1];
    final Point failed = new Point(-1, -1);
    SafeRunnable.run(
        new ISafeRunnable() {
          @Override
          public void handleException(Throwable e) {
            size[0] = failed;
          }

          @Override
          public void run() {
            size[0] = currentPage.computeSize();
          }
        });
    if (size[0].equals(failed)) {
      return false;
    }
    Point contentSize = size[0];
    // Do we need resizing. Computation not needed if the
    // first page is inserted since computing the dialog's
    // size is done by calling dialog.open().
    // Also prevent auto resize if the user has manually resized
    Shell shell = getShell();
    Point shellSize = shell.getSize();
    if (oldPage != null) {
      Rectangle rect = pageContainer.getClientArea();
      Point containerSize = new Point(rect.width, rect.height);
      int hdiff = contentSize.x - containerSize.x;
      int vdiff = contentSize.y - containerSize.y;
      if ((hdiff > 0 || vdiff > 0) && shellSize.equals(lastShellSize)) {
        hdiff = Math.max(0, hdiff);
        vdiff = Math.max(0, vdiff);
        setShellSize(shellSize.x + hdiff, shellSize.y + vdiff);
        lastShellSize = shell.getSize();
        if (currentPage.getControl().getSize().x == 0) {
          currentPage.getControl().setSize(containerSize);
        }

      } else {
        currentPage.getControl().setSize(containerSize);
      }
    }

    scrolled.setMinSize(contentSize);
    // Ensure that all other pages are invisible
    // (including ones that triggered an exception during
    // their creation).
    Control[] children = pageContainer.getChildren();
    Control currentControl = currentPage.getControl();
    for (int i = 0; i < children.length; i++) {
      if (children[i] != currentControl) {
        children[i].setVisible(false);
      }
    }
    // Make the new page visible
    currentPage.setVisible(true);
    if (oldPage != null) {
      oldPage.setVisible(false);
    }
    // update the dialog controls
    update();
    return true;
  }