001 /* 002 Copyright (C) 2001-2003 Renaud Pawlak <renaud@aopsys.com>, 003 Laurent Martelli <laurent@aopsys.com> 004 005 This program is free software; you can redistribute it and/or modify 006 it under the terms of the GNU Lesser General Public License as 007 published by the Free Software Foundation; either version 2 of the 008 License, or (at your option) any later version. 009 010 This program is distributed in the hope that it will be useful, but 011 WITHOUT ANY WARRANTY; without even the implied warranty of 012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 Lesser General Public License for more details. 014 015 You should have received a copy of the GNU Lesser General Public 016 License along with this program; if not, write to the Free Software 017 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 018 USA */ 019 020 package org.objectweb.jac.aspects.gui; 021 022 import java.util.Arrays; 023 import java.util.Collection; 024 import java.util.Iterator; 025 import java.util.List; 026 import java.util.Map; 027 import java.util.Vector; 028 import org.apache.log4j.Logger; 029 import org.objectweb.jac.aspects.integrity.RoleWrapper; 030 import org.objectweb.jac.aspects.session.SessionAC; 031 import org.objectweb.jac.core.Collaboration; 032 import org.objectweb.jac.core.Interaction; 033 import org.objectweb.jac.core.ObjectRepository; 034 import org.objectweb.jac.core.Wrappee; 035 import org.objectweb.jac.core.Wrapping; 036 import org.objectweb.jac.core.rtti.AbstractMethodItem; 037 import org.objectweb.jac.core.rtti.ClassItem; 038 import org.objectweb.jac.core.rtti.ClassRepository; 039 import org.objectweb.jac.core.rtti.CollectionItem; 040 import org.objectweb.jac.core.rtti.FieldItem; 041 import org.objectweb.jac.core.rtti.MemberItem; 042 import org.objectweb.jac.core.rtti.MethodItem; 043 import org.objectweb.jac.core.rtti.NamingConventions; 044 import org.objectweb.jac.core.rtti.RttiAC; 045 import org.objectweb.jac.util.ExtArrays; 046 import org.objectweb.jac.util.Strings; 047 048 /** 049 * This handler manages events received from GUIs (web and swing for 050 * now). It is especially used for lists and arrays (onSelection, 051 * onView, etc ...) 052 */ 053 054 public class EventHandler implements FieldUpdate { 055 static Logger logger = Logger.getLogger("gui.events"); 056 static Logger loggerDnd = Logger.getLogger("gui.dnd"); 057 static Logger loggerAssoc = Logger.getLogger("associations"); 058 059 static EventHandler singleton = new EventHandler(); 060 061 public static EventHandler get() { 062 return singleton; 063 } 064 065 /** 066 * Upcalled when a selection occurs on a field. 067 * 068 * @param context the context 069 * @param container ??? 070 * @param selectedObject the selected object 071 * @param field ??? 072 * @param extraOption */ 073 074 public void onSelection( 075 DisplayContext context, 076 MemberItem container, 077 Object selectedObject, 078 FieldItem field, 079 Object extraOption) 080 { 081 onSelection( 082 context, 083 container, 084 selectedObject, 085 field, 086 extraOption, 087 false); 088 } 089 090 /** 091 * Upcalled when a view is asked on an object. 092 * 093 * @param context the context 094 * @param container ??? 095 * @param selectedObject the selected object 096 * @param field ??? 097 * @param extraOption */ 098 099 public void onView( 100 DisplayContext context, 101 MemberItem container, 102 Object selectedObject, 103 FieldItem field, 104 Object extraOption) 105 { 106 onSelection( 107 context, 108 container, 109 selectedObject, 110 field, 111 extraOption, 112 true); 113 } 114 115 /** 116 * Upcalled when a selection occurs on a field. Displays a view of 117 * the selected object. 118 * 119 * @param context the context 120 * @param container member (reference, collection, or method) that 121 * references the selected object (the result in case of a method) 122 * @param selectedObject the selected object 123 * @param field give focus to this field in the view of the selected object 124 * @param extraOption 125 * @param forceView when true, a window containing the selected 126 * object is opened if we could not find a place where to put the 127 * new view. 128 */ 129 public void onSelection( 130 DisplayContext context, 131 MemberItem container, 132 Object selectedObject, 133 FieldItem field, 134 Object extraOption, 135 boolean forceView) 136 { 137 logger.debug("onSelection(" 138 + (container != null ? container.getLongName() : "null") + "," 139 + Strings.hex(selectedObject) 140 + ",field="+ (field != null ? field.getLongName() : "null") 141 + ",force=" + forceView + ")"); 142 CustomizedDisplay display = context.getDisplay(); 143 ViewFactory factory = display.getFactory(); 144 CustomizedView customizedView = context.getCustomizedView(); 145 146 Collaboration.get().addAttribute(GuiAC.DISPLAY_CONTEXT, context); 147 148 // in choice view collections, nothing as to be done except a refresh 149 if (container instanceof CollectionItem) { 150 if (GuiAC.isChoiceView((CollectionItem) container) 151 && !GuiAC.isExternalChoiceView((CollectionItem) container)) { 152 display.refresh(); 153 return; 154 } 155 } 156 157 MethodItem handler = null; 158 FieldItem targetField = null; 159 if (container != null) { 160 handler = GuiAC.getSelectionHandler(container); 161 targetField = 162 (FieldItem) container.getAttribute(GuiAC.SELECTION_TARGET); 163 } 164 165 if (customizedView == null && handler == null && targetField == null) { 166 if (forceView) { 167 logger.debug("showing in dialog mode " + "(customizedView==null)"); 168 display.show(selectedObject); 169 } else { 170 logger.debug("onSelection aborted " + "(customizedView==null)"); 171 display.refresh(); 172 } 173 return; 174 } 175 176 if (handler != null) { 177 try { 178 logger.debug("invoking selectionHandler " + handler); 179 Object result = 180 handler.invokeStatic( 181 new Object[] { context, container, selectedObject }); 182 if (handler.getType() != void.class && result != null) { 183 if (handler.getType() == HandlerResult.class) { 184 handleResult(context,(HandlerResult)result); 185 } else { 186 onSelection(context, null, result, null, null); 187 } 188 } 189 } catch (Exception e) { 190 logger.error( 191 "gui: invocation of event handler " + handler 192 + " for onSelection failed with " + e); 193 e.printStackTrace(); 194 } 195 } 196 197 if (targetField != null) { 198 selectedObject = targetField.getThroughAccessor(selectedObject); 199 logger.debug("selected target -> " + selectedObject); 200 } 201 202 if (customizedView == null) 203 return; 204 CustomizedGUI customized = customizedView.getCustomizedGUI(); 205 List targets = customized.getFieldTargets(container); 206 logger.debug("targets=" + targets); 207 208 if (targets != null) { 209 Iterator it = targets.iterator(); 210 while (it.hasNext()) { 211 // the target is a panelPath= 212 Target target = (Target) it.next(); 213 logger.debug("target.path = " + target.panePath); 214 /* 215 // target.panePath must look like this <customizedId>/<paneId> 216 int index = target.panePath.indexOf("/"); 217 if (index==-1) { 218 throw new RuntimeException("Bad pane path : "+target.panePath); 219 } 220 String customizedId = target.panePath.substring(0,index); 221 String paneId = target.panePath.substring(index+1); 222 logger.debug("customized = "+customizedId); 223 */ 224 225 String paneId = target.panePath; 226 CompositeView targetView = 227 (CompositeView) customizedView.getView(paneId); 228 229 if (selectedObject != null) { 230 231 Collaboration.get().addAttribute( 232 GuiAC.SMALL_VIEW, 233 container.getAttribute(GuiAC.SMALL_TARGET_CONTAINER)); 234 try { 235 // creating and adding the new view 236 View view = 237 invalidatePane( 238 factory, 239 context, 240 targetView, 241 target.viewType, 242 target.viewParams, 243 selectedObject, 244 extraOption); 245 246 if (field != null && view != null) 247 setFocus(view, field, extraOption); 248 249 } finally { 250 Collaboration.get().removeAttribute(GuiAC.SMALL_VIEW); 251 } 252 } 253 //targetView.validate(); 254 maybeInvalidatePane(factory, context, customizedView, paneId); 255 } 256 display.refresh(); 257 } else if (forceView) { 258 if (container != null 259 && container.getAttribute(GuiAC.NEW_WINDOW) != null) { 260 display.openView(selectedObject); 261 } else { 262 display.show(selectedObject); 263 } 264 } 265 266 } 267 268 public void handleResult(DisplayContext context, HandlerResult hres) { 269 CustomizedView customizedView = context.getCustomizedView(); 270 CustomizedDisplay display = context.getDisplay(); 271 DisplayContext newContext = 272 new DisplayContext( 273 display, 274 hres.target != null 275 ? hres.target 276 : customizedView); 277 if (hres.target != null) 278 customizedView = hres.target; 279 onSelection( 280 newContext, 281 (CollectionItem) hres.container, 282 hres.object, 283 hres.field, 284 hres.extraOption); 285 } 286 287 /** 288 * Removes the content of pane when another pane's content is 289 * changed 290 * 291 * @param selectedPaneID ID of the selected pane */ 292 public void maybeInvalidatePane( 293 ViewFactory factory, 294 DisplayContext context, 295 CustomizedView customizedView, 296 String selectedPaneID) 297 { 298 CustomizedGUI customized = customizedView.getCustomizedGUI(); 299 String invalidPaneID = customized.getInvalidPane(selectedPaneID); 300 logger.debug("invalidPane " + selectedPaneID + " -> " + invalidPaneID); 301 if (invalidPaneID != null) { 302 invalidatePane( 303 factory, 304 context, 305 (CompositeView) customizedView.getView(invalidPaneID), 306 "Empty", 307 ExtArrays.emptyStringArray, 308 null, 309 null); 310 } 311 } 312 313 /** 314 * Gives focus to the view which is a field editor for a given field. 315 * @param top view to start searching from. All subviews of this 316 * view will be recursively inspected. 317 * @param field the field whose editor to search for 318 * @param option an option that will be passed when calling 319 * <code>onSetFocus()</code> on the FieldEditor. 320 * @see FieldEditor#onSetFocus(Object) 321 */ 322 public void setFocus(View top, FieldItem field, Object option) { 323 logger.debug("setFocus " + top + "," + field.getLongName() + "," + option); 324 if (top instanceof CompositeView) { 325 Iterator it = ((CompositeView) top).getViews().iterator(); 326 while (it.hasNext()) { 327 View view = (View) it.next(); 328 if (view instanceof TabsView) { 329 String[] categories = GuiAC.getCategories(field); 330 if (categories != null && categories.length > 0) { 331 ((TabsView) view).select(categories[0]); 332 setFocus( 333 ((CompositeView) view).getView(categories[0]), 334 field, 335 option); 336 } 337 } else { 338 setFocus(view, field, option); 339 } 340 } 341 } else if (top instanceof FieldEditor) { 342 FieldEditor editor = (FieldEditor) top; 343 if (editor.getField().equals(field)) { 344 editor.getContext().getCustomizedView().requestFocus(); 345 editor.onSetFocus(option); 346 } 347 } 348 } 349 350 /** 351 * Used only to test if a CompositeView contains the view that we 352 * are about to build. 353 */ 354 /* 355 static class DummyView { 356 String type; 357 public void setType(String type) { 358 this.type = type; 359 } 360 public String getType() { 361 return type; 362 } 363 364 Object[] parameters; 365 public void setParameters(Object[] parameters) { 366 this.parameters = parameters; 367 } 368 public Object[] getParameters() { 369 return parameters; 370 } 371 public boolean equals(Object o) { 372 return o instanceof ViewIdentity 373 && ((ViewIdentity) o).getType().equals(type) 374 && Arrays.equals(((ViewIdentity) o).getParameters(), parameters); 375 } 376 public int hashCode() { 377 return type.hashCode() ^ parameters.hashCode(); 378 } 379 380 public DummyView(String type, Object[] parameters) { 381 this.type = type; 382 this.parameters = parameters; 383 } 384 } 385 */ 386 387 /** 388 * Create a view for an object and display it if it is not already 389 * displayed. 390 * 391 * @return the new view or the old one 392 */ 393 View invalidatePane( 394 ViewFactory factory, 395 DisplayContext context, 396 CompositeView panel, 397 String viewType, 398 String[] viewParams, 399 Object selectedObject, 400 Object extraInfo) 401 { 402 logger.debug("invalidatePane("+panel+"," 403 +viewType+Arrays.asList(viewParams)+ ","+selectedObject+")"); 404 Collection comps = panel.getViews(); 405 View view = null; 406 // close and remove the currently opened view in the panel 407 Object[] parameters; 408 if (selectedObject != null) { 409 parameters = ExtArrays.add(selectedObject, viewParams); 410 } else { 411 parameters = viewParams; 412 } 413 if (!panel.containsView(viewType, parameters)) { 414 logger.debug("new view " + viewType + ", extraInfo=" + extraInfo); 415 view = 416 factory.createView( 417 "target[?]", 418 viewType, 419 parameters, 420 context); 421 if (extraInfo instanceof CollectionPosition && 422 GuiAC.hasSetNavBar( 423 context.getCustomizedView().getCustomizedGUI(), 424 ((CollectionPosition)extraInfo).getCollection())) 425 { 426 view.setParentView( 427 view = 428 factory.createView( 429 "collectionItemView", 430 "CollectionItemView", 431 new Object[] { 432 view, 433 extraInfo, 434 viewType, 435 viewParams, 436 null }, 437 context)); 438 } 439 logger.debug("new view CREATED"); 440 panel.addView(view, GuiAC.toString(selectedObject)); 441 442 } else { 443 Iterator i = comps.iterator(); 444 while (i.hasNext()) { 445 view = (View) i.next(); 446 if (view.equalsView(viewType,parameters)) { 447 return view; 448 } 449 } 450 return null; 451 } 452 453 return view; 454 } 455 456 /** 457 * Initialize an autocreated object by setting 458 */ 459 public static void initAutocreatedObject( 460 Object created, 461 Object substance, 462 FieldItem role) 463 { 464 FieldItem oppositeRole = 465 (FieldItem) role.getAttribute(RttiAC.OPPOSITE_ROLE); 466 logger.debug("oppositeRole = " + oppositeRole); 467 if (oppositeRole != null) { 468 RoleWrapper.disableRoleUpdate(oppositeRole); 469 try { 470 if (oppositeRole instanceof CollectionItem) { 471 ((CollectionItem) oppositeRole).addThroughAdder( 472 created, 473 substance); 474 } else { 475 oppositeRole.setThroughWriter(created, substance); 476 } 477 } catch (Exception e) { 478 logger.error( 479 "initAutocreatedObject(created=" + created 480 + ",substance=" + substance 481 + "role=" + role 482 + "): " + e); 483 } finally { 484 RoleWrapper.enableRoleUpdate(oppositeRole); 485 } 486 } 487 } 488 489 /** 490 * Upcalled when a tree node is selected. 491 * 492 * @param context the display context 493 * @param node the selected tree node 494 * @param forceView if true, the subtance of the node is opened in 495 * a new window 496 */ 497 public void onNodeSelection( 498 DisplayContext context, 499 AbstractNode node, 500 boolean forceView) 501 { 502 logger.debug("onNodeSelection " + node); 503 AbstractNode parentNode = (AbstractNode) node.getParent(); 504 if (parentNode != null) { 505 // recursively send the event for the parent nodes 506 onNodeSelection(context, parentNode, false); 507 } 508 if (node instanceof ObjectNode) { 509 onSelection( 510 context, 511 ((ObjectNode) node).getRelation(), 512 node.getUserObject(), 513 null, 514 null, 515 forceView); 516 } else if (node instanceof RootNode) { 517 onSelection( 518 context, 519 null, 520 node.getUserObject(), 521 null, 522 null, 523 forceView); 524 } 525 } 526 527 /** 528 * Upcalled when a direct invocation is performed on an object (no 529 * parameters will be asked by the GUI). 530 * 531 * @param context the display context 532 * @param substance the object that holds the method 533 * @param method the method to invoke 534 * @param parameters the parameters of the method 535 */ 536 public void onInvokeDirect( 537 DisplayContext context, 538 Object substance, 539 AbstractMethodItem method, 540 Object[] parameters) 541 { 542 Collaboration.get().addAttribute(GuiAC.DISPLAY_CONTEXT, context); 543 method.invoke(substance, parameters); 544 } 545 546 /** 547 * Upcalled when an invocation is performed on an object. 548 * 549 * @param context the display context 550 * @param invoke 551 * @return the thread the method was invoked in 552 * 553 * @see #onInvoke(DisplayContext,InvokeEvent,String[],Object[]) 554 * @see #onInvoke(DisplayContext,InvokeEvent,boolean,String[],Object[]) 555 */ 556 public InvokeThread onInvoke( 557 DisplayContext context, 558 InvokeEvent invoke) 559 { 560 return onInvoke(context, invoke, null, null); 561 } 562 563 /** 564 * Upcalled when an invocation is performed on an object. 565 * 566 * @param context the display context 567 * @param invoke 568 * @param attrNames the contextual attributes names to pass 569 * @param attrValues the contextual attributes values 570 * @return the thread the method was invoked in 571 * 572 * @see #onInvoke(DisplayContext,InvokeEvent) 573 * @see #onInvoke(DisplayContext,InvokeEvent,boolean,String[],Object[]) 574 */ 575 public InvokeThread onInvoke( 576 DisplayContext context, 577 InvokeEvent invoke, 578 String[] attrNames, 579 Object[] attrValues) 580 { 581 return onInvoke(context, invoke, true, attrNames, attrValues); 582 } 583 584 /** 585 * Invoke a method in the general case. Sets the necessary 586 * attributes in the context. The method is invoked in a new 587 * thread. 588 * 589 * @param context the display context 590 * @param invoke 591 * @param attrNames the contextual attributes names to pass 592 * @param attrValues the contextual attributes values 593 * @return the thread the method was invoked in 594 * 595 * @see #onInvoke(DisplayContext,InvokeEvent) 596 * @see #onInvoke(DisplayContext,InvokeEvent,String[],Object[]) 597 */ 598 public InvokeThread onInvoke( 599 DisplayContext context, 600 InvokeEvent invoke, 601 boolean askFormParameters, 602 String[] attrNames, 603 Object[] attrValues) 604 { 605 logger.debug("onInvoke(" + context + "," + invoke + ")"); 606 CustomizedDisplay display = context.getDisplay(); 607 if (attrNames == null) 608 attrNames = ExtArrays.emptyStringArray; 609 if (attrValues == null) 610 attrValues = ExtArrays.emptyStringArray; 611 Class[] parameterTypes = invoke.getMethod().getParameterTypes(); 612 int parametersLeft = parameterTypes.length; 613 Object[] parameters = invoke.getParameters(); 614 if (parameters == null) { 615 parameters = new Object[parameterTypes.length]; 616 } else if (parameters.length < parameterTypes.length) { 617 // If there are not enough parameters, 618 // we assume the first ones are missing 619 parametersLeft -= parameters.length; 620 Object[] tmp = new Object[parameterTypes.length]; 621 System.arraycopy( 622 parameters, 623 0, 624 tmp, 625 parameterTypes.length - parameters.length, 626 parameters.length); 627 parameters = tmp; 628 } 629 if (parameters.length > 0 630 && parameterTypes[0] == DisplayContext.class) { 631 parametersLeft--; 632 parameters[0] = context; 633 } 634 invoke.setParameters(parameters); 635 // Get the session id from the current context 636 Object sid = Collaboration.get().getAttribute(SessionAC.SESSION_ID); 637 if (parametersLeft == 0) { 638 logger.debug("Invoking " + invoke); 639 String[] names = new String[2 + attrNames.length]; 640 Object[] values = new Object[2 + attrNames.length]; 641 names[0] = GuiAC.DISPLAY_CONTEXT; 642 values[0] = context; 643 names[1] = SessionAC.SESSION_ID; 644 values[1] = sid; 645 System.arraycopy(attrNames, 0, names, 2, attrNames.length); 646 System.arraycopy(attrValues, 0, values, 2, attrNames.length); 647 return 648 InvokeThread.run( 649 invoke, 650 null, 651 null, 652 names, 653 values); 654 } else { 655 //new CallingBox( this, substance, method ); 656 logger.debug("Invoking " + invoke + 657 " (ask for parameters is on, " 658 + parametersLeft + " parameters left)"); 659 660 String[] names = new String[4 + attrNames.length]; 661 Object[] values = new Object[4 + attrNames.length]; 662 names[0] = GuiAC.DISPLAY_CONTEXT; 663 values[0] = context; 664 names[1] = SessionAC.SESSION_ID; 665 values[1] = sid; 666 names[2] = GuiAC.ASK_FOR_PARAMETERS; 667 names[3] = GuiAC.INVOKED_METHOD; 668 // Do not ask for parameters if all values are not null 669 if (ExtArrays.indexOf(parameters, null) != -1 && askFormParameters) { 670 values[2] = invoke.getMethod().getConcreteMethod(); 671 values[3] = invoke.getMethod(); 672 } 673 674 System.arraycopy(attrNames, 0, names, 4, attrNames.length); 675 System.arraycopy(attrValues, 0, values, 4, attrNames.length); 676 return 677 InvokeThread.run( 678 invoke, 679 null, 680 null, 681 names, 682 values); 683 } 684 } 685 686 /** 687 * Invoke a method and waits for the result (and returns it). 688 * 689 * @param context the display context 690 * @param substance the object that holds the method 691 * @param method the method to invoke 692 * @param parameters the method's parameters */ 693 694 public Object onInvokeSynchronous( 695 DisplayContext context, 696 InvokeEvent invoke) 697 { 698 logger.debug("onInvokeSynchronous(" + context + "," + invoke + ")"); 699 CustomizedDisplay display = context.getDisplay(); 700 Class[] parameterTypes = invoke.getMethod().getParameterTypes(); 701 int parametersLeft = parameterTypes.length; 702 Object[] parameters = invoke.getParameters(); 703 if (parameters == null) { 704 parameters = new Object[parameterTypes.length]; 705 } else if (parameters.length < parameterTypes.length) { 706 // If there are not enough parameters, 707 // we assume the first ones are missing 708 parametersLeft -= parameters.length; 709 Object[] tmp = new Object[parameterTypes.length]; 710 System.arraycopy( 711 parameters, 712 0, 713 tmp, 714 parameterTypes.length - parameters.length, 715 parameters.length); 716 parameters = tmp; 717 } 718 if (parameters.length > 0 719 && parameterTypes[0] == DisplayContext.class) { 720 parametersLeft--; 721 parameters[0] = context; 722 } 723 724 String[] names; 725 Object[] values; 726 727 // Get the session id from the current context 728 Object sid = Collaboration.get().getAttribute(SessionAC.SESSION_ID); 729 if (parametersLeft == 0) { 730 logger.debug("Invoking " + invoke); 731 names = 732 new String[] { GuiAC.DISPLAY_CONTEXT, SessionAC.SESSION_ID }; 733 values = new Object[] { context, sid }; 734 } else { 735 //new CallingBox( this, substance, method ); 736 logger.debug("Invoking " + invoke 737 + " (ask for parameters is on, " 738 + parametersLeft + " parameters left)"); 739 names = 740 new String[] { 741 GuiAC.DISPLAY_CONTEXT, 742 SessionAC.SESSION_ID, 743 GuiAC.ASK_FOR_PARAMETERS }; 744 values = new Object[] { context, sid, invoke.getMethod() }; 745 } 746 747 invoke.setParameters(parameters); 748 InvokeThread thread = 749 new InvokeThread( 750 invoke, 751 null, 752 null, 753 names, 754 values); 755 thread.start(); 756 return thread.getReturnValue(); 757 } 758 759 /** 760 * This method is upcalled when an object is added to a collection. 761 * 762 * @param context the display context 763 * @param substance the object that holds the collection 764 * @param collection the collection 765 */ 766 public void onAddToCollection( 767 DisplayContext context, 768 AddEvent add) 769 { 770 onAddToCollection(context, add, false); 771 } 772 773 /** 774 * This method is upcalled when an object is added to a collection. 775 * 776 * @param context the display context 777 * @param substance the object that holds the collection 778 * @param collection the collection 779 * @param noAutoCreate if true, does not auto create the object to 780 * add, whatever the configuration for the collection. 781 */ 782 public void onAddToCollection( 783 DisplayContext context, 784 AddEvent add, 785 boolean noAutoCreate) 786 { 787 logger.debug("onAddToCollection "+add 788 + "; noAutoCreate=" + noAutoCreate); 789 CollectionItem collection = add.getCollection(); 790 MethodItem addMethod = collection.getAdder(); 791 Collaboration collab = Collaboration.get(); 792 FieldItem oppositeRole = 793 (FieldItem) collection.getAttribute(RttiAC.OPPOSITE_ROLE); 794 loggerAssoc.debug("opposite_role = " + oppositeRole); 795 if (oppositeRole instanceof CollectionItem) { 796 loggerAssoc.debug("Ignoring collection oppositeRole " + oppositeRole); 797 oppositeRole = null; 798 } 799 800 try { 801 if (addMethod != null) { 802 logger.debug("Invoking add method " + addMethod.getName() 803 + " on collection owner"); 804 805 if (noAutoCreate) { 806 ClassItem type = 807 ClassRepository.get().getClass( 808 addMethod.getParameterTypes()[0]); 809 onInvoke( 810 context, 811 new InvokeEvent( 812 add.getSource(), 813 add.getSubstance(), 814 addMethod), 815 new String[] { GuiAC.NO_AUTO_CREATE, GuiAC.VIEW }, 816 new Object[] { type, this }); 817 } else { 818 onInvoke( 819 context, 820 new InvokeEvent( 821 add.getSource(), 822 add.getSubstance(), 823 addMethod), 824 new String[] { GuiAC.VIEW, GuiAC.OPPOSITE_ROLE }, 825 new Object[] { this, oppositeRole }); 826 } 827 } else { 828 logger.debug("No adder for " + collection); 829 context.getDisplay().refresh(); 830 /* 831 getMethod = collection.getGetter(); 832 if (getMethod!=null) 833 MethodItem method = null; 834 Object c; 835 try { 836 c = getMethod.invoke(substance,ExtArrays.emptyObjectArray); 837 } catch (Exception e) { 838 logger.error("Getting collection with "+getMethod.getName()+ 839 "failed : "+e); 840 return; 841 } 842 ClassItem cl = ClassRepository.get().getClass(c.getClass()); 843 if (collection.isMap()) 844 method = cl.getMethod("put(Object,Object)"); 845 else 846 method = cl.getMethod("add(Object)"); 847 Log.trace("gui","Invoking "+method.getName()+" on collection itself"); 848 GuiAC.invoke((Display)parent,method,c,collection); 849 } 850 */ 851 } 852 } finally { 853 collab.removeAttribute(GuiAC.OPPOSITE_ROLE); 854 } 855 } 856 857 /** 858 * This method is upcalled when an object is removed from a collection. 859 * 860 * @param context the display context 861 * @param remove 862 * @param askFormParameters wether to to display an input box for 863 * the parameters of the remover method 864 */ 865 public void onRemoveFromCollection( 866 DisplayContext context, 867 RemoveEvent remove, 868 boolean askFormParameters) 869 { 870 CollectionItem collection = remove.getCollection(); 871 Object selected = remove.getRemoved(); 872 MethodItem remover = collection.getRemover(); 873 if (remover != null) { 874 logger.debug("Invoking remove method " 875 + remover.getName() 876 + " on collection owner"); 877 878 if (collection.isMap() && selected instanceof Map.Entry) { 879 // We don't want to call the remover with an entry as the 880 // parameter 881 selected = ((Map.Entry) selected).getKey(); 882 } 883 884 try { 885 if (selected != null) 886 onInvoke( 887 context, 888 new InvokeEvent( 889 remove.getSource(), 890 remove.getSubstance(), 891 remover, 892 new Object[] {selected}), 893 false, 894 ExtArrays.emptyStringArray, 895 ExtArrays.emptyObjectArray); 896 else 897 onInvoke( 898 context, 899 new InvokeEvent( 900 remove.getSource(), 901 remove.getSubstance(), 902 remover, 903 new Object[] {selected}), 904 askFormParameters, 905 ExtArrays.emptyStringArray, 906 ExtArrays.emptyObjectArray); 907 908 /** 909 * Close all views where the removed element is displayed 910 */ 911 CustomizedView customizedView = context.getCustomizedView(); 912 if (customizedView != null) { 913 CustomizedGUI customized = 914 customizedView.getCustomizedGUI(); 915 List targets = customized.getFieldTargets(collection); 916 917 if (targets != null) { 918 Iterator it = targets.iterator(); 919 while (it.hasNext()) { 920 Target target = (Target) it.next(); 921 CompositeView targetView = 922 (CompositeView) customizedView.getView( 923 target.panePath); 924 if (targetView == null) 925 continue; 926 927 Object[] parameters = new Object[] {selected}; 928 Iterator it2 = targetView.getViews().iterator(); 929 while (it2.hasNext()) { 930 View view = (View) it2.next(); 931 932 View view2 = null; 933 if (view 934 instanceof AbstractCollectionItemView) { 935 view2 = view; 936 view = 937 ((AbstractCollectionItemView) view) 938 .getView(); 939 } 940 941 if (view.equalsView(view.getType(),parameters)) { 942 if (view2 != null) { 943 view.close(true); 944 view = view2; 945 } 946 ((CompositeView)view.getParentView()) 947 .removeView(view,true); 948 // Should removeView() do the close() ??? 949 view.close(true); 950 951 it2 = targetView.getViews().iterator(); 952 } 953 } 954 } 955 } 956 } 957 } catch (Exception e) { 958 logger.error( 959 "failed to remove " 960 + ((selected != null) ? selected : "element") 961 + " from collection"); 962 e.printStackTrace(); 963 } 964 } else { 965 context.getDisplay().showError( 966 "Cannot Remove", 967 "No remover method available for collection " + collection); 968 // TODO: handling of arrays 969 } 970 } 971 972 /** 973 * This method is upcalled when an object has to be created in an 974 * object chooser. 975 * 976 * @param context the display context 977 * @param cli the class of the object to create 978 * @param substance 979 * @param field a field to which the created object will be "added". May be null. 980 */ 981 public Object onCreateObject( 982 DisplayContext context, 983 ClassItem cli, 984 Object substance, 985 FieldItem field) 986 { 987 logger.debug("onCreateObject(" + cli.getName() + "," + field + ")"); 988 989 Vector classes = new Vector(cli.getChildren()); 990 classes.add(cli); 991 992 Object newInstance = null; 993 try { 994 995 Collaboration collab = Collaboration.get(); 996 997 Object fieldChoice = field!=null ? field.getAttribute(GuiAC.FIELD_CHOICE) : null; 998 if (fieldChoice instanceof CollectionItem) { 999 CollectionItem choice = (CollectionItem)fieldChoice; 1000 collab.addAttribute(GuiAC.AUTOCREATE_REASON, 1001 new Interaction(null, 1002 (Wrappee)choice.getSubstance(substance), 1003 choice.getAdder(),new Object[1])); 1004 try { 1005 newInstance = cli.newInstance(); 1006 } finally { 1007 collab.removeAttribute(GuiAC.AUTOCREATE_REASON); 1008 } 1009 onInvokeDirect( 1010 context, 1011 choice.getSubstance(substance), 1012 choice.getAdder(), 1013 new Object[] {newInstance}); 1014 } else { 1015 newInstance = cli.newInstance(); 1016 } 1017 1018 if (substance != null && field != null) { 1019 MethodItem init = GuiAC.getInitiliazer(field); 1020 if (init != null) { 1021 init.invoke(substance, new Object[] { newInstance }); 1022 } 1023 } 1024 1025 FieldItem oppositeRole = setOppositeRole(field); 1026 //collab.addAttribute(GuiAC.EMBEDDED_EDITORS, Boolean.TRUE); 1027 collab.addAttribute(GuiAC.AUTO_CREATION, Boolean.TRUE); 1028 try { 1029 boolean ok = 1030 context.getDisplay().showModal( 1031 newInstance, 1032 "Object", 1033 new String[] {GuiAC.AUTOCREATE_VIEW}, 1034 "New " + NamingConventions.getShortClassName(cli), 1035 "Fill the needed information and validate.", 1036 context.getWindow(), 1037 true, 1038 true, 1039 false); 1040 1041 if (!ok) { 1042 logger.debug("Creation of " + cli.getName() + " cancelled"); 1043 ObjectRepository.delete((Wrappee) newInstance); 1044 newInstance = null; 1045 } 1046 } finally { 1047 if (oppositeRole != null) 1048 collab.removeAttribute(GuiAC.OPPOSITE_ROLE); 1049 //collab.removeAttribute(GuiAC.EMBEDDED_EDITORS); 1050 collab.removeAttribute(GuiAC.AUTO_CREATION); 1051 } 1052 } catch (Exception e) { 1053 logger.error("onCreateObject("+cli.getName()+","+ 1054 substance+","+field+") failed",e); 1055 } 1056 return newInstance; 1057 } 1058 1059 public void onDropObject( 1060 DisplayContext context, 1061 Object target, 1062 Object droppedObject, 1063 Object source, 1064 boolean copy) 1065 { 1066 logger.debug("onDropObject(" + target + "," + droppedObject + ")"); 1067 ClassItem cli = ClassRepository.get().getClass(target); 1068 Class objectType = droppedObject.getClass(); 1069 CollectionItem[] cols = cli.getCollections(); 1070 for (int i = 0; i < cols.length; i++) { 1071 CollectionItem c = cols[i]; 1072 loggerDnd.debug("checking collection " + c); 1073 MethodItem adder = c.getAdder(); 1074 if (adder != null) { 1075 loggerDnd.debug("types(" + adder.getParameterTypes()[0] + "," + objectType + ")"); 1076 if (adder.getParameterTypes()[0] == objectType) { 1077 if (!copy && GuiAC.isRemovable(c) && GuiAC.isAddable(c)) { 1078 loggerDnd.debug("moving object..."); 1079 c.removeThroughRemover(source, droppedObject); 1080 c.addThroughAdder(target, droppedObject); 1081 } else if ( 1082 copy && GuiAC.isRemovable(c) && GuiAC.isAddable(c)) { 1083 loggerDnd.debug("copying object..."); 1084 Wrapping.clone(droppedObject); 1085 c.addThroughAdder(target, droppedObject); 1086 } 1087 } 1088 } 1089 } 1090 } 1091 1092 public void fieldUpdated( 1093 Object substance, 1094 FieldItem field, 1095 Object value, 1096 Object param) 1097 { 1098 CompositeView view = (CompositeView) param; 1099 logger.debug("rebuilding view " + view); 1100 view.removeAllViews(false); 1101 GenericFactory.fillObjectView( 1102 view, 1103 ClassRepository.get().getClass(substance), 1104 "default", 1105 substance); 1106 } 1107 1108 public static FieldItem setOppositeRole(FieldItem field) { 1109 if (field!=null) { 1110 FieldItem oppositeRole = 1111 (FieldItem)field.getAttribute(RttiAC.OPPOSITE_ROLE); 1112 if (oppositeRole instanceof CollectionItem) { 1113 loggerAssoc.debug("Ignoring collection oppositeRole of "+ 1114 field.getLongName() + ": "+oppositeRole); 1115 return null; 1116 } else { 1117 loggerAssoc.debug("opposite_role of "+field.getLongName()+" = " + oppositeRole); 1118 Collaboration.get().addAttribute(GuiAC.OPPOSITE_ROLE, oppositeRole); 1119 return oppositeRole; 1120 } 1121 } else { 1122 return null; 1123 } 1124 } 1125 }