Java tutorial
/******************************************************************************* * 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); } }