public class LanguageObjectBuilderTreeViewer extends TreeViewer
    implements ILanguageObjectInputProvider, UiConstants {

  private static final String PREFIX =
      I18nUtil.getPropertyPrefix(LanguageObjectBuilderTreeViewer.class);

  LanguageObjectContentProvider contentProvider;

  private LanguageObject langObj;

  public LanguageObjectBuilderTreeViewer(Composite theParent) {
    super(theParent, SWT.NONE);

    contentProvider = new LanguageObjectContentProvider();
    setContentProvider(contentProvider);
    setLabelProvider(new LanguageObjectLabelProvider());

    getTree().setLayoutData(new GridData(GridData.FILL_BOTH));
  }

  public void addUndefinedAndCriteria() {
    addUndefinedCriteria((Criteria) getSelectedObject(), true);
  }

  private void addUndefinedCriteria(Criteria theCriteria, boolean theAndFlag) {
    CoreArgCheck.isNotNull(theCriteria); // should not be calling if null

    Object newSelection = StructuredSelection.EMPTY;

    if (theCriteria instanceof CompoundCriteria) {
      CompoundCriteria criteria = (CompoundCriteria) theCriteria;
      criteria.addCriteria((Criteria) null);
      refresh(true);
      newSelection = contentProvider.getChildAt((criteria.getCriteriaCount() - 1), criteria);
    } else if (theCriteria instanceof NotCriteria) {
      // the contained Criteria must be a CompoundCriteria
      addUndefinedCriteria(((NotCriteria) theCriteria).getCriteria(), theAndFlag);
    } else if (theCriteria instanceof PredicateCriteria) {
      CompoundCriteria compoundCriteria = new CompoundCriteria();
      compoundCriteria.setOperator((theAndFlag) ? CompoundCriteria.AND : CompoundCriteria.OR);
      compoundCriteria.addCriteria(theCriteria);
      compoundCriteria.addCriteria((Criteria) null);

      // modify parent here
      LanguageObject parent = (LanguageObject) contentProvider.getParent(theCriteria);
      int index = contentProvider.getChildIndex(theCriteria);

      if (parent == null) {
        setLanguageObject(compoundCriteria);
        refresh(true);

        // select undefined criteria
        newSelection = contentProvider.getChildAt(1, contentProvider.getRoot());
        expandToLevel(newSelection, ALL_LEVELS);
      } else if ((parent instanceof NotCriteria) || (parent instanceof CompoundCriteria)) {
        CompoundCriteria criteria = null;

        if (parent instanceof NotCriteria) {
          // then NotCriteria's contained criteria must be a CompoundCriteria
          criteria = (CompoundCriteria) ((NotCriteria) theCriteria).getCriteria();
        } else {
          criteria = (CompoundCriteria) parent;
        }

        List crits = criteria.getCriteria();
        crits.set(index, compoundCriteria);
        refresh(true);

        // select undefined criteria
        newSelection = contentProvider.getChildAt(1, compoundCriteria);
      } else {
        CoreArgCheck.isTrue(
            false,
            Util.getString(
                PREFIX + "unexpectedType", // $NON-NLS-1$
                new Object[] {"addUndefinedCriteria", parent.getClass()})); // $NON-NLS-1$
      }
    }

    // select appropriate tree item
    final Object selection = newSelection;

    Display.getDefault()
        .asyncExec(
            new Runnable() {
              public void run() {
                setSelection(new StructuredSelection(selection));
              }
            });
  }

  public void addUndefinedOrCriteria() {
    addUndefinedCriteria((Criteria) getSelectedObject(), false);
  }

  private boolean canDelete(Object theLangObj) {
    boolean result = true;
    LanguageObject parent = (LanguageObject) contentProvider.getParent(theLangObj);

    if (parent == null) {
      // object is root. can only delete if not undefined
      result = !isUndefined(theLangObj);
    } else if (parent instanceof Function) {
      // all function arguments except converstion type constants can be deleted
      if (theLangObj instanceof Constant) {
        result = !BuilderUtils.isConversionType((Constant) theLangObj);
      }
    } else if (parent instanceof NotCriteria) {
      // get compound criteria and ask again
      NotCriteria notCrit = (NotCriteria) parent;
      Criteria criteria = notCrit.getCriteria();

      // NotCriteria must contain either another NotCriteria or a CompoundCriteria
      while (!(criteria instanceof CompoundCriteria)) {
        // must be a NotCriteria
        criteria = ((NotCriteria) criteria).getCriteria();
        result = canDelete(criteria);
      }
    }

    return result;
  }

  public boolean canDeleteSelection() {
    return canDelete(getSelectedObject());
  }

  private void delete(Object theLangObj) {
    if (canDelete(theLangObj)) {
      boolean doSelect = true;

      //
      // set the parent object to reflect the change in it's child. parent can't be undefined.
      //

      Object newSelection = StructuredSelection.EMPTY;
      LanguageObject parent = (LanguageObject) contentProvider.getParent(theLangObj);

      if (parent == null) {
        // object being delete is root language object
        setLanguageObject(null); // resets undefined count
        refresh(true);
        newSelection = contentProvider.getRoot();
        expandToLevel(newSelection, ALL_LEVELS);
      } else if (parent instanceof Function) {
        // set the arg to null in parent
        int index = contentProvider.getChildIndex(theLangObj);

        Expression[] args = ((Function) parent).getArgs();
        args[index] = null;

        refresh(true);
        newSelection = contentProvider.getChildAt(index, parent);
      } else if (parent instanceof Criteria) {
        if (contentProvider.getChildCount(parent) > 1) {
          CompoundCriteria compoundCriteria = null;

          // parent is either a compound criteria or not criteria
          if (parent instanceof CompoundCriteria) {
            compoundCriteria = (CompoundCriteria) parent;
          } else { // NotCriteria
            NotCriteria notCrit = (NotCriteria) parent;
            Criteria criteria = notCrit.getCriteria();

            // NotCriteria must contain either another NotCriteria or a CompoundCriteria
            while (!(criteria instanceof CompoundCriteria)) {
              // must be a NotCriteria
              criteria = ((NotCriteria) criteria).getCriteria();
            }

            compoundCriteria = (CompoundCriteria) criteria;
          }

          List crits = compoundCriteria.getCriteria();
          int index = contentProvider.getChildIndex(theLangObj);

          // CompoundCriteria has to have at least 2 criteria to be compound. if it has more than 2
          // just delete the selected obj. if there are exactly 2 criteria than this special
          // processing block occurs.
          if (contentProvider.getChildCount(parent) == 2) {
            int siblingIndex = (index == 0) ? 1 : 0;

            // if deleting this node would leave just an undefined node under the parent, delete
            // parent
            if (isUndefined(contentProvider.getChildAt(siblingIndex, parent))) {
              delete(parent);
            } else {
              // sibling is not undefined

              // if deleting an undefined node, delete from parent. this will leave one node
              // under the parent.
              if (isUndefined(theLangObj)) {
                crits.remove(index);
                // selection taken care of below in block checking for size of 1
              } else {
                // replace deleted node with undefined node
                crits.set(index, (Criteria) null);
                refresh(true);
                newSelection = contentProvider.getChildAt(index, parent);
              }
            }
          } else {
            // just remove from parent
            crits.remove(index);
            refresh(true);
            newSelection = parent;
          }

          if (crits.size() == 1) {
            // need to modify parent node with the child (refresh done there)
            modifyLanguageObject(
                parent, (LanguageObject) contentProvider.getChildAt(0, parent), false);
            doSelect = false; // modify does select
          }
        }
      }

      if (doSelect) {
        final Object selection = newSelection;

        Display.getDefault()
            .asyncExec(
                new Runnable() {
                  public void run() {
                    setSelection(new StructuredSelection(selection));
                  }
                });
      }
    }
  }

  public void deleteSelection() {
    delete(getSelectedObject());
  }

  /**
   * @see
   *     com.metamatrix.modeler.transformation.ui.builder.ILanguageObjectInputProvider#getLanguageObject()
   */
  public LanguageObject getLanguageObject() {
    return langObj;
  }

  // returns null if no selection
  // if there is a selection it will either by a LanguageObject or BuilderUtils.UNDEFINED
  public Object getSelectedObject() {
    Object result = null;
    IStructuredSelection selection = (IStructuredSelection) getSelection();

    if (selection.size() == 1) {
      result = selection.getFirstElement();
    }

    return result;
  }

  /**
   * Indicates if the given object has undefined children.
   *
   * @param theLangObj the object being queried
   * @return <code>true</code> if undefined child exist; <code>false</code> otherwise.
   */
  public boolean hasUndefinedChild(Object theLangObj) {
    boolean result = false;
    Object[] kids = contentProvider.getChildren(theLangObj);

    if (kids.length > 0) {
      // go in reverse order since it is more likely undefined will be at the end
      for (int i = (kids.length - 1); i >= 0; i--) {
        if (isUndefined(kids[i])) {
          result = true;
        } else {
          result = hasUndefinedChild(kids[i]);
        }

        if (result) {
          break;
        }
      }
    }

    return result;
  }

  public boolean isComplete() {
    Object root = contentProvider.getRoot();

    boolean result = ((root == null) || (isUndefined(root))) ? false : !hasUndefinedChild(root);

    return result;
  }

  public boolean isUndefined(Object theLangObj) {
    return ((theLangObj == null) || theLangObj.equals(BuilderUtils.UNDEFINED));
  }

  private void modifyLanguageObject(
      Object theObject, LanguageObject theNewValue, boolean retainSelection) {
    CoreArgCheck.isNotNull(theNewValue); // should not be null when modifying

    //
    // set the parent object to reflect the change in it's child. parent's can't be undefined
    //

    Object newSelection = StructuredSelection.EMPTY;
    LanguageObject parent = (LanguageObject) contentProvider.getParent(theObject);

    Object newValue = theNewValue;

    if (parent == null) {
      // root language object
      setLanguageObject((LanguageObject) newValue);
      refresh(true);
      newSelection = contentProvider.getRoot();
      expandToLevel(newSelection, ALL_LEVELS);

      if (newSelection instanceof Function) {
        Function function = (Function) newSelection;

        if (function.getArgs().length > 0) {
          newSelection = contentProvider.getChildAt(0, function);
        }
      }
    } else if (parent instanceof Function) {
      // set the arg to new value in parent
      int index = contentProvider.getChildIndex(theObject);

      Expression[] args = ((Function) parent).getArgs();
      args[index] = (Expression) newValue;

      refresh(true);
      expandToLevel(parent, ALL_LEVELS);

      newSelection = contentProvider.getChildAt(index, parent);

      if (!retainSelection) {
        if (newSelection instanceof Function) {
          // if function arg change to be a function, select first function arg
          if (contentProvider.getChildCount(newSelection) > 0) {
            newSelection = contentProvider.getChildAt(0, newSelection);
          }
        } else {
          // select next sibling function arg if exists
          if ((args.length - 1) > index) {
            newSelection = contentProvider.getChildAt(index + 1, parent);
          } else if (index > 0) {
            newSelection = contentProvider.getChildAt(0, parent);
          } else {
            newSelection = contentProvider.getChildAt(index, parent);
          }
        }
      }
    } else if (parent instanceof Criteria) {
      // theLangObj must also be a Criteria
      // since NotCriteria aren't really edited in the editor (their contained criteria is). Need to
      // save the state in order to restore it when modifying
      Criteria newCriteria = (Criteria) newValue;
      int index = contentProvider.getChildIndex(theObject);

      if ((parent instanceof CompoundCriteria) || (parent instanceof NotCriteria)) {
        CompoundCriteria compoundCriteria = null;

        if (parent instanceof CompoundCriteria) {
          compoundCriteria = (CompoundCriteria) parent;
        } else {
          compoundCriteria = (CompoundCriteria) ((NotCriteria) parent).getCriteria();
        }

        List criteriaCollection = compoundCriteria.getCriteria();
        criteriaCollection.set(index, newCriteria);
        refresh(true);

        if (retainSelection) {
          newSelection = criteriaCollection.get(index);
        } else {
          // set selection to next sibling criteria or to the first sibling
          if ((criteriaCollection.size() - 1) > index) {
            newSelection = criteriaCollection.get(index + 1);
          } else if (index > 0) {
            newSelection = criteriaCollection.get(0);
          } else {
            newSelection = contentProvider.getChildAt(index + 1, parent);
          }
        }
      } else {
        CoreArgCheck.isTrue(
            false,
            Util.getString(
                PREFIX + "unexpectedType", // $NON-NLS-1$
                new Object[] {
                  "modifyLanguageObject", //$NON-NLS-1$
                  parent.getClass().getName()
                }));
      }

      expandToLevel(parent, ALL_LEVELS);
    }

    // select next node
    setSelection(
        (newSelection == null) ? StructuredSelection.EMPTY : new StructuredSelection(newSelection));
  }

  public void modifyNotCriteriaStatus() {
    Object selectedObj = getSelectedObject();
    CoreArgCheck.isNotNull(selectedObj); // should not be calling if no row selected

    if (selectedObj instanceof NotCriteria) {
      modifySelectedItem(((NotCriteria) selectedObj).getCriteria(), true);
    } else if (selectedObj instanceof Criteria) {
      modifySelectedItem(new NotCriteria((Criteria) selectedObj), true);
    } else if (isUndefined(selectedObj)) {
      CoreArgCheck.isTrue(
          false,
          Util.getString(
              PREFIX + "unexpectedType", // $NON-NLS-1$
              new Object[] {"modifyNotCriteriaStatus", BuilderUtils.UNDEFINED})); // $NON-NLS-1$
    } else {
      CoreArgCheck.isTrue(
          false,
          Util.getString(
              PREFIX + "unexpectedType", // $NON-NLS-1$
              new Object[] {"modifyNotCriteriaStatus", selectedObj.getClass()})); // $NON-NLS-1$
    }
  }

  public void modifySelectedItem(LanguageObject theLangObj, boolean retainSelection) {
    modifyLanguageObject(getSelectedObject(), theLangObj, retainSelection);
  }

  public void selectRoot() {
    // put this in the back of the UI thread event queue.
    // at startup the listeners we're working. this makes sure the listeners have all been wired.
    Display.getDefault()
        .asyncExec(
            new Runnable() {
              public void run() {
                setSelection(new StructuredSelection(contentProvider.getRoot()));
              }
            });
  }

  public void setLanguageObject(LanguageObject theLangObj) {
    langObj = theLangObj;
    setInput(this);
  }
}
/** AbstractLanguageObjectBuilder */
public abstract class AbstractLanguageObjectBuilder extends Dialog implements UiConstants {

  // /////////////////////////////////////////////////////////////////////////////////////////////
  // CONSTANTS
  // /////////////////////////////////////////////////////////////////////////////////////////////

  private static final String PREFIX =
      I18nUtil.getPropertyPrefix(AbstractLanguageObjectBuilder.class);

  // /////////////////////////////////////////////////////////////////////////////////////////////
  // FIELDS
  // /////////////////////////////////////////////////////////////////////////////////////////////

  private IAction deleteAction;

  private ILanguageObjectEditor editor;

  private LanguageObject savedSelection;

  protected LanguageObject savedLangObj;

  // /////////////////////////////////////////////////////////////////////////////////////////////
  // CONTROLS
  // /////////////////////////////////////////////////////////////////////////////////////////////

  protected Button btnSet;

  protected Button btnReset;

  private Label lblTitle;

  private Composite pnlEditor;

  private Composite pnlEditorDetail;

  LanguageObjectBuilderTreeViewer treeViewer;

  private SqlDisplayPanel currentSql;

  private SqlDisplayPanel originalSql;

  private CLabel originalLanguageObjLabel;

  // /////////////////////////////////////////////////////////////////////////////////////////////
  // CONSTRUCTORS
  // /////////////////////////////////////////////////////////////////////////////////////////////

  protected AbstractLanguageObjectBuilder(Shell theParent, String theTitle) {
    super(theParent, theTitle);
  }

  // /////////////////////////////////////////////////////////////////////////////////////////////
  // METHODS
  // /////////////////////////////////////////////////////////////////////////////////////////////

  @Override
  public void create() {
    super.create();

    editor = createEditor(pnlEditorDetail);
    editor
        .getModel()
        .addModelListener(
            new ILanguageObjectEditorModelListener() {
              public void modelChanged(LanguageObjectEditorModelEvent theEvent) {
                handleModelChanged();
              }
            });

    lblTitle.setText(editor.getTitle());

    Composite pnlEditorButtons = new Composite(pnlEditor, SWT.NONE);
    pnlEditorButtons.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_CENTER));
    pnlEditorButtons.setLayout(new GridLayout());

    //
    // pnlEditorButtons contents
    //

    btnSet = new Button(pnlEditorButtons, SWT.NONE);
    btnSet.setEnabled(false);
    btnSet.setText(Util.getString(PREFIX + "btnSet")); // $NON-NLS-1$
    btnSet.setToolTipText(Util.getString(PREFIX + "btnSet.tip")); // $NON-NLS-1$
    btnSet.addSelectionListener(
        new SelectionAdapter() {
          @Override
          public void widgetSelected(SelectionEvent theEvent) {
            handleSetSelected();
          }
        });

    btnReset = new Button(pnlEditorButtons, SWT.NONE);
    btnReset.setEnabled(false);
    btnReset.setText(Util.getString(PREFIX + "btnReset")); // $NON-NLS-1$
    btnReset.setToolTipText(Util.getString(PREFIX + "btnReset.tip")); // $NON-NLS-1$
    btnReset.addSelectionListener(
        new SelectionAdapter() {
          @Override
          public void widgetSelected(SelectionEvent theEvent) {
            handleResetSelected();
          }
        });

    setLanguageObject(null); // needed to establish the viewer input

    // select root tree node after all construction is finished
    Display.getDefault()
        .asyncExec(
            new Runnable() {
              public void run() {
                treeViewer.selectRoot();
              }
            });
  }

  /* (non-Javadoc)
   * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
   */
  @Override
  protected Control createDialogArea(Composite theParent) {
    originalLanguageObjLabel =
        WidgetFactory.createLabel(theParent, CoreStringUtil.Constants.EMPTY_STRING);
    Composite pnlContents = (Composite) super.createDialogArea(theParent);

    //
    // main panel contents
    //

    CTabFolder tabFolder = WidgetFactory.createTabFolder(pnlContents);

    //
    // tabFolder contents - 2 tabs (Tree, SQL Text), each with a splitter
    //

    CTabItem treeTab =
        WidgetFactory.createTab(tabFolder, Util.getString(PREFIX + "treeTab")); // $NON-NLS-1$
    treeTab.setToolTipText(Util.getString(PREFIX + "treeTab.tip")); // $NON-NLS-1$

    SashForm treeTabSash = new SashForm(tabFolder, SWT.VERTICAL);
    treeTabSash.setLayoutData(new GridData(GridData.FILL_BOTH));
    treeTab.setControl(treeTabSash);

    CTabItem sqlTab =
        WidgetFactory.createTab(tabFolder, Util.getString(PREFIX + "sqlTab")); // $NON-NLS-1$
    sqlTab.setToolTipText(Util.getString(PREFIX + "sqlTab.tip")); // $NON-NLS-1$

    SashForm sqlTabSash = new SashForm(tabFolder, SWT.VERTICAL);
    sqlTabSash.setLayoutData(new GridData(GridData.FILL_BOTH));
    sqlTab.setControl(sqlTabSash);

    //
    // treeTab contents
    //

    ViewForm formTree = new ViewForm(treeTabSash, SWT.BORDER);
    Composite pnlTree = new Composite(formTree, SWT.NO_TRIM);
    formTree.setContent(pnlTree);
    GridLayout layout = new GridLayout();
    layout.marginWidth = 0;
    layout.marginHeight = 0;
    pnlTree.setLayout(layout);
    pnlTree.setLayoutData(new GridData(GridData.FILL_BOTH));

    ViewForm formEditor = new ViewForm(treeTabSash, SWT.BORDER);
    pnlEditor = new Composite(formEditor, SWT.NO_TRIM);
    formEditor.setContent(pnlEditor);
    pnlEditor.setLayoutData(new GridData(GridData.FILL_BOTH));

    lblTitle = new Label(formEditor, SWT.CENTER);
    lblTitle.setBackground(BuilderUtils.COLOR_HIGHLIGHT);
    formEditor.setTopLeft(lblTitle);

    treeTabSash.setWeights(new int[] {30, 70});

    //
    // sqlTab contents
    //

    ViewForm formCurrentSql = new ViewForm(sqlTabSash, SWT.BORDER);
    ViewForm formOriginalSql = new ViewForm(sqlTabSash, SWT.BORDER);

    //
    // formCurrentSql contents
    //

    Composite pnlCurrentSql = new Composite(formCurrentSql, SWT.NONE);
    formCurrentSql.setContent(pnlCurrentSql);
    pnlCurrentSql.setLayout(new GridLayout());
    pnlCurrentSql.setLayoutData(new GridData(GridData.FILL_BOTH));

    currentSql = new SqlDisplayPanel(pnlCurrentSql);
    currentSql.setLayoutData(new GridData(GridData.FILL_BOTH));

    CLabel lblCurrent = new CLabel(formCurrentSql, SWT.NONE);
    lblCurrent.setBackground(BuilderUtils.COLOR_HIGHLIGHT);
    lblCurrent.setText(Util.getString(PREFIX + "lblCurrent")); // $NON-NLS-1$
    lblCurrent.setToolTipText(Util.getString(PREFIX + "lblCurrent.tip")); // $NON-NLS-1$
    formCurrentSql.setTopLeft(lblCurrent);

    //
    // formOriginalSql contents
    //

    Composite pnlOriginalSql = new Composite(formOriginalSql, SWT.NONE);
    formOriginalSql.setContent(pnlOriginalSql);
    pnlOriginalSql.setLayout(new GridLayout());
    pnlOriginalSql.setLayoutData(new GridData(GridData.FILL_BOTH));

    originalSql = new SqlDisplayPanel(pnlOriginalSql);
    originalSql.setLayoutData(new GridData(GridData.FILL_BOTH));

    CLabel lblOriginal = new CLabel(formOriginalSql, SWT.NONE);
    lblOriginal.setBackground(BuilderUtils.COLOR_HIGHLIGHT);
    lblOriginal.setText(Util.getString(PREFIX + "lblOriginal")); // $NON-NLS-1$
    lblOriginal.setToolTipText(Util.getString(PREFIX + "lblOriginal.tip")); // $NON-NLS-1$
    formOriginalSql.setTopLeft(lblOriginal);

    //
    // pnlTree contents - 2 columns (tree viewer, button panel)
    //

    layout = new GridLayout();
    layout.numColumns = 2;
    layout.marginHeight = 0;
    layout.marginWidth = 0;
    pnlTree.setLayout(layout);

    treeViewer = new LanguageObjectBuilderTreeViewer(pnlTree);
    treeViewer.addSelectionChangedListener(
        new ISelectionChangedListener() {
          public void selectionChanged(SelectionChangedEvent theEvent) {
            handleTreeSelection();
          }
        });

    MenuManager menuMgr = new MenuManager();
    menuMgr.setRemoveAllWhenShown(true);
    menuMgr.addMenuListener(
        new IMenuListener() {
          public void menuAboutToShow(IMenuManager theMenuMgr) {
            fillContextMenu(theMenuMgr);
          }
        });
    treeViewer.getTree().setMenu(menuMgr.createContextMenu(treeViewer.getTree()));

    Composite pnlButtons = new Composite(pnlTree, SWT.NONE);
    pnlButtons.setLayout(new GridLayout());

    createTreeButtons(pnlButtons);

    //
    // pnlEditor contents
    //

    layout = new GridLayout();
    layout.numColumns = 2;
    pnlEditor.setLayout(layout);

    pnlEditorDetail = new Composite(pnlEditor, SWT.NONE);
    pnlEditorDetail.setLayoutData(new GridData(GridData.FILL_BOTH));
    pnlEditorDetail.setLayout(new GridLayout());
    return pnlContents;
  }

  protected abstract ILanguageObjectEditor createEditor(Composite theParent);

  /**
   * Creates buttons that interact with the tree.
   *
   * @param theParent the panel where the buttons are contained
   */
  protected void createTreeButtons(Composite theParent) {
    Runnable deleteRunner =
        new Runnable() {
          public void run() {
            handleDeleteSelected();
          }
        };
    deleteAction = new DeleteViewerObjectAction(theParent, deleteRunner);
  }

  protected void fillContextMenu(IMenuManager theMenuMgr) {
    theMenuMgr.add(deleteAction);
  }

  public ILanguageObjectEditor getEditor() {
    return editor;
  }

  /* (non-Javadoc)
   * @see com.metamatrix.query.internal.ui.builder.ILanguageObjectInputProvider#getLanguageObject()
   */
  public LanguageObject getLanguageObject() {
    return treeViewer.getLanguageObject();
  }

  /**
   * Gets the saved <code>LanguageObject</code>.
   *
   * @return the saved <code>LanguageObject</code> or <code>null</code>
   */
  protected LanguageObject getSavedLanguageObject() {
    return savedLangObj;
  }

  /**
   * Gets a title for the builder. Title is appropriate for use as a dialog title.
   *
   * @return the builder title
   */
  @Override
  public abstract String getTitle();

  protected LanguageObjectBuilderTreeViewer getTreeViewer() {
    return treeViewer;
  }

  protected void handleDeleteSelected() {
    editor.clear();
    treeViewer.deleteSelection();

    // update SQL text
    setCurrentSql(treeViewer.getLanguageObject());

    editor.acceptFocus();
  }

  void handleModelChanged() {
    boolean isEnabled = false;
    boolean isComplete = false;
    boolean hasChanged = false;
    isEnabled = editor.isEnabled();
    if (isEnabled) {
      isComplete = editor.isComplete();
    }
    if (isComplete) {
      hasChanged = editor.hasChanged();
    }
    boolean state = (isEnabled && isComplete && hasChanged);
    btnSet.setEnabled(state);
    btnReset.setEnabled(state);

    setCurrentSql(treeViewer.getLanguageObject());

    // set enable/disable status of buttons
    setEnabledStatus();
  }

  protected void handleResetSelected() {
    editor.reset();

    // put focus back on editor from the reset button
    editor.acceptFocus();
  }

  protected void handleSetSelected() {
    editor.save();

    // need the editor's language object in order to update tree.
    // the language object should never be null. if it was this handler should not have been called
    LanguageObject langObj = editor.getLanguageObject();

    CoreArgCheck.isNotNull(
        langObj,
        Util.getString(
            PREFIX + "nullLangObj", // $NON-NLS-1$
            new Object[] {"handleSetSelected"})); // $NON-NLS-1$

    // update tree
    treeViewer.modifySelectedItem(langObj, false);

    // update SQL text
    setCurrentSql(treeViewer.getLanguageObject());

    // put focus back on editor from the set button
    editor.acceptFocus();
  }

  protected void handleTreeSelection() {
    IStructuredSelection selection = (IStructuredSelection) treeViewer.getSelection();
    Object selectedObj = selection.getFirstElement();

    if (selectedObj == null) {
      savedSelection = null;

      if (editor.isEnabled()) {
        editor.setEnabled(false);
      }
    } else {
      // selection with either be a LanguageObject or an Undefined object (String)
      savedSelection =
          (selectedObj instanceof LanguageObject) ? (LanguageObject) selectedObj : null;
    }

    setEditorLanguageObject(savedSelection);

    // set enable/disable status of buttons
    setEnabledStatus();
  }

  protected boolean isTreeSelectionRoot() {
    boolean isRoot = false;
    IStructuredSelection selection = (IStructuredSelection) treeViewer.getSelection();
    if (selection.size() > 0) {
      Tree tree = treeViewer.getTree();
      // We are assuming that the tree is single-selection.
      TreeItem treeItem = tree.getSelection()[0];
      TreeItem parentItem = treeItem.getParentItem();
      isRoot = (parentItem == null);
    }
    return isRoot;
  }

  protected void setCurrentSql(LanguageObject theLangObj) {
    currentSql.setText(SQLStringVisitor.getSQLString(theLangObj));
  }

  protected void setEditorLanguageObject(LanguageObject theEditorLangObj) {
    getEditor().setLanguageObject(savedSelection);

    if (!editor.isEnabled()) {
      editor.setEnabled(true);
    }
  }

  protected void setEnabledStatus() {
    //
    // set enabled status of delete button
    //

    boolean canDelete = treeViewer.canDeleteSelection();

    if (canDelete) {
      if (!deleteAction.isEnabled()) {
        deleteAction.setEnabled(true);
      }
    } else {
      if (deleteAction.isEnabled()) {
        deleteAction.setEnabled(false);
      }
    }

    //
    // set enabled status of OK button
    //

    Button btnOk = getButton(OK);
    boolean enable = treeViewer.isComplete();

    if (btnOk.isEnabled() != enable) {
      btnOk.setEnabled(enable);
    }
  }

  public void setLanguageObject(LanguageObject theLangObj) {
    // language object must be cloned here so that the original isn't modified.
    // this prevents the original from being modified even if the user cancels out of the builder.
    LanguageObject langObj = (theLangObj == null) ? null : (LanguageObject) theLangObj.clone();

    savedLangObj = langObj;
    setOriginalSql(langObj);
    setCurrentSql(langObj);
    treeViewer.setLanguageObject(langObj);
    treeViewer.selectRoot();
    treeViewer.expandAll();

    // Defect 22003 - needed a context for the original expression
    // Providing a Lable at the top of the dialog.
    String labelText =
        Util.getString(PREFIX + "initialExpression")
            + //$NON-NLS-1$
            CoreStringUtil.Constants.DBL_SPACE
            + CoreStringUtil.Constants.DBL_SPACE
            + Util.getString(PREFIX + "undefined"); // $NON-NLS-1$
    if (savedLangObj != null) {
      String loString = savedLangObj.toString();
      if (loString.length() > 50) {
        loString = loString.substring(0, 50) + "..."; // $NON-NLS-1$
      }
      labelText =
          Util.getString(PREFIX + "initialExpression")
              + //$NON-NLS-1$
              CoreStringUtil.Constants.DBL_SPACE
              + CoreStringUtil.Constants.DBL_SPACE
              + loString;
    }
    if (originalLanguageObjLabel != null) {
      originalLanguageObjLabel.setText(labelText);
      originalLanguageObjLabel.getParent().layout();
    }
    // select root tree node
    Display.getDefault()
        .asyncExec(
            new Runnable() {
              public void run() {
                treeViewer.selectRoot();
              }
            });
  }

  protected void setOriginalSql(LanguageObject theLangObj) {
    originalSql.setText(SQLStringVisitor.getSQLString(theLangObj));
  }
}
/**
 * Implements the SourceHandler interface which provides the VDB Editor the ability to access
 * DQP-related connection info.
 */
public class VdbSourceConnectionHandler implements SourceHandler {
  static final String PREFIX = I18nUtil.getPropertyPrefix(VdbSourceConnectionHandler.class);

  private static SelectTranslatorAction selectTranslatorAction;

  private static SelectJndiDataSourceAction selectJndiDataSourceAction;

  private static Object[] actions;

  private static boolean initialized = false;

  static String getString(final String stringId) {
    return UTIL.getString(PREFIX + stringId);
  }

  @Override
  public VdbSourceConnection ensureVdbSourceConnection(
      String sourceModelname, Properties properties) throws Exception {
    CoreArgCheck.isNotNull(properties, "properties"); // $NON-NLS-1$

    ModelConnectionMapper mapper = new ModelConnectionMapper(sourceModelname, properties);

    VdbSourceConnection vdbSourceConnection = null;

    ExecutionAdmin defaultAdmin = getDefaultServer().getAdmin();

    String uuid = ModelerCore.workspaceUuid().toString();

    try {
      vdbSourceConnection = mapper.getVdbSourceConnection(defaultAdmin, uuid);
    } catch (ModelWorkspaceException e) {
      UTIL.log(
          IStatus.ERROR,
          e,
          UTIL.getString(
              "VdbSourceConnectionHandler.Error_could_not_find_source_connection_info_for_{0}_model",
              sourceModelname)); //$NON-NLS-1$
    }

    // TODO: vdbSourceConnection may be NULL, so query the user for translator name & jndi name

    return vdbSourceConnection;
  }

  @Override
  public Object[] getApplicableActions(Object obj) {
    if (!initialized) {
      initialize();
    }
    Server defServer = getDefaultServer();
    if (defServer == null || !defServer.isConnected()) {
      return null;
    }

    if (obj instanceof IStructuredSelection) {
      IStructuredSelection sel = (IStructuredSelection) obj;
      if (sel.getFirstElement() instanceof VdbModelEntry) {
        if (((VdbModelEntry) sel.getFirstElement()).getType() == ModelType.PHYSICAL_LITERAL) {
          selectTranslatorAction.setSelection((VdbModelEntry) sel.getFirstElement());
          selectJndiDataSourceAction.setSelection((VdbModelEntry) sel.getFirstElement());
          return actions;
        }
      }
    }
    selectTranslatorAction.setSelection(null);
    selectJndiDataSourceAction.setSelection(null);
    return null;
  }

  private void initialize() {
    // Construct the two actions
    selectTranslatorAction =
        new SelectTranslatorAction(getString("selectTranslatorAction.label")); // $NON-NLS-1$

    selectJndiDataSourceAction =
        new SelectJndiDataSourceAction(
            getString("selectJndiDataSourceAction.label")); // $NON-NLS-1$

    Collection<IAction> actionsList = new ArrayList();
    actionsList.add(selectTranslatorAction);
    actionsList.add(selectJndiDataSourceAction);

    actions = actionsList.toArray();
  }

  class SelectJndiDataSourceAction extends Action {

    public SelectJndiDataSourceAction(String text) {
      super(text);
      // TODO Auto-generated constructor stub
    }

    private VdbModelEntry vdbModelEntry;

    public void setSelection(VdbModelEntry vdbModelEntry) {
      this.vdbModelEntry = vdbModelEntry;
    }

    @Override
    public void run() {
      // Get available servers and launch SelectTranslatorDialog
      // vdbModelEntry should not be null and should be a Physical model only
      if (vdbModelEntry != null) {
        String jndiName = vdbModelEntry.getJndiName();

        SelectJndiDataSourceDialog dialog =
            new SelectJndiDataSourceDialog(Display.getCurrent().getActiveShell());

        TeiidDataSource initialSelection = null;
        Server defServer = getDefaultServer();
        if (defServer != null && defServer.isConnected()) {
          try {
            initialSelection = defServer.getAdmin().getDataSource(jndiName);
          } catch (Exception e) {
            UTIL.log(
                IStatus.ERROR,
                e,
                UTIL.getString(
                    "VdbSourceConnectionHandler.Error_could_not_find_data_source_for_name",
                    jndiName)); //$NON-NLS-1$
          }
          dialog.setInitialSelection(initialSelection);
        }

        dialog.open();

        if (dialog.getReturnCode() == Window.OK) {
          Object result = dialog.getFirstResult();
          if (result != null && result instanceof TeiidDataSource) {
            vdbModelEntry.setJndiName(((TeiidDataSource) result).getName());
          }
        }
      }
    }
  }

  class SelectTranslatorAction extends Action {

    public SelectTranslatorAction(String text) {
      super(text);
      // TODO Auto-generated constructor stub
    }

    private VdbModelEntry vdbModelEntry;

    public void setSelection(VdbModelEntry vdbModelEntry) {
      this.vdbModelEntry = vdbModelEntry;
    }

    @Override
    public void run() {
      // Get available servers and launch SelectTranslatorDialog
      // vdbModelEntry should not be null and should be a Physical model only

      if (vdbModelEntry != null) {
        String transName = vdbModelEntry.getTranslator();

        SelectTranslatorDialog dialog =
            new SelectTranslatorDialog(Display.getCurrent().getActiveShell());

        TeiidTranslator initialSelection = null;
        Server defServer = getDefaultServer();
        if (defServer != null && defServer.isConnected()) {
          try {
            initialSelection = defServer.getAdmin().getTranslator(transName);
          } catch (Exception e) {
            UTIL.log(
                IStatus.ERROR,
                e,
                UTIL.getString(
                    "VdbSourceConnectionHandler.Error_could_not_find_translator_for_name",
                    transName)); //$NON-NLS-1$
          }
          dialog.setInitialSelection(initialSelection);
        }

        dialog.open();

        if (dialog.getReturnCode() == Window.OK) {
          Object result = dialog.getFirstResult();
          if (result != null && result instanceof TeiidTranslator) {
            vdbModelEntry.setTranslator(((TeiidTranslator) result).getName());
          }
        }
      }
    }
  }

  /**
   * {@inheritDoc}
   *
   * @see org.teiid.designer.vdb.connections.SourceHandler#getDataSourceNames()
   */
  @Override
  public String[] getDataSourceNames() {
    Server defaultServer = getDefaultServer();

    if ((defaultServer != null) && defaultServer.isConnected()) {
      Collection<TeiidDataSource> dataSources = null;

      try {
        dataSources = defaultServer.getAdmin().getDataSources();
      } catch (Exception e) {
        UTIL.log(
            IStatus.ERROR,
            e,
            UTIL.getString(
                "VdbSourceConnectionHandler.errorObtainingDataSources",
                defaultServer.getHost())); // $NON-NLS-1$
      }

      if (dataSources != null) {
        Collection<String> dataSourceNames = new ArrayList<String>();

        for (TeiidDataSource dataSource : dataSources) {
          if (!dataSource.isPreview()) {
            dataSourceNames.add(dataSource.getName());
          }
        }

        return dataSourceNames.toArray(new String[dataSourceNames.size()]);
      }
    }

    return null;
  }

  Server getDefaultServer() {
    return DqpPlugin.getInstance().getServerManager().getDefaultServer();
  }

  /**
   * {@inheritDoc}
   *
   * @see
   *     org.teiid.designer.vdb.connections.SourceHandler#getTranslatorDefinitions(java.lang.String)
   */
  @Override
  public PropertyDefinition[] getTranslatorDefinitions(String translatorName) {
    if (StringUtilities.isEmpty(translatorName)) {
      throw new IllegalArgumentException();
    }

    Server defaultServer = getDefaultServer();

    if ((defaultServer != null) && defaultServer.isConnected()) {
      try {
        TeiidTranslator translator = defaultServer.getAdmin().getTranslator(translatorName);

        if (translator != null) {
          Collection<PropertyDefinition> props = new ArrayList<PropertyDefinition>();

          for (org.teiid.adminapi.PropertyDefinition propDefn :
              translator.getPropertyDefinitions()) {
            TranslatorProperty prop = new TranslatorProperty(propDefn.getPropertyTypeClassName());
            prop.advanced = propDefn.isAdvanced();
            prop.description = propDefn.getDescription();
            prop.displayName = propDefn.getDisplayName();
            prop.id = propDefn.getName();
            prop.masked = propDefn.isMasked();
            prop.modifiable = propDefn.isModifiable();
            prop.required = propDefn.isRequired();

            prop.defaultValue =
                (propDefn.getDefaultValue() == null)
                    ? StringUtilities.EMPTY_STRING
                    : propDefn.getDefaultValue().toString();

            if (propDefn.isConstrainedToAllowedValues()) {
              Collection values = propDefn.getAllowedValues();
              prop.allowedValues = new String[values.size()];
              int i = 0;

              for (Object value : values) {
                prop.allowedValues[i++] = value.toString();
              }
            } else {
              // if boolean type turn into allowed values
              String type = propDefn.getPropertyTypeClassName();

              if (Boolean.class.getName().equals(type) || Boolean.TYPE.getName().equals(type)) {
                prop.allowedValues =
                    new String[] {Boolean.TRUE.toString(), Boolean.FALSE.toString()};
              }
            }

            props.add(prop);
          }

          return props.toArray(new PropertyDefinition[props.size()]);
        }
      } catch (Exception e) {
        UTIL.log(
            IStatus.ERROR,
            e,
            UTIL.getString(
                "VdbSourceConnectionHandler.errorObtainingTranslatorProperties", //$NON-NLS-1$
                translatorName,
                defaultServer.getHost()));
      }
    }

    return null;
  }

  /**
   * {@inheritDoc}
   *
   * @see org.teiid.designer.vdb.connections.SourceHandler#getTranslatorTypes()
   */
  @Override
  public String[] getTranslatorTypes() {
    Server defaultServer = getDefaultServer();

    if ((defaultServer != null) && defaultServer.isConnected()) {
      Collection<TeiidTranslator> translators = null;

      try {
        translators = defaultServer.getAdmin().getTranslators();
      } catch (Exception e) {
        UTIL.log(
            IStatus.ERROR,
            e,
            UTIL.getString(
                "VdbSourceConnectionHandler.errorObtainingTranslators",
                defaultServer.getHost())); // $NON-NLS-1$
      }

      if (translators != null) {
        Collection<String> translatorTypes = new ArrayList<String>();

        for (TeiidTranslator translator : translators) {
          translatorTypes.add(translator.getName());
        }

        return translatorTypes.toArray(new String[translatorTypes.size()]);
      }
    }

    return null;
  }

  class TranslatorProperty implements PropertyDefinition {

    private final String className;

    boolean advanced;
    String[] allowedValues;
    String defaultValue;
    String description;
    String displayName;
    String id;
    boolean masked;
    boolean modifiable;
    boolean required;

    public TranslatorProperty(String className) {
      this.className = className;
    }

    /**
     * {@inheritDoc}
     *
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
      if (this == obj) {
        return true;
      }

      if ((obj == null) || (getClass() != obj.getClass())) {
        return false;
      }

      return this.id.equals(((TranslatorProperty) obj).id);
    }

    /**
     * {@inheritDoc}
     *
     * @see org.teiid.designer.core.properties.PropertyDefinition#getAllowedValues()
     */
    @Override
    public String[] getAllowedValues() {
      return this.allowedValues;
    }

    /**
     * {@inheritDoc}
     *
     * @see org.teiid.designer.core.properties.PropertyDefinition#getDefaultValue()
     */
    @Override
    public String getDefaultValue() {
      return this.defaultValue;
    }

    /**
     * {@inheritDoc}
     *
     * @see org.teiid.designer.core.properties.PropertyDefinition#getDescription()
     */
    @Override
    public String getDescription() {
      return this.description;
    }

    /**
     * {@inheritDoc}
     *
     * @see org.teiid.designer.core.properties.PropertyDefinition#getDisplayName()
     */
    @Override
    public String getDisplayName() {
      return this.displayName;
    }

    /**
     * {@inheritDoc}
     *
     * @see org.teiid.designer.core.properties.PropertyDefinition#getId()
     */
    @Override
    public String getId() {
      return this.id;
    }

    /**
     * {@inheritDoc}
     *
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
      return this.id.hashCode();
    }

    /**
     * {@inheritDoc}
     *
     * @see org.teiid.designer.core.properties.PropertyDefinition#isAdvanced()
     */
    @Override
    public boolean isAdvanced() {
      return this.advanced;
    }

    /**
     * {@inheritDoc}
     *
     * @see org.teiid.designer.core.properties.PropertyDefinition#isMasked()
     */
    @Override
    public boolean isMasked() {
      return this.masked;
    }

    /**
     * {@inheritDoc}
     *
     * @see org.teiid.designer.core.properties.PropertyDefinition#isModifiable()
     */
    @Override
    public boolean isModifiable() {
      return this.modifiable;
    }

    /**
     * {@inheritDoc}
     *
     * @see org.teiid.designer.core.properties.PropertyDefinition#isRequired()
     */
    @Override
    public boolean isRequired() {
      return this.required;
    }

    /**
     * {@inheritDoc}
     *
     * @see org.teiid.designer.core.properties.PropertyDefinition#isValidValue(java.lang.String)
     */
    @Override
    public String isValidValue(String newValue) {
      // if empty must have a value or a default value if required
      if (StringUtilities.isEmpty(newValue)) {
        // invalid if required and no default value
        if (isRequired() && StringUtilities.isEmpty(getDefaultValue())) {
          return Util.getString("invalidNullPropertyValue", getDisplayName()); // $NON-NLS-1$
        }

        // OK to be null/empty
        return null;
      }

      if (Boolean.class.getName().equals(this.className)
          || Boolean.TYPE.getName().equals(this.className)) {
        if (!newValue.equalsIgnoreCase(Boolean.TRUE.toString())
            && !newValue.equalsIgnoreCase(Boolean.FALSE.toString())) {
          return Util.getString(
              "invalidPropertyValueForType", newValue, Boolean.TYPE.getName()); // $NON-NLS-1$
        }
      } else if (Character.class.getName().equals(this.className)
          || Character.TYPE.getName().equals(this.className)) {
        if (newValue.length() != 1) {
          return Util.getString(
              "invalidPropertyValueForType", newValue, Character.TYPE.getName()); // $NON-NLS-1$
        }
      } else if (Byte.class.getName().equals(this.className)
          || Byte.TYPE.getName().equals(this.className)) {
        try {
          Byte.parseByte(newValue);
        } catch (Exception e) {
          return Util.getString(
              "invalidPropertyValueForType", newValue, Byte.TYPE.getName()); // $NON-NLS-1$
        }
      } else if (Short.class.getName().equals(this.className)
          || Short.TYPE.getName().equals(this.className)) {
        try {
          Short.parseShort(newValue);
        } catch (Exception e) {
          return Util.getString(
              "invalidPropertyValueForType", newValue, Short.TYPE.getName()); // $NON-NLS-1$
        }
      } else if (Integer.class.getName().equals(this.className)
          || Integer.TYPE.getName().equals(this.className)) {
        try {
          Integer.parseInt(newValue);
        } catch (Exception e) {
          return Util.getString(
              "invalidPropertyValueForType", newValue, Integer.TYPE.getName()); // $NON-NLS-1$
        }
      } else if (Long.class.getName().equals(this.className)
          || Long.TYPE.getName().equals(this.className)) {
        try {
          Long.parseLong(newValue);
        } catch (Exception e) {
          return Util.getString(
              "invalidPropertyValueForType", newValue, Long.TYPE.getName()); // $NON-NLS-1$
        }
      } else if (Float.class.getName().equals(this.className)
          || Float.TYPE.getName().equals(this.className)) {
        try {
          Float.parseFloat(newValue);
        } catch (Exception e) {
          return Util.getString(
              "invalidPropertyValueForType", newValue, Float.TYPE.getName()); // $NON-NLS-1$
        }
      } else if (Double.class.getName().equals(this.className)
          || Double.TYPE.getName().equals(this.className)) {
        try {
          Double.parseDouble(newValue);
        } catch (Exception e) {
          return Util.getString(
              "invalidPropertyValueForType", newValue, Double.TYPE.getName()); // $NON-NLS-1$
        }
      } else if (!String.class.getName().equals(this.className)) {
        return Util.getString(
            "unknownPropertyType", this.displayName, this.className); // $NON-NLS-1$
      }

      // valid value
      return null;
    }
  }
}
/** ElementEditor */
public class ElementEditor extends AbstractLanguageObjectEditor {

  private static final String PREFIX = I18nUtil.getPropertyPrefix(ElementEditor.class);

  private ViewController controller;

  private ElementEditorModel model;

  private ICriteriaStrategy strategy;

  private Composite pnlContent;

  private TreeViewer viewer;

  /**
   * Constructs a <code>ElementEditor</code> using the given model.
   *
   * @param theParent the parent container
   * @param theModel the editor's model
   * @throws IllegalArgumentException if any of the parameters are <code>null</code>
   */
  public ElementEditor(Composite theParent, ElementEditorModel theModel) {
    super(theParent, ElementSymbol.class, theModel);
    controller = new ViewController();
    model = theModel;
    model.addModelListener(controller);

    // set the viewer on the CriteriaStrategy
    strategy = ElementViewerFactory.getCriteriaStrategy(viewer);
    strategy.setTreeViewer(viewer);
  }

  /** @see com.metamatrix.modeler.transformation.ui.builder.ILanguageObjectEditor#acceptFocus() */
  @Override
  public void acceptFocus() {
    viewer.getTree().setFocus();
  }

  /**
   * @see
   *     com.metamatrix.modeler.transformation.ui.builder.AbstractLanguageObjectEditor#createUi(org.eclipse.swt.widgets.Composite)
   */
  @Override
  protected void createUi(Composite theParent) {
    pnlContent = new Composite(theParent, SWT.NONE);
    pnlContent.setLayoutData(new GridData(GridData.FILL_BOTH));
    pnlContent.setLayout(new FillLayout());

    //
    // pnlContent contents
    //

    viewer = ElementViewerFactory.createElementViewer(pnlContent);
    viewer.addDoubleClickListener(
        new IDoubleClickListener() {
          public void doubleClick(DoubleClickEvent theEvent) {
            handleDoubleClick();
          }
        });
    viewer.addSelectionChangedListener(
        new ISelectionChangedListener() {
          public void selectionChanged(SelectionChangedEvent theEvent) {
            handleTreeSelection();
          }
        });
    viewer.expandAll();
  }

  /** Displays the appropriate UI for the current model state. */
  void displayElementSymbol() {
    CoreArgCheck.isNotNull(viewer);

    StructuredSelection selection = StructuredSelection.EMPTY;

    if (model.getElementSymbol() != null) {
      strategy.setTreeViewer(viewer); // make sure this viewer is set before using strategy
      Object node = strategy.getNode(model.getElementSymbol());

      if (node != null) {
        selection = new StructuredSelection(node);
      }

      if (!selection.equals(viewer.getSelection())) {
        viewer.setSelection(selection);
      }
    }
  }

  /** @see com.metamatrix.modeler.transformation.ui.builder.ILanguageObjectEditor#getTitle() */
  @Override
  public String getTitle() {
    return Util.getString(PREFIX + "title"); // $NON-NLS-1$
  }

  /**
   * @see
   *     com.metamatrix.modeler.transformation.ui.builder.AbstractLanguageObjectEditor#getToolTipText()
   */
  @Override
  public String getToolTipText() {
    return Util.getString(PREFIX + "tip"); // $NON-NLS-1$
  }

  /** Handler for double-click in tree. */
  void handleDoubleClick() {}

  /** Handler for tree selection. */
  void handleTreeSelection() {
    IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
    ElementSymbol element = null;

    if (!selection.isEmpty()) {
      ICriteriaStrategy strategy = ElementViewerFactory.getCriteriaStrategy(viewer);
      strategy.setTreeViewer(viewer); // make sure this viewer is set before using strategy

      if (strategy.isValid(selection.getFirstElement())) {
        Object eObj = selection.getFirstElement();
        if (eObj instanceof ElementSymbol) {
          element = ((ElementSymbol) eObj);
        } else {
          element = new ElementSymbol(strategy.getRuntimeFullName(eObj), true);

          // the viewer model contains EObjects. so the objects in the selection will
          // be EObjects. since the EObject is used later on in the QueryCriteriaStrategy.getNode()
          // method. save it here.
          element.setMetadataID(eObj);
        }
      }
    }

    model.selectElementSymbol(element);
  }

  /**
   * @see
   *     com.metamatrix.modeler.transformation.ui.builder.ILanguageObjectEditor#setLanguageObject(com.metamatrix.query.sql.LanguageObject)
   */
  @Override
  public void setLanguageObject(LanguageObject theLanguageObject) {
    if (theLanguageObject == null) {
      clear();
    } else {
      if (!(theLanguageObject instanceof ElementSymbol)) {
        CoreArgCheck.isTrue(
            (theLanguageObject instanceof ElementSymbol),
            Util.getString(
                PREFIX + "invalidLanguageObject", // $NON-NLS-1$
                new Object[] {theLanguageObject.getClass().getName()}));
      }

      model.setLanguageObject(theLanguageObject);
    }
  }

  /**
   * The <code>ViewController</code> class is a view controller for the <code>ElementEditor</code>.
   */
  class ViewController implements ILanguageObjectEditorModelListener {

    /**
     * @see
     *     com.metamatrix.query.internal.ui.builder.model.ILanguageObjectEditorModelListener#modelChanged(com.metamatrix.query.internal.ui.builder.model.LanguageObjectEditorModelEvent)
     */
    public void modelChanged(LanguageObjectEditorModelEvent theEvent) {
      displayElementSymbol();
    }
  }
}