at.spardat.xma.gui.mapper.MapperDialog.java Source code

Java tutorial

Introduction

Here is the source code for at.spardat.xma.gui.mapper.MapperDialog.java

Source

/*******************************************************************************
 * Copyright (c) 2003, 2007 s IT Solutions AT Spardat GmbH .
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     s IT Solutions AT Spardat GmbH - initial API and implementation
 *******************************************************************************/

// @(#) $Id: MapperDialog.java 6339 2010-07-29 15:06:02Z laslovd $
package at.spardat.xma.gui.mapper;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.StringTokenizer;

import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.dnd.DropTargetAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.TypedEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.PlatformUI;

import at.spardat.xma.gui.mapper.MdlRelationships.Relationship;
import at.spardat.xma.gui.mapper.TreeMapGraphics.IRelationship;
import at.spardat.xma.gui.mapper.mapprovider.BOLoadHandler;
import at.spardat.xma.guidesign.GuidesignFactory;
import at.spardat.xma.guidesign.HiddenWidget;
import at.spardat.xma.guidesign.IBDAttachable;
import at.spardat.xma.guidesign.XMAComponent;
import at.spardat.xma.guidesign.XMAComposite;
import at.spardat.xma.guidesign.XMALabel;
import at.spardat.xma.guidesign.XMASeperator;
import at.spardat.xma.guidesign.XMATable;
import at.spardat.xma.guidesign.XMATableColumn;
import at.spardat.xma.guidesign.XMAWidget;
import at.spardat.xma.guidesign.presentation.GuidesignEditor;
import at.spardat.xma.guidesign.types.AttachSideType;

/**
 * Main dialog to support mapping widgets <--> business data
 *
 * @author YSD, 09.07.2003 16:14:55
 */
public class MapperDialog extends TitleAreaDialog
        implements BDInstanceSelectionDialog.Validator, TreeMapGraphics.ITreeMapGraphicsChannel {

    //for debugging
    private static boolean debug = false;

    {
        String value = Platform.getDebugOption("at.spardat.xma.mapper/debug/mapper");
        if (value != null && value.equalsIgnoreCase("true")) {
            MapperDialog.debug = true;
        }
    }

    static void debug(String message) {
        if (MapperDialog.debug) {
            System.out.println(message);
        }
    }
    // end debugging stuff

    static {
        String[] images = { "class.gif", "classError.gif", "method.gif", "methodError.gif" };
        for (int i = 0; i < images.length; i++) {
            MapperPlugin.registerImage(images[i], ImageDescriptor.createFromFile(MapperPlugin.class, images[i]));
        }
    }

    private static final String DEFAULT_MESSAGE = "Drag a widget from left to right to connect it to an attribute of a BusinessData. Drag a set of attributes from right to left to create new widgets for the selected attributes.";

    private XMAComponent xmaC_;
    private IJavaProject jp_;
    private GuidesignEditor gEditor_;
    private MdlBDCollection mdlRoot_;
    private MdlRelationships mdlRels_;
    private ModelConverter mdlConverter_;

    /**
     * temporary used
     */
    private MdlBusinessObject tmpBD_;

    /**
     * The object in widgetTreeViewer that is the starting point of a drag operation
     */
    private IBDAttachable leftDragObject_;

    Composite widgetTreeComposite;
    Label widgetTreeLabel;
    Tree widgetTreeW;
    MyTreeViewer widgetTreeViewer;
    Canvas relArea;
    Composite bdTreeComposite;
    Label bdTreeLabel;
    Tree bdTree;
    MyTreeViewer bdTreeViewer;
    SashForm sashForm;
    Button newBDW;
    Button bdDeleteW;
    Button upW;
    Button downW;
    Label separator;
    Button chkShowSepLabels;
    Button chkorder;

    private TreeMapGraphics mapGraphics_;

    private GuidesignFactory factory_;

    private MdlAttribute[] rightDragSource_;

    // temporarely used
    private Widget lastRightDropItem_;

    // state variable that indicates if seperator attach info are shown
    protected boolean showSepLabels = false;

    // state variable that indicates if the widgettree is shown in lexical order
    protected boolean showWTreeOrdered = false;

    /**
     * Constructor
     *
     * @param parent
     * @param xmaC
     * @param jp
     */
    public MapperDialog(Shell parent, XMAComponent xmaC, IJavaProject jp, GuidesignEditor gEditor) {
        super(parent);
        xmaC_ = xmaC;
        gEditor_ = gEditor;

        // todo remove the next line
        // ModelConverter.printXMAComponent(xmaC);

        jp_ = jp;

        // register types of extending Plugins
        ISafeRunnable runnable = new ISafeRunnable() {
            public void handleException(Throwable ex) {
                // more than on extension is defined log error
                IStatus status = new Status(IStatus.ERROR, MapperPlugin.PLUGINID, -1,
                        "Problems registering mappings of " + MapperPlugin.getDefault().getExtensionId(), ex);
                MapperPlugin.getDefault().getLog().log(status);
            }

            public void run() throws Exception {
                MapperPlugin.getDefault().getMappingProvider().registerMappings();
            }
        };
        Platform.run(runnable);

        // load from XMAComponent
        mdlRoot_ = new MdlBDCollection();
        mdlRels_ = new MdlRelationships(mdlRoot_, xmaC);
        factory_ = GuidesignFactory.eINSTANCE;
        mdlConverter_ = new ModelConverter(xmaC, jp, mdlRoot_, mdlRels_, factory_);
        IInfoChannel iChannel = new MessageBoxChannel(parent);
        mdlConverter_.xma2local(iChannel);
    }

    protected void configureShell(Shell shell) {
        super.configureShell(shell);
        shell.setText("Map Widgets to Business Data Attributes");
    }

    /**
     * @see org.eclipse.jface.dialogs.TitleAreaDialog#createDialogArea(org.eclipse.swt.widgets.Composite)
     */
    protected Control createDialogArea(Composite parent) {

        // set help
        PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, "xmaMapper.MapperDialog");

        Composite myComposite = new Composite(parent, SWT.NULL);
        GridData gd = new GridData(GridData.FILL_BOTH);
        myComposite.setLayoutData(gd);

        FormLayout layout = new FormLayout();
        layout.marginHeight = 10;
        layout.marginWidth = 10;
        myComposite.setLayout(layout);

        FormData data;

        sashForm = new SashForm(myComposite, SWT.HORIZONTAL);

        widgetTreeW = new Tree(sashForm, SWT.BORDER | SWT.SINGLE);
        widgetTreeViewer = new MyTreeViewer(widgetTreeW);
        WidgetTreeProvider wtProv = new WidgetTreeProvider();
        WidgetTreeProvider.setShowLeftAttachSep(showSepLabels);
        widgetTreeViewer.setLabelProvider(wtProv);
        widgetTreeViewer.setContentProvider(wtProv);
        widgetTreeViewer.setInput(xmaC_);
        widgetTreeViewer.expandAll();
        widgetTreeLabel = new Label(myComposite, SWT.NULL);

        relArea = new Canvas(sashForm, SWT.NULL);

        bdTree = new Tree(sashForm, SWT.BORDER | SWT.MULTI);
        bdTreeViewer = new MyTreeViewer(bdTree);
        BDTreeProvider bdTreeProvider = new BDTreeProvider();
        bdTreeViewer.setLabelProvider(bdTreeProvider);
        bdTreeViewer.setContentProvider(bdTreeProvider);
        bdTreeViewer.setInput(mdlRoot_);
        bdTreeViewer.expandAll();
        bdTreeLabel = new Label(myComposite, SWT.NULL);
        bdTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
            public void selectionChanged(SelectionChangedEvent event) {
                stateChanged();
            }
        });

        newBDW = new Button(myComposite, SWT.PUSH | SWT.CENTER);
        bdDeleteW = new Button(myComposite, SWT.PUSH | SWT.CENTER);
        upW = new Button(myComposite, SWT.PUSH | SWT.CENTER);
        downW = new Button(myComposite, SWT.PUSH | SWT.CENTER);

        separator = new Label(myComposite, SWT.SEPARATOR | SWT.HORIZONTAL);

        chkShowSepLabels = new Button(myComposite, SWT.CHECK | SWT.LEFT);
        chkorder = new Button(myComposite, SWT.CHECK | SWT.LEFT);

        widgetTreeLabel.setText("Widgets:");
        bdTreeLabel.setText("Attributes:");
        data = new FormData();
        data.right = new FormAttachment(100, 0);
        bdTreeLabel.setLayoutData(data);

        data = new FormData();
        data.left = new FormAttachment(0, 0);
        data.right = new FormAttachment(100, 0);
        data.top = new FormAttachment(widgetTreeLabel, 5);
        data.bottom = new FormAttachment(newBDW, -5, SWT.TOP);
        sashForm.setLayoutData(data);
        sashForm.setWeights(new int[] { 48, 22, 30 });
        sashForm.setLayout(new FormLayout());

        downW.setText("Down");
        data = new FormData();
        //data.width = 70;
        data.right = new FormAttachment(100, 0);
        data.bottom = new FormAttachment(separator, -5, SWT.TOP);
        downW.setLayoutData(data);
        downW.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                down_Selected();
            }
        });

        upW.setText("Up");
        data = new FormData();
        //data.width = 70;
        data.right = new FormAttachment(downW, -5, SWT.LEFT);
        data.bottom = new FormAttachment(separator, -5, SWT.TOP);
        upW.setLayoutData(data);
        upW.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                up_Selected();
            }
        });

        newBDW.setText("New...");
        data = new FormData();
        data.width = 70;
        data.right = new FormAttachment(upW, -5, SWT.LEFT);
        data.bottom = new FormAttachment(separator, -5, SWT.TOP);
        newBDW.setLayoutData(data);
        newBDW.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                newBD_Selected();
            }
        });

        bdDeleteW.setText("Delete");
        data = new FormData();
        data.width = 70;
        data.right = new FormAttachment(newBDW, -5, SWT.LEFT);
        data.bottom = new FormAttachment(separator, -5, SWT.TOP);
        bdDeleteW.setLayoutData(data);
        bdDeleteW.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                deleteBD_Selected();
            }
        });

        // separator
        data = new FormData();
        data.left = new FormAttachment(0, 0);
        data.right = new FormAttachment(100, 0);
        data.bottom = new FormAttachment(100, 0);
        separator.setLayoutData(data);

        // chkbox for seperator labels
        chkShowSepLabels.setText("Show Sep.leftAttach");
        chkShowSepLabels.setToolTipText("Show to which seperator the widgets are left attached");
        data = new FormData();
        data.width = 130;
        data.left = new FormAttachment(0, 0);
        data.bottom = new FormAttachment(separator, -5, SWT.TOP);
        chkShowSepLabels.setLayoutData(data);
        chkShowSepLabels.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                if (showSepLabels) {
                    showSepLabels = false;
                } else {
                    showSepLabels = true;
                }
                WidgetTreeProvider.setShowLeftAttachSep(showSepLabels);
                widgetTreeViewer.refresh(true);
            }
        });

        // chkbox for wtree in lexical order
        chkorder.setText("Order widgets");
        chkorder.setToolTipText("Show the widgets inside each hierachical group in lexical order");
        data = new FormData();
        data.width = 100;
        data.left = new FormAttachment(chkShowSepLabels, 5, SWT.RIGHT);
        data.bottom = new FormAttachment(separator, -5, SWT.TOP);
        chkorder.setLayoutData(data);
        chkorder.addSelectionListener(new SelectionAdapter() {
            private ViewerComparator myViewerComperator = new ViewerComparator() {
                Comparator comp = new Comparator() {
                    public int compare(Object o1, Object o2) {
                        String s1 = ((String) o1).substring(0, ((String) o1).indexOf(" : "));
                        String s2 = ((String) o2).substring(0, ((String) o2).indexOf(" : "));
                        if (s1 == null)
                            s1 = "";
                        if (s2 == null)
                            s2 = "";
                        return s1.compareToIgnoreCase(s2);
                    }
                };

                protected Comparator getComparator() {
                    return comp;
                }
            };

            public void widgetSelected(SelectionEvent e) {
                if (showWTreeOrdered) {
                    showWTreeOrdered = false;
                    widgetTreeViewer.setComparator(null);
                } else {
                    showWTreeOrdered = true;
                    widgetTreeViewer.setComparator(myViewerComperator);
                }
                widgetTreeViewer.refresh(true);
            }
        });

        mapGraphics_ = new TreeMapGraphics(widgetTreeW, relArea, bdTree, this);

        //        tabOrder = new Control[3];
        //        tabOrder[1] = newBDW;
        //        tabOrder[2] = bdDeleteW;
        //        myComposite.setTabList (tabOrder);

        /**
         * dnd support
         */
        widgetTreeViewer.addDragSupport(DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK,
                new Transfer[] { TextTransfer.getInstance() }, new WidgetTreeDragSource());

        bdTreeViewer.addDropSupport(DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK,
                new Transfer[] { TextTransfer.getInstance() }, new BDTreeDropTarget());

        bdTreeViewer.addDragSupport(DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK,
                new Transfer[] { TextTransfer.getInstance() }, new BDTreeDragSource());

        widgetTreeViewer.addDropSupport(DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK,
                new Transfer[] { TextTransfer.getInstance() }, new WidgetTreeDropTarget());

        // register selection listener on the widget tree
        widgetTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
            public void selectionChanged(SelectionChangedEvent event) {
                widgetTreeSelectionChanged(event);
            }
        });

        // register selection listener on the business data tree
        bdTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
            public void selectionChanged(SelectionChangedEvent event) {
                bdTreeSelectionChanged(event);
            }
        });

        return myComposite;
    }

    /**
     * Adds buttons to this dialog's button bar.
     */
    protected void createButtonsForButtonBar(Composite parent) {
        createButton(parent, IDialogConstants.OK_ID, "Close", true);
    }

    //    /**
    //     * @see org.eclipse.jface.window.Window#setShellStyle(int)
    //     */
    //    protected void setShellStyle (int newShellStyle) {
    //        super.setShellStyle (SWT.APPLICATION_MODAL | SWT.CLOSE | SWT.RESIZE | SWT.TITLE);
    //    }
    //
    public int open() {
        super.setShellStyle(SWT.APPLICATION_MODAL | SWT.TITLE | SWT.RESIZE | SWT.CLOSE | SWT.MAX);
        //super.setShellStyle ();
        create();
        getShell().setSize(700, 600);
        getShell().layout();
        //getShell().pack();
        stateChanged();
        widgetTreeViewer.setSelection(gEditor_.getSelection());
        return super.open();
    }

    private void newBD_Selected() {
        BDInstanceSelectionDialog dia = new BDInstanceSelectionDialog(getShell(),
                BDInstanceSelectionDialog.MODE_NEW, xmaC_, jp_, this);
        if (dia.open() == BDInstanceSelectionDialog.OK) {
            tmpBD_.setName(dia.getResultName());
            mdlRoot_.add(tmpBD_);
            bdTreeViewer.rebuild();
            bdTreeViewer.expandToLevel(tmpBD_, TreeViewer.ALL_LEVELS);
            stateChanged();
        }
    }

    private void deleteBD_Selected() {
        Object[] selectedMdls = getSelectedBdMdls();
        if (selectedMdls.length == 1 && selectedMdls[0] instanceof MdlBusinessObject) {
            MdlBusinessObject toDelete = (MdlBusinessObject) selectedMdls[0];
            // delete relationships
            mdlRels_.removeRelated(toDelete);
            mdlRoot_.remove(toDelete.getName());
            bdTreeViewer.rebuild();
            relArea.redraw();
            stateChanged();
        }
    }

    private void up_Selected() {
        moveBusinessData(true);
    }

    private void down_Selected() {
        moveBusinessData(false);
    }

    private void moveBusinessData(boolean up) {
        Object[] selectedMdls = getSelectedBdMdls();
        if (selectedMdls.length == 1 && selectedMdls[0] instanceof MdlBusinessObject) {
            mdlRoot_.move((MdlBusinessObject) selectedMdls[0], up);
            bdTreeViewer.rebuild();
            relArea.redraw();
            stateChanged();
        }
    }

    /**
     * The selection changed in the widget-tree. The reaction is, that an associated
     * relationship and the attribute is highlithed.
     */
    private void widgetTreeSelectionChanged(SelectionChangedEvent event) {
        Iterator iter = ((StructuredSelection) event.getSelection()).iterator();
        if (iter.hasNext()) {
            Object widget = iter.next();
            if (widget instanceof IBDAttachable) {
                //for debugging
                debug("--> widget selected: " + ((IBDAttachable) widget).getNamInstance());

                // is there a relationship attached?
                Relationship rel = mdlRels_.find((IBDAttachable) widget);
                if (rel == null) {
                    // no attachment; deselect all
                    bdTreeViewer.setSelection(StructuredSelection.EMPTY);
                    mapGraphics_.setFocusedRelationship(null);
                } else {
                    MdlAttribute attr = rel.attribute_;
                    if (attr != null) {
                        if (mapGraphics_.getFocusedRelationship() != rel) {
                            mapGraphics_.setFocusedRelationship(rel);
                            StructuredSelection sel = new StructuredSelection(attr);
                            bdTreeViewer.setSelection(sel, true);
                        }
                    }
                }
                relArea.redraw();
                stateChanged();
            }
        }
    }

    /**
     * The selection changed in the businessData-tree. The reaction is, that an associated
     * relationshiop and the widget is highlighted.
     */
    private void bdTreeSelectionChanged(SelectionChangedEvent event) {
        int numSelected = 0;
        Iterator iter = ((StructuredSelection) event.getSelection()).iterator();
        while (iter.hasNext()) {
            iter.next();
            numSelected++;
        }
        if (numSelected == 1) {
            iter = ((StructuredSelection) event.getSelection()).iterator();
            if (iter.hasNext()) {
                Object attribute = iter.next();
                if (attribute instanceof MdlAttribute) {
                    // for debugging
                    debug("---> attribute selected: " + ((MdlAttribute) attribute).getNamInstance());

                    // is there a relationship attached?
                    Relationship rel = null;

                    // fixe for mantis bug 18593
                    rel = getInvolvedRS((MdlAttribute) attribute);
                    if (rel != null) {
                        if (mapGraphics_.getFocusedRelationship() != rel) {
                            mapGraphics_.setFocusedRelationship(rel);
                            StructuredSelection sel = new StructuredSelection(rel.bdAttachable_);
                            widgetTreeViewer.setSelection(sel, true);
                        }
                    } else {
                        // no attachment; deselect all
                        widgetTreeViewer.setSelection(StructuredSelection.EMPTY);
                        mapGraphics_.setFocusedRelationship(null);
                    }
                    relArea.redraw();
                    stateChanged();
                }
            }
        }
    }

    /**
     * check if the selection stems from a widget selection and
     * assures that the right relationsship is retuned
     * @param attribute
     * @return
     * @author s1462
     */
    private Relationship getInvolvedRS(MdlAttribute attribute) {
        Iterator relIter = mdlRels_.find(attribute).iterator();
        Relationship nextRel = null;
        IBDAttachable actWidget = null;

        // fixe for mantis bug 18593
        TreeSelection actWidgetSel = (TreeSelection) widgetTreeViewer.getSelection();
        if (actWidgetSel.getFirstElement() instanceof IBDAttachable) {
            actWidget = (IBDAttachable) actWidgetSel.getFirstElement();
        }

        while (relIter.hasNext()) {
            nextRel = (Relationship) relIter.next();
            if (nextRel.bdAttachable_.equals(actWidget)) {
                break;
            }
        }
        return nextRel;
    }

    /**
     * @see at.spardat.xma.gui.mapper.BDInstanceSelectionDialog.Validator#validateResult(java.lang.String, java.lang.String)
     */
    public String validateResult(BDInstanceSelectionDialog dialog, String name, String type) {
        String error = validateState(dialog, name, type);
        if (error != null)
            return error;
        // load an MdlBusinessObject
        IInfoChannel iChannel = new MessageBoxChannel(getShell());
        tmpBD_ = new BOLoadHandler(jp_).loadBusinessObject(type, iChannel);
        if (!tmpBD_.isLoaded())
            return "Could not load BusinessData " + type;
        return null;
    }

    /**
     * @see at.spardat.xma.gui.mapper.BDInstanceSelectionDialog.Validator#validateState(java.lang.String, java.lang.String)
     */
    public String validateState(BDInstanceSelectionDialog dialog, String name, String type) {
        if (name.length() == 0)
            return "Name cannot be empty.";
        if (type.length() == 0)
            return "Type cannot be empty.";
        try {
            if (jp_.findType(type) == null)
                return "Type does not exist in current project.";
        } catch (Exception ex) {
            return "Type does not exist in current project.";
        }
        // name must not be duplicate
        // and must not be in the generated BD coll
        if (dialog.getMode() == BDInstanceSelectionDialog.MODE_NEW) {
            if (mdlRoot_.getBusinessData(name) != null)
                return "Name does already exist.";
            if (mdlConverter_.getGeneratedBD() != null && mdlConverter_.getGeneratedBD().containsKey(name))
                return "Name does already exist in the generated BusinessData!";
        } else {
            throw new RuntimeException("todo");
        }
        return null;
    }

    /**
     * Returns the widget selected in the widget tree or <tt>null</tt>, if nothing is selected.
     */
    private Object getSelectedWidget() {
        ISelection sel = widgetTreeViewer.getSelection();
        if (!sel.isEmpty() && sel instanceof IStructuredSelection) {
            IStructuredSelection sSel = (IStructuredSelection) sel;
            return sSel.getFirstElement();
        }
        return null;
    }

    /**
     * Returns the Mdl???-objects selected in the BDTree as array.
     */

    private Object[] getSelectedBdMdls() {
        ISelection sel = bdTreeViewer.getSelection();
        if (!sel.isEmpty() && sel instanceof IStructuredSelection) {
            IStructuredSelection sSel = (IStructuredSelection) sel;
            return sSel.toArray();
        }
        return new Object[0];
    }

    /**
     * Extension of <tt>TreeViewer</tt> to better support mapping from SWT tree items
     * to objects.
     *
     * TODO Prio 1: when upgrading to a new eclipse version change this thru an
     * own implementation derived from abstracttreeviewer
     *
     * @author YSD, 13.07.2003 20:27:39
     */
    private static class MyTreeViewer extends TreeViewer {
        public MyTreeViewer(Tree tree) {
            super(tree);
            setUseHashlookup(true);
        }

        /**
         * Maps a domain object to the corresponding SWT TreeItem.
         *
         * @return <tt>null</tt> if mapping not possible.
         */
        public TreeItem object2item(Object o) {
            Widget w = findItem(o);
            if (w == null || !(w instanceof TreeItem))
                return null;
            return (TreeItem) w;
        }

        /**
         * Maps a SWT TreeItem to the corresponding domain object.
         *
         * @return <tt>null</tt> if mapping not possible.
         */
        public Object item2object(TreeItem ti) {
            return ti.getData();
        }

        /**
         * Workaround; refresh does not always work; the observed problem was
         * that drop in the bdTreeViewer yielded the wrong object after
         * a subtree has been moved.
         */
        public void rebuild() {
            refresh();
        }
    }

    /**
     * Listener for the drag source.
     *
     * @author YSD, 26.06.2003 21:43:41
     */
    private class WidgetTreeDragSource implements DragSourceListener {

        public void dragStart(DragSourceEvent event) {
            Object sel = getSelectedWidget();
            if (sel == null || !(sel instanceof IBDAttachable)) {
                event.doit = false;
            } else {
                leftDragObject_ = (IBDAttachable) sel;
                event.doit = true;
                lastRightDropItem_ = null;
                //bdTreeViewer.setSelection (StructuredSelection.EMPTY);  // todo check if it works
            }
        };

        public void dragSetData(DragSourceEvent event) {
            event.data = "widgetTreeDS"; // unknown if used
        }

        public void dragFinished(DragSourceEvent event) {
            leftDragObject_ = null;
        }
    }

    /**
     * Listener that supports the drop on the right tree.
     *
     * @author YSD, 26.06.2003 22:00:17
     */
    private class BDTreeDropTarget extends DropTargetAdapter {

        public void dragOver(DropTargetEvent event) {
            event.feedback = DND.FEEDBACK_EXPAND | DND.FEEDBACK_SCROLL | DND.FEEDBACK_SELECT;
            if (isValidBDDropTarget(event.item)) {
                event.detail = DND.DROP_LINK;
                lastRightDropItem_ = (TreeItem) event.item;
            } else {
                event.detail = DND.DROP_NONE;
                lastRightDropItem_ = null;
            }
        }

        public void drop(DropTargetEvent event) {
            //print ("drop", event);
            //Widget          item = event.item;

            /**
             * workaround: the instance event.item cannot be trusted; it is wrong at the moment
             * after the bdTreeViewer is refreshed;
             */
            Widget item = lastRightDropItem_;

            if (!"widgetTreeDS".equals(event.data) || !isValidBDDropTarget(item)) {
                event.detail = DND.DROP_NONE;
                return;
            } else {
                // do the drop operation
                MdlAttribute bdAttr = (MdlAttribute) bdTreeViewer.item2object((TreeItem) item);
                mdlRels_.add(mdlRels_.new Relationship(leftDragObject_, bdAttr));
                relArea.redraw();
            }
        }
    }

    /**
     * Helper method that returns true if the drop target is valid.
     */
    private boolean isValidBDDropTarget(Widget item) {
        if (leftDragObject_ == null || item == null || !(item instanceof TreeItem))
            return false;
        Object bdObj = bdTreeViewer.item2object((TreeItem) item);
        if (bdObj == null)
            return false;
        if (!(bdObj instanceof MdlAttribute))
            return false;
        return mdlRels_.mayRelate(leftDragObject_, (MdlAttribute) bdObj);
    }

    private void print(String text, DropTargetEvent e) {
        debug(text + ", data: " + e.data + ", item: " + e.item);
    }

    /**
     * @see at.spardat.xma.gui.mapper.TreeMapGraphics.ITreeMapGraphicsChannel#event(int, org.eclipse.swt.events.TypedEvent, at.spardat.xma.gui.mapper.TreeMapGraphics.IRelationship)
     */
    public void event(int type, TypedEvent ev, IRelationship selected) {
        if (type == TreeMapGraphics.ITreeMapGraphicsChannel.ET_MOUSE_MOVED)
            stateChanged();
        if (selected != null && type == ET_KEY_PRESSED) {
            KeyEvent kev = (KeyEvent) ev;
            if (kev.keyCode == SWT.DEL || kev.character == 'd') {
                MdlRelationships.Relationship rel = (MdlRelationships.Relationship) selected;
                mdlRels_.removeRelated(rel.bdAttachable_);
                relArea.redraw();
                stateChanged();
            }
        }

    }

    /**
     * Converts all relationships contained in <tt>mdlRels_</tt> to Relationship objects needed
     * by the <tt>TreeMapGraphics</tt> object.
     *
     * @see at.spardat.xma.gui.mapper.TreeMapGraphics.ITreeMapGraphicsChannel#getRelationships()
     */
    public Collection getRelationships() {
        Collection rels = mdlRels_.relationships();
        ArrayList toReturn = new ArrayList();
        Iterator iter = rels.iterator();
        while (iter.hasNext()) {
            MdlRelationships.Relationship el = (MdlRelationships.Relationship) iter.next();
            if (!el.isDangling()) {
                TreeItem left = widgetTreeViewer.object2item(el.bdAttachable_);
                TreeItem right = bdTreeViewer.object2item(el.attribute_);
                if (left != null) {
                    if (right == null) {
                        //                        //on delete and new BDObjects in the BDTree all collapsed
                        //                        //attributes are removed from tree
                        //                        //remember this event for debugging
                        debug("---> Element has no bd.attribute: " + el);
                        //                        continue;
                    }
                    el.leftItem_ = left;
                    el.rightItem_ = right;
                    toReturn.add(el);
                }
            }
        }
        return toReturn;
    }

    /**
     * Responsible for graying and informing
     */
    private void stateChanged() {
        if (mapGraphics_.getFocusedRelationship() != null) {
            setMessage("Hit <del> or <d> to delete this relationship.", IMessageProvider.INFORMATION);
        } else {
            setMessage(DEFAULT_MESSAGE);
        }
        // gray delete button
        Object[] selectedMdls = getSelectedBdMdls();
        boolean oneBDSelected = selectedMdls.length == 1 && selectedMdls[0] instanceof MdlBusinessObject;
        bdDeleteW.setEnabled(oneBDSelected);
        int indexOfBD = -1;
        if (selectedMdls.length > 0 && oneBDSelected) {
            indexOfBD = mdlRoot_.indexOf((MdlBusinessObject) selectedMdls[0]);
        }
        upW.setEnabled(oneBDSelected && mdlRoot_.size() > 1 && indexOfBD >= 1);
        downW.setEnabled(oneBDSelected && mdlRoot_.size() > 1 && indexOfBD <= mdlRoot_.size() - 2);
    }

    /**
     * Implementation of <tt>IInfoChannel</tt> that shows exceptions in message boxes and writes
     * the stack trace to standard error.
     *
     * @author YSD, 14.07.2003 01:03:39
     */
    private static class MessageBoxChannel implements IInfoChannel {

        private Shell parent_;

        public MessageBoxChannel(Shell parent) {
            parent_ = parent;
        }

        /**
         * @see at.spardat.xma.gui.mapper.IInfoChannel#exception(java.lang.Exception, java.lang.String)
         */
        public boolean exception(Throwable ex, String explainingText) {
            StringBuffer b = new StringBuffer();
            if (explainingText != null) {
                b.append(explainingText);
            }
            if (ex != null) {
                b.append("\n");
                appendStacktraceOf(ex, b);
            }
            // put the exception in the error log
            // more than on extension is defined log error
            IStatus status = new Status(IStatus.ERROR, MapperPlugin.PLUGINID, -1, explainingText, ex);
            MapperPlugin.getDefault().getLog().log(status);

            /**
             * construct MessageBox and show
             */
            MessageBox mb = new MessageBox(parent_, SWT.ICON_ERROR | SWT.OK);
            mb.setText("Error");
            mb.setMessage(b.toString());
            int ret = mb.open();

            return (ret == SWT.OK);
        }
    }

    /**
     * Appends the result of <tt>throwable.printStackTrace</tt> to the
     * provided StringBuffer. Lines are separated with '\n'.
     *
     * @param throwable the Throwable whose stack trace is to be appended.
     * @param b the StringBuffer where to append to.
     */
    private static void appendStacktraceOf(Throwable throwable, StringBuffer b) {
        String[] lines = stackTraceLinesOf(throwable);
        for (int i = 0; i < lines.length; i++) {
            b.append(lines[i]);
            b.append('\n');
        }
    }

    /**
     * Calls <tt>printStackTrace</tt> on the provided <tt>Throwable</tt>,
     * extracts the lines and returns an String array of lines.
     */
    private static String[] stackTraceLinesOf(Throwable th) {
        ArrayList lines = new ArrayList();
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        th.printStackTrace(pw);
        pw.close();
        String stackTrace = sw.toString();
        StringTokenizer tokizer = new StringTokenizer(stackTrace, System.getProperty("line.separator"));
        while (tokizer.hasMoreTokens()) {
            lines.add(tokizer.nextToken());
        }
        String[] toReturn = new String[lines.size()];
        lines.toArray(toReturn);
        return toReturn;
    }

    /**
     * User presses close.
     *
     * @see org.eclipse.jface.dialogs.Dialog#okPressed()
     */
    protected void okPressed() {
        finish();
        super.okPressed();
    }

    private boolean finished_ = false;

    private void finish() {
        if (!finished_) {
            try {
                // suppress ui changes
                gEditor_.suspendPreViewRefresh();
                mdlConverter_.clearXMAModel();
                mdlConverter_.local2xma();
                finished_ = true;
            } catch (Exception ex) {
                ex.printStackTrace();
            } finally {
                // reenable changes
                gEditor_.resumePreViewRefresh();
            }
        }
    }

    /**
     * @see org.eclipse.jface.dialogs.Dialog#close()
     */
    public boolean close() {
        finish();
        return super.close();
    }

    /**
     * Listener for the BDTree drag source
     */
    private class BDTreeDragSource implements DragSourceListener {

        public void dragStart(DragSourceEvent event) {
            rightDragSource_ = null;
            event.doit = false;
            Object[] sel = getSelectedBdMdls();
            /**
             * Selection must consist of MdlAttribute objects
             */
            if (sel == null || sel.length == 0)
                return;
            rightDragSource_ = new MdlAttribute[sel.length];
            for (int i = 0; i < sel.length; i++) {
                if (!(sel[i] instanceof MdlAttribute)) {
                    rightDragSource_ = null;
                    return;
                }
                MdlAttribute attr = (MdlAttribute) sel[i];
                rightDragSource_[i] = attr;
            }
            event.doit = true;
        };

        public void dragSetData(DragSourceEvent event) {
            event.data = "BDTreeDS";
        }

        public void dragFinished(DragSourceEvent event) {
            rightDragSource_ = null;
        }
    }

    public static final int INSERT_ON = 0;
    public static final int INSERT_BEFORE = 1;
    public static final int INSERT_AFTER = 2;

    /**
     * Requires that ev holds a valid TreeItem in ev.item and returns
     * INSERT_BEFORE or INSERT_AFTER, if the cursor is nearer to the top or bottom.
     */
    private int getInsertionDirection(DropTargetEvent ev) {
        TreeItem ti = (TreeItem) ev.item;
        Tree tree = ti.getParent();
        Point relCoordInTree = tree.toControl(ev.x, ev.y);
        Rectangle itemRect = ti.getBounds();
        if (relCoordInTree.y < itemRect.y + itemRect.height / 2)
            return INSERT_BEFORE;
        else
            return INSERT_AFTER;
    }

    /**
     * Holds information where newly created widgets are to be inserted in the widget tree
     *
     * @author YSD, 17.07.2003 15:46:22
     */
    class InsertionPoint {
        /**
         * Control that will get new childs. Either an XMAComposite or an XMATable
         */
        public Object parent_;
        /**
         * Index, where new childs should be inserted. Only filled if parent_ is a table
         */
        public int childIndex_;
        /**
         * The child widget, where the newly created widgets should be inserted before
         * or after. Only relevant if parent_ is not a table. May be <tt>null</tt> if
         * the widgets should be inserted at the top of the composite.
         */
        public XMAWidget child_;
        /**
         * Is filled, if <tt>child_</tt> is not <tt>null</tt> and indicates whether the
         * new widgets should be inserted before (true) or after (false) <tt>child_</tt>.
         */
        public boolean before_;
        /**
         * Insertion direction, one of the INSERT_-constants. This field controls where
         * the insertion beam of the drop operation will be drawn.
         */
        public int direction_;
        /**
         * A message that should be displayed to the user that informs him what's going
         * on if he drops at a particular position.
         */
        public String message_;
    };

    private static String CHAIN_MSG = "Requires a bottom-up chain layout, i.e, every widget has a top attachment to its north neighbor. ";

    /**
     * Calculates information about where widgets must be inserted in the widget tree if
     * the end user drops item at the widget tree control.
     *
     * @return <tt>null</tt> if <tt>ev</tt> does not indicate a valid drop position.
     */
    private InsertionPoint getInsertionPoint(DropTargetEvent ev) {
        Object obj = bdTreeViewer.item2object((TreeItem) ev.item);
        InsertionPoint insP = new InsertionPoint();
        if (obj instanceof XMATableColumn) {
            XMATable parent = ((XMATableColumn) obj).getTable();
            insP.parent_ = parent;
            // search the index of the column within the table
            int i = 0, found = -1;
            for (Iterator iter = parent.getColumn().iterator(); iter.hasNext(); i++) {
                if (obj == iter.next()) {
                    found = i;
                    break;
                }
            }
            if (found == -1)
                return null;
            insP.childIndex_ = found;
            // where should the insertion line be?
            insP.direction_ = getInsertionDirection(ev);
            if (insP.direction_ == INSERT_AFTER)
                insP.childIndex_++;
            insP.message_ = "Columns are inserted at index " + insP.childIndex_ + " in the table.";
        } else if (obj instanceof XMATable) {
            insP.parent_ = obj;
            insP.childIndex_ = 0;
            insP.direction_ = INSERT_ON;
            insP.message_ = "Columns are inserted in front of all other columns.";
        } else if (obj instanceof XMAComposite) {
            /**
             * About to drop on a composite
             */
            insP.parent_ = obj;
            insP.direction_ = INSERT_ON;
            insP.child_ = null;
            // search the first child that is not a label and not a separator
            Iterator iter = ((XMAComposite) obj).getControls().iterator();
            while (iter.hasNext()) {
                Object wi = iter.next();
                if (!(wi instanceof XMALabel) && !(wi instanceof XMASeperator)) {
                    insP.child_ = (XMAWidget) wi;
                    break;
                }
            }
            if (insP.child_ != null) {
                // found a child
                insP.message_ = CHAIN_MSG + "Then, widgets are inserted before '" + getWiName(insP.child_) + "'.";
                insP.before_ = true;
            } else {
                // found no child
                insP.message_ = "Widgets are inserted starting at the top edge of the composite.";
            }
        } else if (obj instanceof XMAWidget) {
            /**
             * not a composite, but some widget is under the cursor
             */
            insP.child_ = (XMAWidget) obj;
            insP.parent_ = insP.child_.getParentcomp();
            if (insP.parent_ == null)
                return null;
            // where should the insertion line be?
            insP.direction_ = getInsertionDirection(ev);
            insP.message_ = CHAIN_MSG + "Then, widgets are inserted "
                    + (insP.direction_ == INSERT_AFTER ? "after" : "before") + " widget '" + getWiName(insP.child_)
                    + "'.";
            insP.before_ = (insP.direction_ == INSERT_BEFORE);
        } else {
            return null;
        }
        return insP;
    }

    /**
     * TODO Prio 0: implement this to change the message box to warning if a top attachment destroys the layout
     * @param w
     * @return
     * @since 3.4.1.1
     * @author s1462
     */
    private boolean hasUseableTopAttachment(XMAWidget w) {
        if (w.getFormData() != null && w.getFormData().getTopAttach() != null
                && ((w.getFormData().getTopAttach().getCodAttachSide() != null
                        && !w.getFormData().getTopAttach().getCodAttachSide().equals(AttachSideType.CENTER_LITERAL))
                        || w.getFormData().getTopAttach().getAttachElement() == null)) {
            return true;
        }
        return false;
    }

    /**
     * Returns name for a widget that is not null.
     */
    private String getWiName(XMAWidget w) {
        String s = w.getNamInstance();
        if (s == null)
            return "unnamed";
        return s;
    }

    /**
     * Drop target impl when user drops attributes to the widget tree
     *
     * @author YSD, 17.07.2003 11:34:45
     */
    private class WidgetTreeDropTarget extends DropTargetAdapter {

        public void dragOver(DropTargetEvent event) {
            if (event.item == null || !(event.item instanceof TreeItem)) {
                event.detail = DND.DROP_NONE;
                return;
            }
            if (!isValidWidgetDropTarget(event)) {
                event.detail = DND.DROP_NONE;
                return;
            }
            InsertionPoint insP = getInsertionPoint(event);
            if (insP == null) {
                event.detail = DND.DROP_NONE;
                return;
            } else {
                event.detail = DND.DROP_COPY;
                if (insP.direction_ == INSERT_BEFORE)
                    event.feedback = DND.FEEDBACK_INSERT_BEFORE;
                else if (insP.direction_ == INSERT_AFTER)
                    event.feedback = DND.FEEDBACK_INSERT_AFTER;
                else
                    event.feedback = DND.FEEDBACK_EXPAND | DND.FEEDBACK_SCROLL | DND.FEEDBACK_SELECT;
                // adjust information message
                if (insP.message_ != null) {
                    setMessage(insP.message_, IMessageProvider.INFORMATION);
                } else {
                    setMessage(DEFAULT_MESSAGE);
                }
            }
        }

        public void drop(DropTargetEvent event) {
            if (!"BDTreeDS".equals(event.data) || !isValidWidgetDropTarget(event) || rightDragSource_ == null) {
                event.detail = DND.DROP_NONE;
                return;
            } else {
                InsertionPoint insP = getInsertionPoint(event);
                if (insP == null) {
                    event.detail = DND.DROP_NONE;
                    return;
                }
                /**
                 * Start the Creation Wizard
                 */
                WidgetCreationWiz wiz = new WidgetCreationWiz(rightDragSource_, insP, mdlRels_);
                WizardDialog wd = new WizardDialog(getShell(), wiz) {
                    protected void setShellStyle(int newShellStyle) {
                        super.setShellStyle(newShellStyle | SWT.RESIZE);
                    }
                };
                wd.open();
                widgetTreeViewer.refresh();
                widgetTreeViewer.expandAll(); // important, in order to ensure that the SWT Tree is built completely
                stateChanged();
            }
        }

        /**
         * Helper method that returns true if the drop target is valid.
         */
        private boolean isValidWidgetDropTarget(DropTargetEvent ev) {
            if (rightDragSource_ == null || ev.item == null || !(ev.item instanceof TreeItem))
                return false;
            Object obj = bdTreeViewer.item2object((TreeItem) ev.item);
            if (obj == null)
                return false;
            if (obj instanceof XMALabel)
                return false;

            // no dropping on hidden widgets is allowed because they havn't any layout data
            if (obj instanceof HiddenWidget)
                return false;

            if (obj instanceof XMAComposite || obj instanceof XMAWidget || obj instanceof XMATable
                    || obj instanceof XMATableColumn)
                return true;
            return false;
        }

    }

    public TreeItem getTreeItem(Object o) {
        return bdTreeViewer.object2item(o);
    }

}