/**
   * Returns the (non-<code>null</code>) name of the left or right side if they are identical.
   * Otherwise both names are concatenated (separated with a slash ('/')).
   *
   * <p>Subclasses may re-implement to provide a different name for this node.
   *
   * @return the name of this node.
   */
  public String getName() {
    String right = null;
    if (fRight != null) right = fRight.getName();

    String left = null;
    if (fLeft != null) left = fLeft.getName();

    if (right == null && left == null) {
      if (fAncestor != null) return fAncestor.getName();
      return Utilities.getString("DiffNode.noName"); // $NON-NLS-1$
    }

    if (right == null) return left;
    if (left == null) return right;

    if (right.equals(left)) return right;

    String s1;
    String s2;

    if (fSwapSides) {
      s1 = left;
      s2 = right;
    } else {
      s1 = right;
      s2 = left;
    }

    String fmt = Utilities.getString("DiffNode.nameFormat"); // $NON-NLS-1$
    return MessageFormat.format(fmt, new String[] {s1, s2});
  }
  /**
   * Callback that is invoked when a property in the compare configuration ( {@link
   * #getCompareConfiguration()} changes.
   *
   * @param event the property change event
   * @since 3.3
   */
  protected void handlePropertyChangeEvent(PropertyChangeEvent event) {

    String key = event.getProperty();

    if (key.equals(ICompareUIConstants.PROP_ANCESTOR_VISIBLE)) {
      fAncestorVisible =
          Utilities.getBoolean(
              getCompareConfiguration(),
              ICompareUIConstants.PROP_ANCESTOR_VISIBLE,
              fAncestorVisible);
      fComposite.layout(true);

      updateCursor(fLeftLabel, VERTICAL);
      updateCursor(fDirectionLabel, HORIZONTAL | VERTICAL);
      updateCursor(fRightLabel, VERTICAL);

      return;
    }

    if (key.equals(ICompareUIConstants.PROP_IGNORE_ANCESTOR)) {
      setAncestorVisibility(
          false,
          !Utilities.getBoolean(
              getCompareConfiguration(), ICompareUIConstants.PROP_IGNORE_ANCESTOR, false));
      return;
    }
  }
  private void initializeToolbars(Composite parent) {
    ToolBarManager tbm = CompareViewerPane.getToolBarManager(parent);
    if (tbm != null) {
      tbm.removeAll();

      // define groups
      tbm.add(new Separator("modes")); // $NON-NLS-1$
      tbm.add(new Separator("merge")); // $NON-NLS-1$
      tbm.add(new Separator("navigation")); // $NON-NLS-1$

      CompareConfiguration cc = getCompareConfiguration();

      if (cc.isRightEditable()) {
        fCopyLeftToRightAction =
            new Action() {
              public void run() {
                copy(true);
              }
            };
        Utilities.initAction(
            fCopyLeftToRightAction, getResourceBundle(), "action.CopyLeftToRight."); // $NON-NLS-1$
        tbm.appendToGroup("merge", fCopyLeftToRightAction); // $NON-NLS-1$
        fHandlerService.registerAction(
            fCopyLeftToRightAction, "org.eclipse.compare.copyAllLeftToRight"); // $NON-NLS-1$
      }

      if (cc.isLeftEditable()) {
        fCopyRightToLeftAction =
            new Action() {
              public void run() {
                copy(false);
              }
            };
        Utilities.initAction(
            fCopyRightToLeftAction, getResourceBundle(), "action.CopyRightToLeft."); // $NON-NLS-1$
        tbm.appendToGroup("merge", fCopyRightToLeftAction); // $NON-NLS-1$
        fHandlerService.registerAction(
            fCopyRightToLeftAction, "org.eclipse.compare.copyAllRightToLeft"); // $NON-NLS-1$
      }

      final ChangePropertyAction a =
          new ChangePropertyAction(
              fBundle,
              getCompareConfiguration(),
              "action.EnableAncestor.",
              ICompareUIConstants.PROP_ANCESTOR_VISIBLE); // $NON-NLS-1$
      a.setChecked(fAncestorVisible);
      fAncestorItem = new ActionContributionItem(a);
      fAncestorItem.setVisible(false);
      tbm.appendToGroup("modes", fAncestorItem); // $NON-NLS-1$
      tbm.getControl().addDisposeListener(a);

      createToolItems(tbm);
      updateToolItems();

      tbm.update(true);
    }
  }
  /**
   * This method is called from the <code>Viewer</code> method <code>inputChanged</code> to save any
   * unsaved changes of the old input.
   *
   * <p>The <code>ContentMergeViewer</code> implementation of this method calls <code>
   * saveContent(...)</code>. If confirmation has been turned on with <code>setConfirmSave(true)
   * </code>, a confirmation alert is posted before saving. Clients can override this method and are
   * free to decide whether they want to call the inherited method.
   *
   * @param newInput the new input of this viewer, or <code>null</code> if there is no new input
   * @param oldInput the old input element, or <code>null</code> if there was previously no input
   * @return <code>true</code> if saving was successful, or if the user didn't want to save (by
   *     pressing 'NO' in the confirmation dialog).
   * @since 2.0
   */
  protected boolean doSave(Object newInput, Object oldInput) {

    // before setting the new input we have to save the old
    if (isLeftDirty() || isRightDirty()) {

      if (Utilities.RUNNING_TESTS) {
        if (Utilities.TESTING_FLUSH_ON_COMPARE_INPUT_CHANGE) {
          flushContent(oldInput, null);
        }
      } else if (fConfirmSave) {
        // post alert
        Shell shell = fComposite.getShell();

        MessageDialog dialog =
            new MessageDialog(
                shell,
                Utilities.getString(getResourceBundle(), "saveDialog.title"), // $NON-NLS-1$
                null, // accept the default window icon
                Utilities.getString(getResourceBundle(), "saveDialog.message"), // $NON-NLS-1$
                MessageDialog.QUESTION,
                new String[] {
                  IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL,
                },
                0); // default
        // button
        // index

        switch (dialog.open()) { // open returns index of pressed button
          case 0:
            flushContent(oldInput, null);
            break;
          case 1:
            setLeftDirty(false);
            setRightDirty(false);
            break;
          case 2:
            throw new ViewerSwitchingCancelled();
        }
      } else flushContent(oldInput, null);
      return true;
    }
    return false;
  }
  private void internalRefresh(Object input) {

    IMergeViewerContentProvider content = getMergeContentProvider();
    if (content == null) {
      return;
    }
    Object ancestor = content.getAncestorContent(input);
    boolean oldFlag = fIsThreeWay;
    if (Utilities.isHunk(input)) {
      fIsThreeWay = true;
    } else if (input instanceof ICompareInput)
      fIsThreeWay = (((ICompareInput) input).getKind() & Differencer.DIRECTION_MASK) != 0;
    else fIsThreeWay = ancestor != null;

    if (fAncestorItem != null) fAncestorItem.setVisible(fIsThreeWay);

    if (fAncestorVisible && oldFlag != fIsThreeWay) fComposite.layout(true);

    Object left = content.getLeftContent(input);
    Object right = content.getRightContent(input);
    updateContent(ancestor, left, right);

    // https://bugs.eclipse.org/bugs/show_bug.cgi?id=453799
    // Content provider may be disposed after call to updateContent()
    content = getMergeContentProvider();
    if (content == null) {
      return;
    }

    updateHeader();
    ToolBarManager tbm = CompareViewerPane.getToolBarManager(fComposite.getParent());
    if (tbm != null) {
      updateToolItems();
      tbm.update(true);
      tbm.getControl().getParent().layout(true);
    }
  }
 /**
  * Returns the viewer's name.
  *
  * @return the viewer's name
  */
 public String getTitle() {
   return Utilities.getString(getResourceBundle(), "title"); // $NON-NLS-1$
 }
  /**
   * Creates a new content merge viewer and initializes with a resource bundle and a configuration.
   *
   * @param style SWT style bits
   * @param bundle the resource bundle
   * @param cc the configuration object
   */
  protected ContentMergeViewer(int style, ResourceBundle bundle, CompareConfiguration cc) {

    fStyles = style & ~(SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT); // remove
    // BIDI
    // direction
    // bits
    fBundle = bundle;

    fAncestorVisible =
        Utilities.getBoolean(cc, ICompareUIConstants.PROP_ANCESTOR_VISIBLE, fAncestorVisible);
    fConfirmSave = Utilities.getBoolean(cc, CompareEditor.CONFIRM_SAVE_PROPERTY, fConfirmSave);

    setContentProvider(new MergeViewerContentProvider(cc));

    fCompareInputChangeListener =
        new ICompareInputChangeListener() {
          public void compareInputChanged(ICompareInput input) {
            if (input == getInput()) {
              handleCompareInputChange();
            }
          }
        };

    // Make sure the compare configuration is not null
    if (cc == null) fCompareConfiguration = new CompareConfiguration();
    else fCompareConfiguration = cc;
    fPropertyChangeListener =
        new IPropertyChangeListener() {
          public void propertyChange(PropertyChangeEvent event) {
            ContentMergeViewer.this.handlePropertyChangeEvent(event);
          }
        };
    fCompareConfiguration.addPropertyChangeListener(fPropertyChangeListener);

    fLeftSaveAction = new SaveAction(true);
    fLeftSaveAction.setEnabled(false);
    fRightSaveAction = new SaveAction(false);
    fRightSaveAction.setEnabled(false);

    // this is used to update the dirty status,if we use
    // org.eclipse.php.internal.ui.compare.ContentMergeViewer,we will get a
    // ClassCastException
    cmv =
        new org.eclipse.compare.contentmergeviewer.ContentMergeViewer(
            fStyles, fBundle, fCompareConfiguration) {

          @Override
          protected void createControls(Composite composite) {}

          @Override
          protected void handleResizeAncestor(int x, int y, int width, int height) {}

          @Override
          protected void handleResizeLeftRight(
              int x, int y, int leftWidth, int centerWidth, int rightWidth, int height) {}

          @Override
          protected void updateContent(Object ancestor, Object left, Object right) {}

          @Override
          protected void copy(boolean leftToRight) {}

          @Override
          protected byte[] getContents(boolean left) {
            return null;
          }

          @Override
          public boolean internalIsLeftDirty() {
            return ContentMergeViewer.this.isLeftDirty();
          }

          @Override
          public boolean internalIsRightDirty() {
            return ContentMergeViewer.this.isRightDirty();
          }
        };
  }
 private void fireDirtyState(boolean state) {
   Utilities.firePropertyChange(
       fListenerList, cmv, CompareEditorInput.DIRTY_STATE, null, new Boolean(state));
 }