1 /**
  2  * Copyright 2008-Present actioncenters.org
  3  *
  4  * This file is part of actioncenters.org.
  5  *
  6  * Actioncenters.org is free software: you can redistribute it and/or modify
  7  * it under the terms of the BSD License found in the LICENSE.txt file.
  8 */
  9 
 10 /** @fileOverview Provides PSS utility functions. */
 11 
 12 /*global Ext, dojox, AC, actionCenterAPI */
 13 
 14 Ext.namespace('AC.pss');
 15 
 16 /**
 17  * Default constructor.
 18  *
 19  * @class The empty/root renderer.  This is the object that is responsible for rendering a component.
 20  * @param componentConfiguration
 21  *          the component configuration
 22  */
 23 AC.pss.EmptyRenderer = function (componentConfiguration) {
 24     this.componentConfiguration = componentConfiguration;
 25     if (this.componentConfiguration.getPropertyValue("openMultiple") !== null) {
 26          this.multiInstanceComponent = (this.componentConfiguration.getPropertyValue("openMultiple") === 'Y');
 27     } else {
 28          this.multiInstanceComponent = true;
 29     }
 30     this.reloading = false;
 31 
 32     /**
 33      * Gets the component configuration.
 34      *
 35      * @return the component configuration.
 36      */
 37     this.getComponentConfiguration = function () {
 38         return this.componentConfiguration;
 39     };
 40 
 41     /**
 42      * Handles user's 'send' action.
 43      *
 44      * @return void
 45      */
 46     this.onSend = function () {
 47         // do nothing here
 48     };
 49 }
 50 
 51 /**
 52  * @class Component renderer.  This class is responsible for rendering a component.
 53  * @extends AC.pss.EmptyRenderer
 54  */
 55 AC.pss.ComponentRenderer = Ext.extend(AC.pss.EmptyRenderer,
 56 /** @lends AC.pss.ComponentRenderer */
 57 {
 58     /**
 59      * Default constructor.
 60      *
 61      * @param componentConfiguration
 62      *          the component configuration
 63      */
 64     constructor: function (componentConfiguration) {
 65         AC.pss.ComponentRenderer.superclass.constructor.call(this, componentConfiguration);
 66 
 67         /**
 68          * Handles user's 'send' action. If this component is configured to swap, this handler will invoke a swap.
 69          *
 70          * @return void
 71          */
 72         this.onSend = function () {
 73             if ("Y" === this.getComponentConfiguration().getPropertyValue('swapperMode')) {
 74                 this.swap();
 75                 var container = this.subcomponentInstance.findByItemId('subcomponentContainer');
 76                 if (container) {
 77                     container.fireEvent('swap');
 78                 }
 79             }
 80         };
 81     },
 82 
 83     /**
 84      * Destroys this component.
 85      *
 86      * @param superiorContributionId
 87      *          the superior contribution id
 88      * @param launchPoint
 89      *          the launch point
 90      * @return void
 91      */
 92     destroyComponent: function (superiorContributionId, launchPoint) {
 93         if (this.subcomponentInstance) {
 94             this.subcomponentInstance.close();
 95             this.subcomponentInstance = null;
 96         }
 97         if (this.subscription) {
 98             dojox.cometd.unsubscribe(this.subscription);
 99             this.subscription = null;
100         }
101     },
102 
103     /**
104      * Renders this component.
105      *
106      * @param superiorContributionId
107      *          the superior contribution id
108      * @param launchPoint
109      *          The object that triggered or invoked the rendering of this component.  There are times where it is necessary
110      *          for a component to know information about where it was invoked from.  This is accomplished by calling back to a
111      *          method on the launchPoint.
112      * @return void
113      */
114     renderComponent: function (superiorContributionId, launchPoint) {
115         this.windowId = superiorContributionId + launchPoint.id + this.getComponentConfiguration().getId();
116         this.superiorContributionId = superiorContributionId;
117         if (!this.multiInstanceComponent && this.subcomponentInstance) {
118             //this.destroyComponent();
119             this.reloading = true;
120             this.superiorRootContributionId = null;
121         } else if (Ext.WindowMgr.get(this.windowId)) {
122             Ext.WindowMgr.bringToFront(this.windowId);
123             //return;
124         }
125         this.launchPoint = launchPoint;
126         if ("Y" === this.getComponentConfiguration().getPropertyValue('swapperMode')) {
127             this.swap();
128         } else {
129             this.renderIt();
130         }
131     },
132 
133     /**
134      * Swaps the superior contribution for this component.  This will cause the component to reload itself with a new superior contribution.
135      *
136      * @return void
137      */
138     swap : function () {
139         if (this.beforeSwap) {
140             this.beforeSwap();
141         }
142         if (this.subcomponentInstance) {
143             //this.destroyComponent();
144             if (this.subscription) {
145                 dojox.cometd.unsubscribe(this.subscription);
146                 this.subscription = null;
147             }
148             this.reloading = true;
149         }
150 
151         if (!this.superiorRootContributionId && this.launchPoint && this.launchPoint.getRootContributionId) {
152             this.superiorRootContributionId = this.launchPoint.getRootContributionId();
153         }
154         if (this.superiorRootContributionId) {
155             actionCenterAPI.getSwapperParent(this.superiorRootContributionId, this.getComponentConfiguration().getId(),
156                 this.superiorContributionId, this.getComponentConfiguration().getPropertyValue('subComponentId'),
157                 this, this.swapCallback);
158         } else {
159             this.renderIt();
160         }
161     },
162 
163     /**
164      * Callback function for swapping.  This function registers the component to listen on a specific swapping channel
165      * so that the server can keep track of which clients are subscribed to which superior contributions.
166      *
167      * @param msg
168      *          the message
169      * @return void
170      */
171     swapCallback : function (msg) {
172         actionCenterAPI.startBatch();
173         this.superiorContributionId = msg.data.swapperContributionId;
174         var channel = '/contributions/contribution/swapper/' + this.superiorContributionId;
175         this.subscription = dojox.cometd.subscribe(channel, this, function () {
176             // do nothing here..  this is a dummy callback method that should not get called because we don't intend to publish anything on the swapper channel
177             console.log('this should not happen');
178         });
179         actionCenterAPI.endBatch();
180 
181         // if this component has a parent and this component is configured to activate its parent
182         if (this.launchPoint && this.componentConfiguration.getParsedProperties().activeContributionMarker === 'Y') { // activate the new superior node's active contribution marker
183             this.launchPoint.root.cascade(function () {
184                 if (this.contributionId === msg.data.swapperContributionId) {
185                     this.ownerTree.selModel.activateNode(this);
186                 }
187             });
188         }
189 
190         this.renderIt();
191     },
192 
193     /**
194      * Renders this component.
195      *
196      * @return void
197      */
198     renderIt : function () {
199         if (this.reloading) {
200             var subComponent = this.subcomponentInstance.items.items[0];
201             subComponent.reload(this.superiorContributionId);
202             this.reloading = false;
203         } else {
204             AC.pss.Utility.renderIt(
205                 this.superiorContributionId,
206                 this.getComponentConfiguration().getId(),
207                 null,
208                 this, this.launchSubCompCallback,
209                 this);
210         }
211     },
212 
213     /**
214      * Callback function invoked after renderIt().  This function creates a popup window and renders the subcomponent into it.
215      *
216      * @param subComponent
217      *          the sub-component
218      * @return void
219      */
220     launchSubCompCallback : function (subComponent) {
221         var windowTitle = this.getComponentConfiguration().getPropertyValue('name');
222         if (Ext.WindowMgr.get(this.windowId)) {
223             Ext.WindowMgr.bringToFront(this.windowId);
224             return;
225         }
226         var popupHeight      = this.getComponentConfiguration().getPropertyValue('popupHeight');
227         var popupWidth       = this.getComponentConfiguration().getPropertyValue('popupWidth');
228         var browserDim = actionCenterUtility.getBrowserDimensions();
229         this.subcomponentInstance = new Ext.Window({
230             id: this.windowId,
231             itemId: 'subcomponentwindow',
232             layout: 'fit',
233             items: [subComponent],
234             title: windowTitle,
235             height: browserDim.height * parseInt(popupHeight, 10) / 100,
236             width:  browserDim.width  * parseInt(popupWidth,  10) / 100,
237             minHeight: 0,
238             minWidth: 0,
239             maximizable: true,
240             constrainHeader: true,
241             launchPoint: this.launchPoint,
242             componentRenderer: this,
243             destroy: function () {
244                 if (this.launchPoint && this.launchPoint.onRenderedComponentDestroy) {
245                     this.launchPoint.onRenderedComponentDestroy();
246                 }
247                 Ext.Window.superclass.destroy.call(this);
248                 if (this.componentRenderer.subscription) {
249                     dojox.cometd.unsubscribe(this.componentRenderer.subscription);
250                     this.componentRenderer.subscription = null;
251                 }
252                 this.componentRenderer.subcomponentInstance = null;
253             }
254         }).show();
255     }
256 });
257 
258 /**
259  * Default constructor.
260  *
261  * @class Component controller.
262  * @param superiorContributionId
263  *          the superior contribution id
264  * @param componentId
265  *          the id of the component's configuration
266  * @param target
267  *          the location to render this component
268  * @param callbackObject
269  *          the callback object
270  * @param callback
271  *          the function to call back once the component is created
272  * @param renderer
273  *          the renderer that rendered this component
274  * @param subComponentRenderers
275  *          an array of subcomponent renderers
276  */
277 AC.pss.ComponentController = function (superiorContributionId, componentId, target, callbackObject, callback, renderer, subComponentRenderers) {
278     this.target = target;
279     this.superiorContribution = null;
280     this.renderer = renderer;
281     this.callback = callback;
282     this.callbackObject = callbackObject;
283     this.providedRenderers = subComponentRenderers;
284 
285     /**
286      * Initiliazes this component controller when rendering the top-level component.
287      *
288      * @param msg
289      *          the message
290      * @return void
291      */
292     this.initialize = function (msg) {
293         this.renderer = new AC.pss.EmptyRenderer(new AC.data.Contribution(msg.data.component));
294         this.superiorContribution = new AC.data.Contribution(msg.data.superiorContribution);
295         this.render();
296     };
297 
298     /**
299      * Initializes the superior contribution.
300      *
301      * @param msg
302      *          the message
303      * @return void
304      */
305     this.initSuperiorContribution = function (msg) {
306         this.superiorContribution = new AC.data.Contribution(msg.data.contribution);
307         this.render();
308     };
309 
310     /**
311      * Initializes the control.
312      *
313      * @param msg
314      *          the message
315      * @return void
316      */
317     this.initControl = function (msg) {
318         this.renderer = new AC.pss.EmptyRenderer(new AC.data.Contribution(msg.data.contribution));
319         this.render();
320     };
321 
322     /**
323      * Creates a component renderer.
324      *
325      * @param subComponentConfiguration
326      *          the sub-component configuration
327      * @return the component renderer
328      */
329     // Given a subComponentConfiguration see if there was a renderer passed in for it or create a new one
330     // if one was not passed in for it.
331     this.createRenderer = function (subComponentConfiguration) {
332         var returnValue = null;
333         if (this.providedRenderers) {
334             for (var i = 0; i < this.providedRenderers.length; i++) {
335                 var providedRenderer = this.providedRenderers[i];
336                 if (providedRenderer.getComponentConfiguration().getId() === subComponentConfiguration.id) {
337                     returnValue = providedRenderer;
338                     break;
339                 }
340             }
341         }
342         if (!returnValue) {
343             returnValue = new AC.pss.ComponentRenderer(new AC.data.Contribution(subComponentConfiguration));
344         }
345         return returnValue;
346     };
347 
348     /**
349      * Renders this component.
350      *
351      * @return void
352      */
353     this.render = function () {
354         if (!this.subComponentRenderers) {
355             this.subComponentRenderers = [];
356             if (this.renderer.getComponentConfiguration()._msg.subComponents) {
357                 for (var i = 0; i < this.renderer.getComponentConfiguration()._msg.subComponents.length; i++) {
358                     var subComponentConfiguration = this.renderer.getComponentConfiguration()._msg.subComponents[i];
359                     this.subComponentRenderers.push(this.createRenderer(subComponentConfiguration));
360                 }
361             }
362         }
363         var command = "var componentObject = new " + this.renderer.getComponentConfiguration().getPropertyValue("subType") + "(" +
364                         "this.superiorContribution, "  +
365                         "this.renderer, "              +
366                         "this.subComponentRenderers, " +
367                         "this.target);";
368         eval(command);
369 
370         if (this.callbackObject && this.callback) {
371             callback.call(this.callbackObject, componentObject.getPanel());
372         }
373     };
374 
375     if (!this.renderer) {
376         if (!superiorContributionId) {
377             // this must be a control
378             actionCenterAPI.getContribution(componentId, this, this.initControl);
379         } else {
380             // this is a top level component
381             actionCenterAPI.getComponentConfiguration(superiorContributionId, componentId, this, this.initialize);
382         }
383     } else {
384         // this is a child component
385         actionCenterAPI.getContribution(superiorContributionId, this, this.initSuperiorContribution);
386     }
387 }
388 // The necessary cleanup on unload
389 window.onbeforeunload = function (e) {
390     AC.pss.Utility.endUserScreenSubscription();
391     var windowItems = AC.pss.divViewportManager;
392     for (var i = windowItems.length - 1; i >= 0; i--) {
393         var windowItem = windowItems[i];
394         try {
395             windowItem.destroy();
396         } catch (err) {
397 //            console.log("error occurred while destroying an item");
398         }
399     }
400 };
401 
402 /**
403  * Default constructor.
404  *
405  * @class AC PSS utility
406  */
407 AC.pss.Utility = {
408     /**
409      * Starts a listener for relationships of the specified user to the specified role and activity ids.
410      *
411      * @param roleUserRelationshipId
412      *          the role user relationship id
413      * @param activityUserRelationshipId
414      *          the activity user relationship id
415      * @return void
416      */
417     startUserPageListener : function (roleUserRelationshipId, activityUserRelationshipId) {
418         actionCenterAPI.startBatch();
419         var rolechannel = "/relationships/relationship/" + roleUserRelationshipId + "/delete";
420         var activitychannel = "/relationships/relationship/" + activityUserRelationshipId + "/delete";
421         dojox.cometd.subscribe(rolechannel, AC.pss.Utility, 'refreshPage');
422         dojox.cometd.subscribe(activitychannel, AC.pss.Utility, 'refreshPage');
423         actionCenterAPI.endBatch();
424     },
425 
426     /**
427      * Callback function executed upon deletion of a user's role and activity relationships.
428      *
429      * @return void
430      */
431     refreshPage : function () {
432        AC.pss.Utility.endUserScreenSubscription();
433        location.reload(true);
434     },
435 
436     /**
437      * Starts a subscription so that the server can monitor when a user closes a window.
438      *
439      * @return void
440      */
441     startUserScreenSubscription : function () {
442         var userScreenChannel = "/service/thumbprint/" + currentScreenId + "/" + actionCenterAPI.getUserId();
443         // this subscription is only here so that the server can track when a user closes the page
444         // nothing should ever be pe published on this channel
445         AC.pss.Utility.userScreenSubscription = dojox.cometd.subscribe(userScreenChannel, AC.pss.Utility, 'doNothing');
446     },
447 
448     /**
449      * Ends a subscription so that the server can monitor when a user closes a window.
450      *
451      * @return void
452      */
453     endUserScreenSubscription : function () {
454         if (AC.pss.Utility.userScreenSubscription) {
455             dojox.cometd.unsubscribe(AC.pss.Utility.userScreenSubscription);
456         }
457         AC.pss.Utility.userScreenSubscription = null;
458     },
459 
460     /**
461      * Callback function.  This should never be called but it needs to be here so that the User Screen
462      * subscription has a dummy callback.
463      *
464      * @return void
465      */
466     doNothing : function () {
467     },
468 
469     /**
470      * Renders the specified component to the specified target location using the specified renderers.
471      *
472      * @param superiorContributionId
473      *          the superior contribution id
474      * @param componentId
475      *          the component id
476      * @param target
477      *          the rendering target
478      * @param callbackObject
479      *          the callback object
480      * @param callbackMethod
481      *          the callback method
482      * @param renderer
483      *          the component renderer
484      * @param subComponentRenderers
485      *          the sub-component renderers
486      * @return void
487      */
488     renderIt: function (superiorContributionId, componentId, target, callbackObject, callbackMethod, renderer, subComponentRenderers) {
489         var componentController = new AC.pss.ComponentController(superiorContributionId, componentId, target, callbackObject, callbackMethod, renderer, subComponentRenderers);
490     },
491 
492     /**
493      * Renders the specified tool as a button to the specified target location.
494      *
495      * @param config
496      *          the configuration of the button
497      *
498      * @return void
499      */
500     renderItAsButton: function (config) {
501         //initiate the button
502         var buttonIcon = config.icon;
503         var buttonLabel = config.buttonLabel;
504         var pssButton = new AC.pss.Button({
505             buttonIcon: buttonIcon,
506             buttonLabel: buttonLabel,
507             handler: function(){
508                 if(this.popupWindow){
509                     this.popupWindow.show();
510                 } else {
511                     var windowTitle = config.windowTitle;
512                     var popupHeight = config.popupHeight;
513                     var popupWidth  = config.popupWidth;
514                     var browserDim = actionCenterUtility.getBrowserDimensions();
515                     this.popupWindow = new AC.Window({
516                         title: windowTitle,
517                         layout: 'fit',
518                         height: browserDim.height * parseInt(popupHeight, 10) / 100,
519                         width:  browserDim.width  * parseInt(popupWidth,  10) / 100
520                     });
521                   AC.pss.Utility.renderIt(config.superiorContributionId,config.componentId,null,this,this.launchPopupWindow);
522                 }
523             },
524             launchPopupWindow: function(component){
525                 this.popupWindow.add(component);
526                 this.popupWindow.doLayout();
527                 if(this.popupWindow.hidden){
528                     this.popupWindow.show();
529                 }
530             }
531         });
532 
533         var divConfig = {
534            renderTo: config.target,
535            layout: 'fit',
536            items: [pssButton]
537         };
538         AC.pss.divViewportManager.push(new Ext.ux.DivViewport(divConfig));
539     }
540 };
541 
542 
543 //**********************************************************************************************************************
544 /**
545  * @class
546  * <p>A specialized container representing the viewable application area similar to the Ext.Viewport(the browser viewport).</p>
547  * <p>The DivViewport renders itself to the Dom element identified by the renderTo attribute, and is kept in the
548  * AC.pss.divViewportManager and resized as the browser resizes.
549  * We can have multiple DivViewports in a web page. However, each DivViewport can only contain a child item.
550  * @extends Ext.Container
551  *
552  * @constructor Default constructor that creates a new DivViewport
553  * @param {Object} config The config object
554  * @xtype divviewport
555  */
556 Ext.ux.DivViewport = Ext.extend(Ext.Container,
557 /** @lends Ext.ux.DivViewport */
558 {
559     /*
560      * Privatize config options which, if used, would interfere with the
561      * correct operation of the Viewport as the sole manager of the
562      * layout of the document body.
563      */
564     /**
565      * @cfg {Mixed} applyTo @hide
566      */
567     /**
568      * @cfg {Boolean} allowDomMove @hide
569      */
570     /**
571      * @cfg {Boolean} hideParent @hide
572      */
573     /**
574      * @cfg {Mixed} renderTo @hide
575      */
576     /**
577      * @cfg {Boolean} hideParent @hide
578      */
579     /**
580      * @cfg {Number} height @hide
581      */
582     /**
583      * @cfg {Number} width @hide
584      */
585     /**
586      * @cfg {Boolean} autoHeight @hide
587      */
588     /**
589      * @cfg {Boolean} autoWidth @hide
590      */
591     /**
592      * @cfg {Boolean} deferHeight @hide
593      */
594     /**
595      * @cfg {Boolean} monitorResize @hide
596      */
597 
598     /**
599      * Initializes this component.
600      *
601      * @return void
602      */
603     initComponent : function () {
604         Ext.ux.DivViewport.superclass.initComponent.call(this);
605         this.el = Ext.get(this.renderTo);
606         this.el.setHeight = Ext.emptyFn;
607         this.el.setWidth = Ext.emptyFn;
608         this.el.setSize = Ext.emptyFn;
609         this.el.dom.scroll = 'no';
610         this.allowDomMove = false;
611     }
612 });
613 Ext.reg('divviewport', Ext.ux.DivViewport);
614 
615 
616 //**********************************************************************************************************************
617 /**
618  * Array of DivViewports. This manager keeps track of all the DivViewports created.
619  *
620  * @default []
621  */
622 AC.pss.divViewportManager = [];
623 
624 /**
625  * Handles browser resize events.
626  *
627  * @return void
628  */
629 var fireResize = function () {
630     //a little trick,at first we have to reduce the size of the child item of the div viewport to 0
631     //so that the size of the div viewport can change according to the new size of the browser.
632     //If we don't do so, the div viewport minimum size will always be the size of its child item.
633     var i;
634     for (i = 0; i < AC.pss.divViewportManager.length; i++) {
635         AC.pss.divViewportManager[i].items.items[0].setSize(0, 0);
636     }
637     //after getting the new size, set the size of the child item to this new size.
638     for (i = 0; i < AC.pss.divViewportManager.length; i++) {
639         var w = AC.pss.divViewportManager[i].el.dom.clientWidth;
640         var h = AC.pss.divViewportManager[i].el.dom.clientHeight;
641         AC.pss.divViewportManager[i].items.items[0].setSize(w, h);
642     }
643 };
644 
645 //*********************************************** AC_Component *****************************************************************
646 //This is a generic class for all the Components in the PSS that are built based on Extjs
647 //At the moment, we just copy and paste all the code from the AC_Outliner
648 //******************************************************************************************************************************
649 
650 //****************************** Outliner Explorer Grid Node ****************************************
651 actioncenter.outlinerExplorerGridNode = function (attributes) {
652     attributes = attributes || {};
653     this.allowDropOnlyValidChildTypes = false;
654     this.dragOnlyFirstCell = true;
655     this.type = "AC_ComponentSuperior";
656     actioncenter.outlinerExplorerGridNode.superclass.constructor.call(this, attributes);
657     this.pasteProfiles = null;
658     this.fontString = '';
659     this.expanded = true;
660     var uiClass = actioncenter.outlinerExplorerGridNodeUI;
661     if (this.ui) {
662         this.ui.destroy();
663     }
664     this.ui = new uiClass(this);
665     this.triggerEventRegistry = [];//the cache to contain the trigger events for each sub component
666 };
667 
668 Ext.extend(actioncenter.outlinerExplorerGridNode, actioncenter.standardTreeGridNode,
669 /** @lends actioncenter.outlinerExplorerGridNode */
670 {
671 /**
672      * @override
673      *
674      * Invokes the sorting after finishing the initial load.
675      *
676      * @return void
677      */
678     sortAfterLoad: function () {
679         //only sort the child nodes of the nodes other than the root node
680         //The child nodes of the root are already sorted at the outliner panel level
681         var root = this.getOwnerTree().root;
682         if (this !== root){
683              actionCenterUtility.reorder(this);
684         }
685     },
686     editNode: function (msg) {
687         var lock = actionCenterJSON.getMsgProperty(msg, 'data.contribution.lockedBy');
688         this.toggleLockInfo(lock);
689         var newType = actionCenterJSON.getMsgProperty(msg, 'data.contribution.type');
690         if (this.type !== 'AC_ComponentSuperior' && this.type !== newType) {
691             this.type = newType;
692             var sm = this.getOwnerTree().getSelectionModel();
693             sm.fireEvent('anchorchange', sm.tree, sm.anchoredNode);
694             this.cascade(function() {
695                 this.setAttributes();
696                 return true;
697             });
698         }
699     },
700 
701     /**
702      * Creates a child node.
703      *
704      * @param msg
705      *          the message
706      * @return void
707      */
708     createChild: function (msg) {
709         var id = actionCenterJSON.getMsgProperty(msg, 'data.contribution.id');
710         var existingchild = this.findChild("contributionId", id);
711         var wsnode = null;
712         if (existingchild == null) {
713             var contributionType = actionCenterJSON.getMsgProperty(msg, 'data.contribution.type');
714             var nodeText = actionCenterJSON.getMsgProperty(msg, 'data.contribution.contributionProperties.name.value');
715             var childTypeList = this.attributes.populationRules.getAllChildTypeList();
716             var customIcon = this.attributes.populationRules.getRuleProperty(contributionType, this.type, 'normalIcon');
717             if (!customIcon || customIcon.length === 0) customIcon = 'Ext.BLANK_IMAGE_URL';
718             var normalIconHeight = this.attributes.populationRules.getRuleProperty(contributionType, this.type, 'normalIconHeight');
719             if (!normalIconHeight || normalIconHeight.length === 0) normalIconHeight = '';
720             var normalIconWidth = this.attributes.populationRules.getRuleProperty(contributionType, this.type, 'normalIconWidth');
721             if (!normalIconWidth || normalIconWidth.length === 0) normalIconWidth = '';
722             var activeIcon = this.attributes.populationRules.getRuleProperty(contributionType, this.type, 'activeIcon');
723             if (!activeIcon || activeIcon.length === 0) activeIcon = 'Ext.BLANK_IMAGE_URL';
724             var activeIconHeight = this.attributes.populationRules.getRuleProperty(contributionType, this.type, 'activeIconHeight');
725             if (!activeIconHeight || activeIconHeight.length === 0) activeIconHeight = '';
726             var activeIconWidth = this.attributes.populationRules.getRuleProperty(contributionType, this.type, 'activeIconWidth');
727             if (!activeIconWidth || activeIconWidth.length === 0) activeIconWidth = '';
728             var populationRuleId = this.attributes.populationRules.getRuleProperty(contributionType, this.type, 'id');
729             if (populationRuleId == undefined) populationRuleId = '';
730             var order = actionCenterJSON.getMsgProperty(msg, 'data.contribution.contributionProperties.AC_Order.value');
731             var isValidType = this.attributes.populationRules.isValidChildType(this.type, contributionType);
732             wsnode = new actioncenter.outlinerExplorerGridNode({
733                 isInvalidType: !isValidType,
734                 type: contributionType,
735                 name: nodeText,
736                 text: nodeText,
737                 colstyles: 'x-treegrid-col-no-border',
738                 cls:'AC_'+populationRuleId,
739                 selectedCls:'AC_'+populationRuleId+'-selected',
740                 overCls:'AC_'+populationRuleId+'-over',
741                 over_selectedCls:'AC_'+populationRuleId+'-over_selected',
742                 useCustomIcon: true,
743                 customIcon: customIcon,
744                 normalIcon: customIcon,
745                 activeIcon: activeIcon,
746                 iconWidth: this.attributes.iconWidth,
747                 iconHeight: this.attributes.iconHeight,
748                 normalWidth: normalIconWidth,
749                 normalHeight: normalIconHeight,
750                 activeWidth: activeIconWidth,
751                 activeHeight: activeIconHeight,
752                 contributionId: id,
753                 populationRules: this.attributes.populationRules,
754                 order: order,
755                 contextMenu: [{cut: true},
756                               {copy: true},
757                               {pastebefore: true},
758                               {pasteafter: true},
759                               {pastesub: true},
760                               {del: true}],
761                 listenProfiles: [{channelId       : id,
762                                   childType       : childTypeList,
763                                   updateSelf      : true,
764                                   properties      : [{key: 'AC_Order', method: 'editOrder'},
765                                                      {key: 'name', method: 'editText'},
766                                                      {key: 'icon', method: 'editIcon'}]
767                                 }],
768                 treePanelId: 'outlinerPanel' + this.componentId
769             });
770             window.actionCenterUtility.reorder(this, wsnode);
771             wsnode.subscribeAllChannels();
772         }
773         return wsnode;
774     },
775 
776     /**
777      * Updates appropriate attributes for this contribution in its new location.
778      *
779      * @param contributionMsg
780      *          the contribution message
781      */
782     setAttributes: function (msg) {        
783         if (msg) {
784              this.type = actionCenterJSON.getMsgProperty(msg, 'data.contribution.type');             
785         }
786 
787         this.attributes.customIcon = this.attributes.populationRules.getRuleProperty(this.type, this.parentNode.type, 'normalIcon');
788         this.attributes.normalIcon = this.attributes.populationRules.getRuleProperty(this.type, this.parentNode.type, 'normalIcon');
789         this.attributes.activeIcon = this.attributes.populationRules.getRuleProperty(this.type, this.parentNode.type, 'activeIcon');
790         //change the node format to match its type
791         this.attributes.type = this.type;
792         var clsArray = [this.attributes.cls, this.attributes.selectedCls, this.attributes.overCls, this.attributes.over_selectedCls];
793         if (this.ui){
794             this.ui.removeClass(clsArray);
795             this.ui.removeCssClass(clsArray);
796         }
797         var populationRuleId = this.attributes.populationRules.getRuleProperty(this.type, this.parentNode.type, 'id');
798         this.attributes.cls = 'AC_'+populationRuleId;
799         this.attributes.selectedCls = 'AC_'+populationRuleId+'-selected';
800         this.attributes.overCls = 'AC_'+populationRuleId+'-over';
801         this.attributes.over_selectedCls = 'AC_'+populationRuleId+'-over_selected';       
802         if (this.ui){
803             this.ui.addClass(this.attributes.cls);
804             this.ui.addCssClass(this.attributes.cls);
805         }
806         //end of changing the node format
807         if (!this.attributes.customIcon || this.attributes.customIcon.length === 0) {
808             this.attributes.customIcon = 'Ext.BLANK_IMAGE_URL';
809         }
810         if (!this.attributes.normalIcon || this.attributes.normalIcon.length === 0) {
811             this.attributes.normalIcon = 'Ext.BLANK_IMAGE_URL';
812         }
813         if (!this.attributes.activeIcon || this.attributes.activeIcon.length === 0) {
814             this.attributes.activeIcon = 'Ext.BLANK_IMAGE_URL';
815         }
816         this.attributes.normalIconWidth = 
817                 this.attributes.populationRules.getRuleProperty(this.type, this.parentNode.type, 'normalIconWidth')
818             ||  this.attributes.iconWidth;
819         this.attributes.normalIconHeight = 
820                 this.attributes.populationRules.getRuleProperty(this.type, this.parentNode.type, 'normalIconHeight')
821             ||  this.attributes.iconHeight;
822         this.attributes.activeIconWidth = 
823                 this.attributes.populationRules.getRuleProperty(this.type, this.parentNode.type, 'activeIconWidth')
824             ||  this.attributes.iconWidth;
825         this.attributes.activeIconHeight = 
826                 this.attributes.populationRules.getRuleProperty(this.type, this.parentNode.type, 'activeIconHeight')
827             ||  this.attributes.iconHeight;
828         this.attributes.isInvalidType = !this.attributes.populationRules.isValidChildType(this.parentNode.type, this.type);
829         if (this == this.ownerTree.selModel.activeNode) {
830             this.ui.onActiveChange(true);
831         } else {
832             this.ui.onActiveChange(false);
833         }
834         this.toggleInvalidIndicator();
835     },
836 
837     /**
838      * Deletes a child node.
839      *
840      * @param msg
841      *         the message
842      *
843      * @return void
844      */
845     deleteChild: function (msg) {
846         if (!this.isMove(msg)) {
847             var childId = actionCenterJSON.getMsgProperty(msg,'data.contribution.id');
848 
849             var node = this.findChild('contributionId', childId);
850             if (node != null) {
851                 //this.beforeDeleteChild(msg, node);
852                 var sm = this.getOwnerTree().getSelectionModel();
853                 var isAnchoredNode;
854                 if (sm.anchoredNode === node) {
855                     isAnchoredNode = true;
856                 }
857                 node.cleanUp();
858                 this.removeChild(node);
859                 if (node.counter) {
860                     window.actionCenterUtility.reorderCounter(this);
861                 }
862                 if (isAnchoredNode) {
863                     sm.fireEvent('iyo');
864                 }
865             }
866         }
867         return;
868     },
869 
870     handleSubComponentTrigger: function (event) {
871         for (var i=0; i < this.triggerEventRegistry.length;i++) {
872             var subCompTriggers = this.triggerEventRegistry[i];
873             var triggerEvents = subCompTriggers.triggerEvents;
874             for (var j=0;j < triggerEvents.length;j++) {
875                 if (triggerEvents[j] == event) {
876                     var subCompCell = this.getCellObject(this.getOwnerTree(),this,subCompTriggers.subComponentCol);
877                     subCompCell.launchSubCompWindow();//this is to launch the sub component window
878                     break;
879                 }
880             }
881         }
882     },
883     
884     /**
885      * Handles beforeremove events.
886      *
887      * @param tree
888      *          the tree
889      * @param parentNode
890      *          the parent node
891      * @param node
892      *          the node
893      * @return true
894      */
895     onBeforeremove: function (tree, parentNode, node) {
896         actioncenter.outlinerExplorerGridNode.superclass.onBeforeremove.call(this,tree, parentNode, node);
897         var tree = node.getOwnerTree();
898         var sm = tree.selModel; 
899         var cols = tree.columns;
900         var pcChildCol = null;
901         for(var i = 0;i<cols.length;i++){
902             if (cols[i].renderer && cols[i].renderer.type == 'pcChildComponentRenderer'){
903                 pcChildCol = cols[i];                
904                 break;
905             } 
906         }       
907         if (pcChildCol){
908             if (sm.anchoredNode){
909                 var n = sm.anchoredNode;            
910                 var subCompCell = n.getCellObject(n.getOwnerTree(),n,pcChildCol);
911                 subCompCell.launchSubCompWindow();//this is to launch the sub component window            
912             } else {
913                 //there is no nodes left in the outliner
914                 pcChildCol.renderer.destroyComponent();
915             }
916         }
917     }
918 });
919 //****************************** Outliner Explorer Grid Node UI ****************************************
920 actioncenter.outlinerExplorerGridNodeUI = Ext.extend(Ext.ux.tree.ACTreeGridNodeUI, {
921     isDoubleClickEvent: false,
922 
923     render: function (bulkRender) {
924         actioncenter.outlinerExplorerGridNodeUI.superclass.render.call(this, bulkRender);
925         this.addCssClass(this.node.attributes.cls);
926     },
927 
928     // private
929     //override
930     onSelectedChange : function (state, focusNotAllowed) {
931         actioncenter.outlinerExplorerGridNodeUI.superclass.onSelectedChange.call(this, state, focusNotAllowed);
932         // remove the over css classes
933         var clsArray = [this.node.attributes.overCls, this.node.attributes.over_selectedCls];
934         var el = Ext.fly(this.elNode);
935         el.removeClass(clsArray);
936         this.removeCssClass(clsArray);
937 
938         // then add the selected css class
939         if (state) {
940             this.addClass(this.node.attributes.selectedCls);
941             this.addCssClass(this.node.attributes.selectedCls);
942         }else{
943             this.removeClass(this.node.attributes.selectedCls);
944             this.removeCssClass(this.node.attributes.selectedCls);
945         }
946     },
947 
948     onOver : function (e) {
949         actioncenter.outlinerExplorerGridNodeUI.superclass.onOver.call(this, e);
950         var cls;
951         if (this.node.isSelected()) {
952             cls = this.node.attributes.over_selectedCls;
953         } else {
954             cls = this.node.attributes.overCls;
955         }
956         this.addClass(cls);
957         this.addCssClass(cls);
958     },
959 
960     onOut : function (e) {
961         actioncenter.outlinerExplorerGridNodeUI.superclass.onOut.call(this, e);
962         var cls;
963         if (this.node.isSelected()) {
964             cls = this.node.attributes.over_selectedCls;
965         } else {
966             cls = this.node.attributes.overCls;
967         }
968         this.removeClass(cls);
969         this.removeCssClass(cls);
970     },
971 
972     addCssClass: function (cls) {
973         var el = Ext.fly(this.elNode);
974         var spanChildren = el.query('td span');
975         for (var i = 0; i < spanChildren.length; i++) {
976             var childEl = Ext.fly(spanChildren[i]);
977             childEl.addClass(cls);
978         }
979     },
980 
981     removeCssClass: function (cls) {
982         var el = Ext.fly(this.elNode);
983         var spanChildren = el.query('td span');
984         for (var i = 0; i < spanChildren.length; i++) {
985             var childEl = Ext.fly(spanChildren[i]);
986             childEl.removeClass(cls);
987         }
988     },
989 
990     /**
991       * Defines the double-click behavior.
992       *
993       * @param e
994       *     the event
995       */
996     onDblClick : function (e) {
997         e.stopEvent();
998         this.isDoubleClickEvent = true;
999         this.node.handleSubComponentTrigger('dblclick');
1000     },
1001     /**
1002       * Defines the click behavior.
1003       *
1004       * @param e
1005       *      the event
1006       */
1007     onClick: function (e) {
1008         actioncenter.outlinerExplorerGridNodeUI.superclass.onClick.call(this,e);
1009         this.clickAction();
1010         //this.node.handleSubComponentTrigger('click');
1011     },
1012 
1013     clickAction: function () {
1014         this.isDoubleClickEvent = false;
1015         var obj = this;
1016         setTimeout(function () {
1017             if (!obj.isDoubleClickEvent) {
1018                 obj.node.handleSubComponentTrigger('click');
1019             }
1020         },500);
1021     }
1022 });
1023 //**********************************************************************************************************
1024 //****************************** Outliner Subcomponent Grid Cell Object ************************************
1025 Ext.ux.tree.ACOutlinerSubcomponentCell = function (row, col, treegrid, config) {
1026     Ext.ux.tree.ACOutlinerSubcomponentCell.superclass.constructor.call(this, row, col, treegrid, config);
1027     for (var i = 0; i < treegrid.ownerPanel.columns.length; i++) {
1028         var columnobj = treegrid.ownerPanel.columns[i];
1029         if (columnobj.dataIndex === col) {
1030             this.superiorContributionId = row;
1031             this.renderer     = columnobj.renderer;
1032             this.contribution = columnobj.renderer.getComponentConfiguration();
1033             this.customIcon   = columnobj.renderer.getComponentConfiguration().getPropertyValue('icon');
1034             this.subType      = columnobj.renderer.getComponentConfiguration().getPropertyValue('subType');
1035             this.name         = columnobj.name;
1036             this.displayHover = columnobj.renderer.getComponentConfiguration().getPropertyValue('name');
1037             this.type         = columnobj.type;
1038             return;
1039         }
1040     }
1041 };
1042 
1043 Ext.extend(Ext.ux.tree.ACOutlinerSubcomponentCell, Ext.ux.tree.ACTreeGridCell, {
1044     layout : 'anchor',
1045     anchored : true,
1046     type : 'AC_Component',
1047     populationRules : null,
1048     icon : Ext.BLANK_IMAGE_URL,
1049     afterRender: function () {
1050         Ext.ux.tree.ACOutlinerSubcomponentCell.superclass.afterRender.call(this);
1051         this.el.on({
1052             scope: this,
1053             mouseover: this.onMouseOver,
1054             mouseout: this.onMouseOut,
1055             mouseup: this.onMouseUp,
1056             mousedown: this.onMouseDown
1057             });
1058         if (!this.registered) {
1059             this.registered = true;
1060         }
1061         var emptyIconGUID = this.contribution.getPropertyValue("emptyIcon");
1062         if (emptyIconGUID != null && emptyIconGUID.length > 0) {
1063             this.emptyIcon = AC.util.StandardIcons.getImageServlet() + emptyIconGUID;
1064         } else {
1065             this.emptyIcon = this.icon;
1066         }
1067         var filledIconGUID = this.contribution.getPropertyValue("filledIcon");
1068         if (filledIconGUID != null && filledIconGUID.length > 0) {
1069             this.filledIcon = AC.util.StandardIcons.getImageServlet() + filledIconGUID;
1070         } else {
1071             this.filledIcon = this.icon;
1072         }
1073         if (this.contributionChildCounter && this.contributionChildCounter.count > 0) {
1074             this.icon = this.filledIcon;
1075         } else {
1076             this.icon = this.emptyIcon;
1077         }
1078         this.removeSubcomponentEl();
1079         this.addSubcomponentEl();
1080         this.triggerIcon = Ext.fly(this.el).child('.x-tree-trigger-icon');
1081         this.newInfoMarkerImg = Ext.fly(this.el).child('.x-tree-infomarker');
1082         Ext.QuickTips.getQuickTip().origAnchor = 'right';
1083         Ext.QuickTips.register({
1084             target: this.triggerIcon,
1085             text: this.getTipText(0,0),
1086             title: this.displayHover,
1087             anchor: 'right',
1088             trackMouse: true
1089         });
1090 
1091         //Send the trigger events that the row that contains this cell have to listen to
1092         // and response by launching the subcomponent
1093         var triggerEvents = this.contribution.getPropertyValue("triggerEvents");
1094         if (triggerEvents && triggerEvents != '') {
1095             var triggerEventArray = triggerEvents.split('|~|');
1096             this.row.triggerEventRegistry.push({subComponentCol:this.col,triggerEvents:triggerEventArray});
1097         }
1098 
1099         // actionCenterAPI.getPopulationRules(this.contribution.getId(), this, this.setPopulationRules);
1100         this.setPopulationRules(this.renderer.getComponentConfiguration()._msg.populationRules);
1101     },
1102     getTipText: function (contributionsCount, newCount) {
1103         var tipText = "<br><div>Contributions: " + contributionsCount + "</div></br><div>New: "
1104                       + newCount + "</div>";
1105         return tipText;
1106     },
1107     setPopulationRules: function (msg) {
1108         this.populationRules = msg;
1109         var populationRulesUtil = new AC.data.PopulationRulesParser(msg);
1110         this.contributionChildCounter = new AC.data.ContributionChildCounter(this.superiorContributionId, populationRulesUtil, this, this.updateCounter);
1111         var dropConvertToTypes = populationRulesUtil.getValidCastTypesOnTriggerDrop();
1112         if (dropConvertToTypes) {
1113             this.drop = new Ext.dd.DropTarget(this.triggerImg, {
1114                 // must be same as for tree
1115                 ddGroup: this.ddGroup || "TreeDD",
1116                 subCompentTagId: this.subCompentTagId,
1117                 contributionId: this.row.contributionId,
1118                 dropConvertToTypes: dropConvertToTypes,
1119                 notifyEnter : function (dd, e, data) {
1120                     return this.notifyOver(dd, e, data);
1121                 },
1122                 notifyOver : function (dd, e, data) {
1123                     if (!data) return this.dropNotAllowed;
1124                     var dropNodes = data.nodes ? data.nodes : [data.node];
1125                     var isValid = true;
1126                     for (var i=0; i < dropNodes.length; i++) {
1127                         if (this.contributionId === dropNodes[i].contributionId) {
1128                             isValid = false;
1129                         }
1130                     }
1131                     if (isValid)
1132                         return this.dropAllowed;
1133                     else
1134                         return this.dropNotAllowed;
1135                 },
1136                 // what to do when user drops a node here
1137                 notifyDrop:function (dd, e, node) {
1138                     e.preventDefault();
1139                      e.stopEvent();
1140                      if (e.target.id != this._domRef.id) {
1141                          var nodeEl = Ext.fly(e.target).parent('table');
1142                            if (nodeEl.id != this._domRef.id) {
1143                                return false;
1144                            }
1145                      }
1146                     for (var i=0; i < node.nodes.length; i++) {
1147                         if (node.nodes[i].contributionId === this.contributionId) {
1148                             return false;
1149                         }
1150                     }
1151                     if (this.dropConvertToTypes.length == 1) {
1152                         this.moveContribution(node, this.dropConvertToTypes[0]);
1153                     } else {
1154                         actionCenterUtility.choiceDialog(this.dropConvertToTypes, 'Select the type to convert to', this.contributionId+'selectType',node, this, this.moveContribution);
1155                     }
1156                     return true;
1157                 }, // eo function notifyDrop
1158                 moveContribution: function (node, type) {
1159                     for (var i=0; i < node.nodes.length; i++) {
1160                         actionCenterAPI.moveContribution2(node.nodes[i].contributionId,
1161                             node.nodes[i].parentNode.contributionId, this.contributionId,
1162                                'childof', null, null, type, node.nodes[i].addChannelRelationshipType);
1163                     }
1164                 }
1165             });
1166         }
1167     },
1168     addSubcomponentEl : function () {
1169         if (!this.subcomponentel) {
1170             this.subCompentTagId = Ext.id();
1171             var lt = '<';
1172             var gt = '>';
1173             this.newInfoMarker = "<img style='text-align: center; display: float; width: 3px;' src='" + Ext.BLANK_IMAGE_URL + "' class='x-tree-infomarker'/>";
1174             var subcomponentTag = "<table id=" + this.subCompentTagId + ">"
1175                                   + "<tr valign='center'>"
1176                                   + "<td width='3px' align='left'>" + this.newInfoMarker + "</td>"
1177                                   + "<td>"
1178                                   + "<img class='x-tree-trigger-icon' style='text-align: center; display: float' src='" + this.icon + "'/>";
1179                                   + "</td>"
1180                                   + "</tr>"
1181                                   + "</table>";
1182             this.subcomponentel = this.el.insertHtml('afterBegin',subcomponentTag,true);
1183             this.triggerImg = Ext.get(this.subCompentTagId);
1184         }
1185     },
1186     removeSubcomponentEl : function () {
1187         if (this.subcomponentel) {
1188             this.subcomponentel.remove();
1189             delete this.subcomponentel;
1190             this.subcomponentel = null;
1191         }
1192         while(this.el.dom.children.length > 0) {
1193             Ext.fly(this.el.dom.children[0]).remove();
1194         }
1195     },
1196     updateCounter : function () {
1197         var currentCount = this.contributionChildCounter.count;
1198         var currentNewCount = this.contributionChildCounter.newCount;
1199         var quickTip = Ext.QuickTips.getQuickTip();
1200         var target = quickTip.targets[Ext.id(this.triggerIcon)];
1201         target.text = this.getTipText(currentCount, currentNewCount);
1202         // set the appropriate trigger image
1203         if (currentCount > 0) {
1204             if (!this.hasChildren) {
1205                 this.icon = this.filledIcon;
1206                 this.triggerIcon.dom.src = this.icon;
1207                 this.hasChildren = true;
1208             }
1209         }  else if (this.hasChildren) {
1210             this.icon = this.emptyIcon;
1211             this.triggerIcon.dom.src = this.icon;
1212             this.hasChildren = false;
1213         }
1214         // set/remove new infomarker
1215         if (this.newInfoMarkerImg.hasClass('x-tree-infomarker-on') && currentNewCount === 0) {
1216             this.newInfoMarkerImg.removeClass('x-tree-infomarker-on');
1217         } else if (!this.newInfoMarkerImg.hasClass('x-tree-infomarker-on') && currentNewCount > 0) {
1218             this.newInfoMarkerImg.addClass('x-tree-infomarker-on');
1219         }
1220     },
1221     onDblClick: function (e) {
1222         e.stopEvent();
1223     },
1224     onRightClick: function (e) {
1225         e.stopEvent();
1226     },
1227     onClick: function (e) {
1228         e.stopEvent();
1229         this.launchSubCompWindow();
1230     },
1231     onMouseOver : function (e) {
1232         if (!this.disabled) {
1233             var internal = e.within(this.el,  true);
1234             if (!internal) {
1235                 if (this.triggerIcon) {
1236                        this.triggerIcon.addClass('x-tree-trigger-icon-over');
1237                 }
1238                 this.fireEvent('mouseover', this, e);
1239             }
1240         }
1241     },
1242     // private
1243     onMouseOut : function (e) {
1244         if (this.triggerIcon ) {
1245             if (!this.triggerIcon.getRegion() || !this.triggerIcon.getRegion().contains(e.getPoint())) {
1246                   this.triggerIcon.removeClass('x-tree-trigger-icon-over');
1247               }
1248         }
1249     },
1250     // private
1251     onMouseDown : function (e) {
1252         if (!this.disabled && e.button === 0) {
1253             if (this.triggerIcon) {
1254                   this.triggerIcon.addClass('x-tree-trigger-icon-down');
1255             }
1256         }
1257     },
1258     // private
1259     onMouseUp : function (e) {
1260         if (this.triggerIcon) {
1261               this.triggerIcon.removeClass('x-tree-trigger-icon-down');
1262         }
1263     },
1264     launchSubCompWindow: function () {
1265         if (this.contribution.getPropertyValue('activeContributionMarker') === 'Y') {
1266             this.treegrid.selModel.activateNode(this.row);
1267         }
1268         this.renderer.renderComponent(this.superiorContributionId, this.treegrid);
1269     },
1270     beforeDestroy : function () {
1271         if (this.actionCenterListener) {
1272             this.actionCenterListener.destroy();
1273         }
1274         this.removeSubcomponentEl();
1275     }
1276 });
1277 actioncenter.tgrCellReg('acoutlinersubcomponentcell', Ext.ux.tree.ACOutlinerSubcomponentCell);
1278 
1279 // Begin AC.pss.Component definition ///////////////////////////////////////////////////////////////////////////////////
1280 AC.pss.Component = function(superiorContribution, renderer, subComponentRenderers, target) {
1281     var component = renderer.getComponentConfiguration();
1282     var componentId = component.getId();
1283     var populationRulesUtil = new AC.data.PopulationRulesParser(component._msg.populationRules);
1284     var superiorContributionId = superiorContribution.getId();
1285     var collapseUnspecifiedIcon = false;
1286     var lines               = component.getPropertyValue("lines")                             === 'Y' ? true : false;
1287     var lineNumberEnable    = component.getPropertyValue("lineNumbering")                     === 'Y' ? true : false;
1288     var openInputOnStartup  = component.getPropertyValue("openInputOnStartup")                === 'Y' ? true : false;
1289     var isHeaderVisible     = component.getPropertyValue("isHeaderVisible")                   === 'Y' ? true : false;
1290     var contributionIconWidth  = component.getPropertyValue("contributionIconWidth");
1291     var contributionIconHeight  = component.getPropertyValue("contributionIconHeight");
1292 
1293     //##################################### begin Header panel assembly ################################################
1294     var headerLabel = new Ext.form.Label ({
1295         id: 'headerLabel' + acGlobalDelimiter + componentId + superiorContributionId,
1296         staticTitle: true,
1297         superiorConId: superiorContributionId,
1298         contributionChildCounter: null,
1299         style: "color: "         + component.getPropertyValue("headerTitleColor")
1300              + "; font-size: "   + component.getPropertyValue("headerTitleFontSize")
1301              + "; font-family: " + component.getPropertyValue("headerTitleFont")
1302              + "; font-weight: bold; position: absolute; top: 4px; left: 4px;",
1303         onRender : function (ct, position) {
1304             var headerFormat = component.getPropertyValue("headerFormat");
1305             if (headerFormat === 'customContent') {
1306                 this.headerTitle = component.getPropertyValue("headerTitle");
1307                 this.text        = component.getPropertyValue("headerTitle");
1308             }
1309             else if (headerFormat === 'parentContributionTextWithoutFIBU') {
1310                 if (renderer.launchPoint) {
1311                     this.staticTitle = false;
1312                     this.launchPoint = renderer.launchPoint;
1313                     var initHeaderObj = this.launchPoint.getSubComponentHeaderInfo(this.superiorConId);
1314                     this.subscribeToUpdates(initHeaderObj.node);
1315                     this.headerTitle = initHeaderObj.text;
1316                     this.html        = this.buildLabelHtml(initHeaderObj, false);
1317                 } else {
1318                     this.headerTitle = component.getPropertyValue("headerTitle");
1319                     this.text        = component.getPropertyValue("headerTitle");
1320                 }
1321             }
1322             else if (headerFormat === 'parentContributionTextWithFIBU') {
1323                 if (renderer.launchPoint) {
1324                     this.staticTitle = false;
1325                     this.launchPoint = renderer.launchPoint;
1326                     var initHeaderObj = this.launchPoint.getSubComponentHeaderInfo(this.superiorConId);
1327                     this.subscribeToUpdates(initHeaderObj.node);
1328                     this.headerTitle = initHeaderObj.text;
1329                     this.html        = this.buildLabelHtml(initHeaderObj, true);
1330                     this.ownerCt.body.setStyle('background', '');
1331                     this.ownerCt.body.replaceClass("x-outliner-header", initHeaderObj.cls);
1332                 } else {
1333                     this.headerTitle = component.getPropertyValue("headerTitle");
1334                     this.text        = component.getPropertyValue("headerTitle");
1335                 }
1336             }
1337             Ext.form.Label.prototype.onRender.apply(this, arguments);
1338         },
1339         subscribeToUpdates: function(target, isReload) {
1340             if (isReload) {
1341                 this.clearMons();
1342             }
1343             this.mon(target, 'counterchange', this.updateLabel, this);
1344             this.mon(target, 'textchange',    this.updateLabel, this);
1345             this.mon(target, 'iconchange',    this.updateLabel, this);
1346             this.mon(target, 'nodedestroy',   this.updateLabel, this);
1347         },
1348         updateLabel : function (isReload) {
1349             var labelText = this.headerTitle + "<sup>" + " (" + this.contributionChildCounter.count + "/" + this.contributionChildCounter.newCount + ")" + "</sup>";
1350             if (this.staticTitle) {
1351                 this.setText(labelText, false);
1352             } else {
1353                 var initHeaderObj;
1354                 if (isReload === true) {
1355                     initHeaderObj = {
1356                         'icon'   : 'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
1357                         'text'   : '',
1358                         'cls'    : '',
1359                         'counter': '',
1360                         'node'   : ''
1361                     };
1362                 } else {
1363                     initHeaderObj = this.launchPoint.getSubComponentHeaderInfo(this.superiorConId);
1364                     this.headerTitle = initHeaderObj.text;
1365                     labelText = this.headerTitle + "<sup>" + " (" + this.contributionChildCounter.count + "/" + this.contributionChildCounter.newCount + ")" + "</sup>";
1366                 }
1367 
1368                 var newHtml;
1369                 if ('parentContributionTextWithoutFIBU'     === component.getPropertyValue("headerFormat")) {
1370                     newHtml = this.buildLabelHtml(initHeaderObj, false);
1371                 } else if ('parentContributionTextWithFIBU' === component.getPropertyValue("headerFormat")) {
1372                     newHtml = this.buildLabelHtml(initHeaderObj, true);
1373                 }
1374                 this.setText(newHtml, false);
1375             }
1376         },
1377         buildLabelHtml: function (initHeaderObj, useParentFIBU) {
1378             var newHtml =
1379                 "<table width='100%' style='white-space: normal; " + (useParentFIBU ? "" : this.initialConfig.style) + "'>"
1380                +  "<tbody><tr>"
1381                +    "<td valign='top'>"
1382                +      "<img height='" + (initHeaderObj.iconHeight || "18") + "px' "
1383                +        "width='" + (initHeaderObj.iconWidth || "16") + "px' "
1384                +        "unselectable='on' class='x-tree-node-icon x-tree-node-inline-icon' style='vertical-align: middle;"
1385                +        (initHeaderObj.icon === undefined ? " display:none;" : "") + "' src='" + initHeaderObj.icon + "'>"
1386                +      "<span class='x-treegrid-counter " + (useParentFIBU ? initHeaderObj.cls + "'" : "'") + ">" + initHeaderObj.counter + "</span>"
1387                +    "</td>"
1388                +    "<td width='100%'>"
1389                +      "<span" + (useParentFIBU ? " class='" + initHeaderObj.cls + "'" : "") + ">" + this.headerTitle + "</span>"
1390                +    "</td>"
1391                +  "</tr></tbody>"
1392                + "</table>";
1393             return newHtml;
1394         },
1395         reload: function (newSuperiorConId) {
1396             this.superiorConId = newSuperiorConId;
1397             this.launchPoint = renderer.launchPoint;
1398             var initHeaderObj = this.launchPoint.getSubComponentHeaderInfo(this.superiorConId);
1399             this.subscribeToUpdates(initHeaderObj.node, true);
1400             this.contributionChildCounter = new AC.data.ContributionChildCounter(this.superiorConId, this.contributionChildCounter._populationRulesUtil, this, this.updateLabel);
1401             this.updateLabel();
1402         }
1403     });
1404 
1405     var backgroundColor = new Ext.Template('background: -moz-linear-gradient({start}, {stop});').apply({
1406         start: component.getPropertyValue("headerPanelColorStart"),
1407         stop:  component.getPropertyValue("headerPanelColorStop")
1408     });
1409     var headerPanelHeight = parseInt(component.getPropertyValue("headerPanelHeight"));
1410     if ('percent' === component.getPropertyValue("headerPanelHeightUnit")) {
1411         headerPanelHeight += '%';
1412     }
1413 
1414     var headerPanel = new Ext.Panel({ // this panel is used to present the header
1415         id: 'header' + acGlobalDelimiter + componentId + superiorContributionId,
1416         region: 'north',
1417         title: 'Header',
1418         height: headerPanelHeight,
1419         header: false,
1420         bodyCssClass: 'x-outliner-header',
1421         bodyStyle: backgroundColor,
1422         margins: '2 2 1 2',
1423         autoScroll: true,
1424         items: [headerLabel]
1425     });
1426     //##################################### end Header panel assembly ##################################################
1427 
1428     //##################################### begin outliner/treegrid panel assembly #########################
1429      var outlinerPanel =
1430          new Ext.Panel({
1431             xtype: 'panel',
1432             header: false,
1433             layout: 'fit',
1434             id: 'outlinerPanel' + componentId + superiorContributionId,
1435             margins: '1 2 1 2',
1436             bodyStyle: 'border-bottom-width: 0px; -moz-border-radius-bottomleft: 0px; -moz-border-radius-bottomright: 0px; background-color: white; padding-top: 4px;',
1437             region: 'center',
1438             split: true,
1439             minWidth: 100,
1440             maxWidth: 350,
1441             hideBorders: true,
1442             width: 200,
1443             bbar: [
1444                {xtype:'tbfill'},
1445                {xtype: 'button',
1446                 id: 'editbutton' + acGlobalDelimiter + componentId + superiorContributionId,
1447                 tooltip: {
1448                     text: 'Edit Contribution',
1449                     anchor: 'right',
1450                     trackMouse: true},
1451                 scale: 'small',
1452                 width: 22,
1453                 height: 16,
1454                 icon: 'images/icn_edit_gray_16x16.png'
1455             }],
1456             populationRules: populationRulesUtil,
1457             subComponentRenderers: subComponentRenderers,
1458             buildBaseTreeNode : function () {
1459                 if (component.getPropertyValue("superiorContributionOrder")) {
1460                     this.order = component.getPropertyValue("superiorContributionOrder");
1461                 } else {
1462                     this.order = superiorContribution.getPropertyValue("AC_Order");
1463                 }
1464                 if (isHeaderVisible) {
1465                     var headerLabel = this.ownerCt.findById('headerLabel' + acGlobalDelimiter + componentId + superiorContributionId);
1466                     headerLabel.contributionChildCounter = new AC.data.ContributionChildCounter(superiorContributionId, this.populationRules, headerLabel, headerLabel.updateLabel);
1467                 }
1468                 this.ownerCt.contributionId = superiorContributionId; // for the scenarios, where a contribution is added but nothing is anchored
1469                 this.createTreeGrid(superiorContributionId);
1470                 this.add(this.maintreegrid);
1471                 this.doLayout();
1472                 inputPanel.mon(inputPanel.getFormItem('place'),          'change', inputPanel.handleLocationChangeEvent,   inputPanel);
1473                 inputPanel.mon(inputPanel.getFormItem('type'),           'select', inputPanel.handleTypeChangeEvent,       inputPanel);
1474                 inputPanel.mon(inputPanel.getFormItem('name'),           'focus',  textArea.handleOnFocus,            textArea);
1475                 inputPanel.mon(inputPanel.getFormItem('name'),           'blur',   textArea.handleOnBlur,             textArea);
1476                 inputPanel.mon(inputPanel.getFormItem('collapsebutton'), 'click',  inputPanel.collapse,               inputPanel);
1477                 inputPanel.mon(tagBar.getButton('sendbutton'),           'click',  inputPanel.addContribution,        inputPanel);
1478                 inputPanel.mon(tagBar.getButton('updatebutton'),         'click',  inputPanel.updateContribution,     inputPanel);
1479                 inputPanel.mon(tagBar.getButton('cancelbutton'),         'click',  inputPanel.cancelEditContribution, inputPanel);
1480                 inputPanel.mon(outlinerPanel.getButton('editbutton'),    'click',  inputPanel.initiateEdit,           inputPanel);
1481             },
1482             reload: function (newSuperiorContributionId) {
1483                 this.maintreegrid.destroy();
1484                 if (isHeaderVisible) {
1485                     var headerLabel = this.ownerCt.findById('headerLabel' + acGlobalDelimiter + componentId + superiorContributionId);
1486                     headerLabel.reload(newSuperiorContributionId);
1487                 }
1488                 this.ownerCt.contributionId = newSuperiorContributionId;
1489                 this.createTreeGrid(newSuperiorContributionId);
1490                 this.add(this.maintreegrid);
1491                 this.doLayout(false, true);
1492                 inputPanel.anchorNode = this.maintreegrid.selModel.anchoredNode;
1493             },
1494             createTreeGrid : function (rootContributionId) {
1495                 var outlinerExplorerRoot = new actioncenter.outlinerExplorerGridNode({
1496                     text: 'rootnode',
1497                     leaf: false,
1498                     validChildTypes: null,
1499                     contributionId: rootContributionId,
1500                     populationRules: this.populationRules,
1501                     order: this.order,
1502                     iconWidth: contributionIconWidth,
1503                     iconHeight: contributionIconHeight,
1504                     componentId: componentId,
1505                     listenProfiles: [{channelId       : rootContributionId,
1506                                       childType       : this.populationRules.getAllChildTypeList(),
1507                                       updateSelf      : true,
1508                                       properties      : [{key: 'AC_Order', method: 'editOrder'}]
1509                                     }],
1510                     expanded: true,
1511                     treePanelId: 'outlinerPanel' + componentId + superiorContributionId
1512                 });
1513 
1514                 var crFactory = new AC.tree.grid.CellObjectFactory();
1515                 var allTypes = this.populationRules.getAllTypesList();
1516                 for (var i = 0; i < allTypes.length; i++) {
1517                     crFactory.addWidget(['AC_Component', allTypes[i]], 'acoutlinersubcomponentcell');
1518                 }
1519                 var objectManager = new AC.tree.grid.WidgetManager(crFactory);
1520                 var columnFactory = [{
1521                     header: 'Name',
1522                     dataIndex: 'name',
1523                     headerType: 'constant',
1524                     columnContent: 'text',
1525                     align: 'center',
1526                     //width: '100%',
1527                     autoExpand: true,
1528                     type: 'AC_User_Name',
1529                     displayIcon: false,
1530                     displayText: true,
1531                     locked: true
1532                 }];
1533                 for (var i = 0; i < this.subComponentRenderers.length; i++) {
1534                     var subComponentRenderer = this.subComponentRenderers[i];
1535                     var emptyGUID = subComponentRenderer.getComponentConfiguration().getPropertyValue("emptyIcon");
1536                     var fullGUID = subComponentRenderer.getComponentConfiguration().getPropertyValue("filledIcon");
1537                     var showColumn = emptyGUID && emptyGUID.length > 0 || fullGUID && fullGUID.length > 0;
1538                     columnFactory.push({
1539                         header: subComponentRenderer.getComponentConfiguration().getPropertyValue('name'),
1540                         dataIndex: subComponentRenderer.getComponentConfiguration().getId(),
1541                         align: 'center',
1542                         width: showColumn ? 26 : 0,
1543                         renderer: subComponentRenderer,
1544                         type: 'AC_Component',
1545                         headerType: 'constant',
1546                         columnContent: 'object',
1547                         childType: 'AC_Component',
1548                         displayIcon: false,
1549                         displayText: true
1550                     });
1551                 }
1552                 this.maintreegrid = new Ext.ux.tree.ACTreeGrid({
1553                     tableclass: '.x-treegrid-root-table-no-border',
1554                     projectType: "AC_Library_Type",
1555                     style: 'border:none;',
1556                     //bodyStyle: 'background-color: white;',
1557                     bodyCssClass: 'AC_'+ componentId,
1558                     componentId: componentId,
1559                     id: 'outlinerExplorer' + componentId + superiorContributionId,
1560                     animate: true,
1561                     vScrollBarVisible: true,
1562                     containerScroll: true,
1563                     rootVisible: false,
1564                     lines: this.ownerCt.lines,
1565                     root: outlinerExplorerRoot,
1566                     objectManager: objectManager,
1567                     cellObjectReference: null,
1568                     enableDD: true,
1569                     ddata: 'yeah',
1570                     allowDrop: true,
1571                     enableSort: false,
1572                     enableHdMenu: false,
1573                     enableColumnHide: false,
1574                     hideHeaders: true,
1575                     ownerPanel: this,
1576                     columnFactory: columnFactory,
1577                     contextMenu:  [{paste: true}],
1578                     keys: [
1579                     {
1580                         key: 'c',
1581                         ctrl: true,
1582                         scope: this,
1583                         stopEvent:true,
1584                         fn: function (key, event) {
1585                             this.maintreegrid.copyToClipboard();
1586                         }
1587                     }, {
1588                         key: 'x',
1589                         ctrl: true,
1590                         scope: this,
1591                         stopEvent:true,
1592                         fn: function (key, event) {
1593                            this.maintreegrid.cutToClipboard();
1594                         }
1595                     }, {
1596                         key: 'v',
1597                         ctrl: true,
1598                         scope: this,
1599                         stopEvent:true,
1600                         fn: function (key, event) {
1601                            this.maintreegrid.delegatePaste();
1602                         }
1603                     }, {
1604                         key: 46,
1605                         scope: this,
1606                         stopEvent:true,
1607                         fn: function (key, event) {
1608                             var selectedNodes = this.maintreegrid.getSelectionModel().getSelectedNodes();
1609                             if (selectedNodes && selectedNodes instanceof Array && selectedNodes.length > 0) {
1610                                 Ext.Msg.show({
1611                                     title: 'Delete',
1612                                     msg: 'Are you sure you want to delete the selected item(s)?',
1613                                     buttons: Ext.Msg.YESNO,
1614                                     icon: Ext.MessageBox.QUESTION,
1615                                     fn: function (btn, text) {
1616                                         if (btn === 'yes') {
1617                                              actionCenterAPI.moveContributionToRecycleBin(selectedNodes);
1618                                         }
1619                                     }
1620                                 });
1621                             }
1622                         }
1623                     }, {
1624                         key: 13,
1625                         scope: this,
1626                         fn: function (key, event) {
1627                             var anchoredNode = this.maintreegrid.getSelectionModel().getAnchoredNode();
1628                             if (anchoredNode) {
1629                                 anchoredNode.handleSubComponentTrigger('enter');
1630                             }
1631                         },
1632                         stopEvent: true
1633                     }],
1634                     onRenderedComponentDestroy: function () {
1635                         this.getSelectionModel().getAnchoredNode().ui.anchor.focus();
1636                     },
1637                     getRootContributionId: function () {
1638                         return this.root.contributionId;
1639                     },
1640                     getSubComponentHeaderInfo: function (row) {
1641                         var node = this.root.findChild('contributionId', row, true);
1642                         var subComponentHeaderInfo = {
1643                             'icon'      : node.ui.iconNode.src,
1644                             'iconHeight': node.ui.iconNode.height,
1645                             'iconWidth' : node.ui.iconNode.width,
1646                             'text'      : node.attributes.name,
1647                             'cls'       : node.attributes.cls,
1648                             'counter'   : node.ui.counter,
1649                             'node'      : node
1650                         };
1651                         return subComponentHeaderInfo;
1652                     }
1653                 });
1654                 this.maintreegrid.enableInfoMarker        = true;
1655                 this.maintreegrid.enableNewInfoMarker     = true;
1656                 this.maintreegrid.borderWidth             = 0;
1657                 this.maintreegrid.collapseUnspecifiedIcon = this.ownerCt.collapseUnspecifiedIcon;
1658                 this.maintreegrid.enableLineNumbering     = this.ownerCt.lineNumbering;
1659                 inputPanel.mon(this.maintreegrid.getSelectionModel(), 'anchorchange', inputPanel.handleAnchorChange, inputPanel);
1660                 inputPanel.mon(this.maintreegrid.getSelectionModel(), 'iyo',          textArea.calcLocaterArrow,     textArea);
1661                 this.maintreegrid.mon(this.maintreegrid, 'aftertreeload', this.afterTreeLoad, this);
1662                 outlinerExplorerRoot.subscribeAllChannels();
1663                 return this.maintreegrid;
1664             },
1665             getButton: function (itemname) {
1666                 var button = this.bottomToolbar.items.map[itemname + acGlobalDelimiter + componentId + superiorContributionId];
1667                 return button;
1668             },
1669             afterTreeLoad : function () {
1670                 if (this.maintreegrid.enableDefaultSort) {
1671                     // default sort
1672                     if (this.maintreegrid.treeGridSorter) {
1673                         this.maintreegrid.root.sort(this.maintreegrid.treeGridSorter.defaultSortFn);
1674                     }
1675                 } else {
1676                     // this will sort the child nodes of the root node according to the AC_Order property
1677                     actionCenterUtility.reorder(this.maintreegrid.root);
1678                 }
1679                 var sm = this.maintreegrid.getSelectionModel();
1680                 // anchor and select the first new contribution or the first top-level contribution
1681                 var firstNewCon = this.maintreegrid.root.findChildBy(
1682                     function () {
1683                         return (this.isNewContribution && this.isNewContribution === true);
1684                     }, null, true); // depth-first search
1685                 if (firstNewCon && this.maintreegrid.enableNewInfoMarker) {
1686                     sm.anchorNode(firstNewCon, true);
1687                     sm.select(firstNewCon);
1688                 } else {
1689                     if (this.maintreegrid.root.childNodes && this.maintreegrid.root.childNodes.length > 0) {
1690                         sm.anchorNode(this.maintreegrid.root.childNodes[0], true);
1691                         sm.select(this.maintreegrid.root.childNodes[0]);
1692                     }
1693                 }
1694                 if (!inputPanel.collapsed) {
1695                     inputPanel.onBodyResize(inputPanel.getWidth(), inputPanel.getHeight());
1696                     sm.clearSelections();
1697                     textArea.focus(false, true);
1698                 }
1699                 // trigger child of the pc shell, if there exists any
1700                 for (var i = 0; i < this.subComponentRenderers.length; i++) {
1701                     if (this.subComponentRenderers[i].type &&
1702                         this.subComponentRenderers[i].type === 'pcChildComponentRenderer') {
1703                         var t = this.maintreegrid;
1704                         var anchoredNode = t.selModel.anchoredNode;
1705                         var childTriggerCell = anchoredNode.getCellObject(t, anchoredNode, t.columns[i + 1]);
1706                         if (childTriggerCell) {
1707                             childTriggerCell.launchSubCompWindow();
1708                         }
1709                         break;
1710                     }
1711                 }
1712                 tagBar.getButton('sendbutton').enable();
1713             },
1714             afterRender : function () {
1715                 Ext.Panel.superclass.afterRender.call(this);
1716                 if (!inputPanel.collapsed) {
1717                     textArea.focus(true, 1000);
1718                 }
1719                 this.inputPanel = inputPanel;
1720             }
1721         });
1722     //##################################### end outliner/treegrid panel assembly ###########################
1723 
1724 
1725     //##################################### begin input panel assembly #####################################
1726     // build the "place" radio group and the input panel collapse trigger row
1727     var placeRadioGroup = new Ext.form.RadioGroup({
1728         id: 'place' + acGlobalDelimiter + componentId + superiorContributionId,
1729         width: 230,
1730         fieldLabel: 'PLACE',
1731         columns: [70, 62, 57, 40],
1732         items: [{boxLabel: 'Append', id: 'append' + acGlobalDelimiter + componentId + superiorContributionId, name: 'place' + acGlobalDelimiter + componentId, inputValue: 'Append', checked: true},
1733                 {boxLabel: 'Before', id: 'before' + acGlobalDelimiter + componentId+ superiorContributionId, name: 'place' + acGlobalDelimiter + componentId, inputValue: 'Before'},
1734                 {boxLabel: 'After',  id: 'after'  + acGlobalDelimiter + componentId+ superiorContributionId, name: 'place' + acGlobalDelimiter + componentId, inputValue: 'After'},
1735                 {boxLabel: 'Sub',    id: 'sub'    + acGlobalDelimiter + componentId+ superiorContributionId, name: 'place' + acGlobalDelimiter + componentId, inputValue: 'Sub'}]
1736     });
1737     var placePanel = new Ext.Panel({
1738         layout: 'hbox',
1739         header: false,
1740         margins: '0 0 2 0',
1741         style: 'padding-left: 4px; padding-right: 4px',
1742         items: [
1743             {   xtype: 'panel',
1744                 layout: 'form',
1745                 items: [placeRadioGroup]
1746             }, {
1747                 xtype: 'panel',
1748                 layout: 'fit',
1749                 flex: 1
1750             }, {
1751                 xtype: 'iconbutton',
1752                 id: 'collapsebutton' + acGlobalDelimiter + componentId+ superiorContributionId,
1753                 scale: 'small',
1754                 iconAlign: 'right',
1755                 width: 16,
1756                 icon: 'images/btn_showhide.png',
1757                 tooltip: 'Hide the input panel'
1758             }
1759         ],
1760         id: 'placePanel' + acGlobalDelimiter + componentId+ superiorContributionId,
1761         afterRender: function () {
1762             Ext.Panel.superclass.afterRender.call(this);
1763             this.boxReady = true;
1764             this.setSize(this.width, this.height);
1765             if (this.x || this.y) {
1766                 this.setPosition(this.x, this.y);
1767             } else if (this.pageX || this.pageY) {
1768                 this.setPagePosition(this.pageX, this.pageY);
1769             }
1770 
1771             if (this.layout) {
1772                 if (typeof this.layout == 'string') {
1773                     this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig);
1774                 }
1775                 this.setLayout(this.layout);
1776 
1777                 if (this.activeItem !== undefined) {
1778                     var item = this.activeItem;
1779                     delete this.activeItem;
1780                     this.layout.setActiveItem(item);
1781                     return;
1782                 }
1783             }
1784             this.ownerCt.doLayout();
1785 
1786             // this block of code puts the underline below the radio group
1787             var radioGroupItem = inputPanel.getFormItem('place');
1788             var formitemwrappernode = radioGroupItem.el.dom.parentNode.parentNode;
1789             formitemwrappernode.style.cssText="padding-bottom:-1px; border-bottom-style:solid; border-bottom-width:1px; border-color: #C4C4C4;";
1790         }
1791     });
1792 
1793     // build the "type" combo box //////////////////////////////////////////////////////////////////////////
1794     // create an ArrayStore that contains all of the fields (displaytext, value) for the combobox
1795     var dataList = [];
1796     var subordinates = populationRulesUtil.getSubordinatesOfType('AC_ComponentSuperior');
1797     var defaultValue = '';
1798     var defaultIcon = null;
1799     var defaultPrompt = '';
1800     var subordinate;
1801     for (var i = 0; i < subordinates.length; i++) {
1802         subordinate = subordinates[i];
1803         dataList.push([
1804             subordinate.subordinate_type,
1805             subordinate.subordinate_type,
1806             AC.util.StandardIcons.getImageURL(subordinate.normalIcon, true, 16)
1807         ]);
1808         if (i === 0) {
1809             defaultValue = subordinate.subordinate_type;
1810             defaultIcon = AC.util.StandardIcons.getImageURL(subordinate.normalIcon, true, 16);
1811             defaultPrompt = subordinate.inputPrompt;
1812         }
1813     }
1814     var store = new Ext.data.ArrayStore({
1815         id: 0,
1816         fields: ['selectValue', 'displayText', 'iconURL'],
1817         data: dataList
1818     });
1819 
1820     var typeCombo = new Ext.ux.form.IconCombo({
1821         triggerAction: "all",
1822         store: store,
1823         mode: 'local',
1824         editable: false,
1825         style: 'border-right-width: 0px; background-image: none;',
1826         name: 'type' + acGlobalDelimiter + componentId,
1827         id: 'type' + acGlobalDelimiter + componentId+ superiorContributionId,
1828         valueField: 'selectValue',
1829         displayField: 'displayText',
1830         iconField: 'iconURL',
1831         value: defaultValue,
1832         lazyRender: true,
1833         width: 132,
1834         hideTrigger: false,
1835         minListWidth: 115,
1836         fieldLabel: 'TYPE',
1837         hideParent: true,
1838         hideMode: 'offsets',
1839         triggerClass: 'x-form-orange-trigger'
1840     });
1841     // cause the drop down selection item list to be as wide as the widest item
1842     typeCombo.on("expand", function () {
1843         typeCombo.list.setStyle("width", "auto");
1844         typeCombo.innerList.setStyle("width", "auto");
1845     }, {single: true});
1846 
1847     var typePanel = new Ext.Panel({
1848         layout: 'form',
1849         header: false,
1850         labelWidth: 42,
1851         margins: '0 0 2 0',
1852         style: 'padding-left: 4px; padding-right: 4px; padding-top: 2px;',
1853         items: [typeCombo],
1854         id: 'typePanel' + acGlobalDelimiter + componentId+ superiorContributionId,
1855         afterRender: function () {
1856             Ext.Panel.superclass.afterRender.call(this);
1857             if (!populationRulesUtil.hasAmbiguities()) {
1858                 this.hide();
1859             }
1860         }
1861     });
1862 
1863     // build the "contributionEntry" entry including the text area and info/add tags bar////////////////////
1864     var textArea = new Ext.form.TextArea({
1865         id: 'name' + acGlobalDelimiter + componentId+ superiorContributionId,
1866         value: defaultPrompt,
1867         defaultPrompt: defaultPrompt,
1868         allowBlank: false,
1869         style: 'border-color: white; background-image: none; overflow-y: auto;',
1870         columnWidth: 1.0,
1871         selectOnFocus: true,
1872         enableKeyEvents: true,
1873         beginEdit: false,//a new property used to indicate the editing starts in the text area
1874         outlinerPanel: outlinerPanel,
1875         cursorStart: 0,
1876         cursorEnd: 0,
1877         afterRender: function () {
1878             Ext.form.TextArea.superclass.afterRender.call(this);
1879             this.el.on({
1880                 scope: this,
1881                 mouseup:   this.onMouseUp,
1882                 mousedown: this.onMouseDown
1883             });
1884             this.mon(this.ownerCt.body,'click',this.ownerCt.onClick,this.ownerCt);
1885             this.mon(this.ownerCt,'bodyresize',this.onOwnerCtResize,this);
1886             this.addClass('x-form-textarea-prompt');
1887         },
1888 
1889         onOwnerCtResize: function(){
1890             this.setHeight(this.ownerCt.getHeight()-8);
1891         },
1892 
1893         onMouseDown: function(e) {
1894             if (!this.isDirty()) {
1895                 this.selectText(0, 0);
1896             }
1897         },
1898         onMouseUp: function(e) {
1899             if (!this.isDirty()) {
1900                 this.selectText(0, 0);
1901             }
1902         },
1903         handleOnFocus: function (e) {
1904             if (this.isDirty()) {
1905                 this.selectText(this.cursorStart, this.cursorEnd);
1906                 this.addClass('x-form-textarea-on-focus');
1907             } else {
1908                 this.selectText(0, 0);
1909             }
1910             this.calcLocaterArrow();
1911         },
1912 
1913         calcLocaterArrow: function () {
1914             //get tree ref for arrow marker
1915             var curranchor = outlinerPanel.maintreegrid.getSelectionModel().getAnchoredNode();
1916             var horiznode;
1917             var placement = this.ownerCt.ownerCt.ownerCt.ownerCt.getFormItem('place').getValue().inputValue;
1918             if (placement === 'Sub') {
1919                 placement = 'append';
1920                 horiznode = curranchor;
1921                 if (curranchor) {
1922                     if (curranchor.lastChild) {
1923                         curranchor = curranchor.lastChild;
1924                     }
1925                 }
1926             } else if (placement === 'Append') {
1927                 placement = 'below';
1928                 horiznode = curranchor;
1929                 if (curranchor) {
1930                     curranchor = curranchor.parentNode.lastChild;
1931                     while (curranchor.isExpanded() && curranchor.hasChildNodes()) {
1932                         curranchor = curranchor.lastChild;
1933                     }
1934                 }
1935             } else if (placement === 'After') {
1936                 placement = 'below';
1937                 horiznode = curranchor;
1938                 if (curranchor) {
1939                     while (curranchor.isExpanded() && curranchor.hasChildNodes()) {
1940                         curranchor = curranchor.lastChild;
1941                     }
1942                 }
1943             } else {
1944                 placement = 'above';
1945                 horiznode = curranchor;
1946             }
1947             outlinerPanel.maintreegrid.placeLocaterArrow(curranchor, horiznode, placement);
1948         },
1949         handleOnBlur: function (txtArea) {
1950             if (this.getValue() === '') {
1951                 this.cursorStart = 0;
1952                 this.cursorEnd   = 0;
1953                 this.setValue(this.defaultPrompt);
1954                 this.addClass('x-form-textarea-prompt');
1955             } else {
1956                 if (Ext.isIE) {
1957                     var bookmark = document.selection.createRange().getBookmark();
1958                     var selection = this.el.dom.createTextRange();
1959                     selection.moveToBookmark(bookmark);
1960 
1961                     var before = this.el.dom.createTextRange();
1962                     before.collapse(true);
1963                     before.setEndPoint("EndToStart", selection);
1964 
1965                     var selLength = selection.text.length;
1966 
1967                     this.cursorStart = before.text.length;
1968                     this.cursorEnd   = this.cursorStart + selLength;
1969                 } else {
1970                     this.cursorStart = this.el.dom.selectionStart;
1971                     this.cursorEnd   = this.el.dom.selectionEnd;
1972                 }
1973             }
1974             this.removeClass('x-form-textarea-on-focus');
1975             outlinerPanel.maintreegrid.removeLocaterArrow();
1976         },
1977         onKeyPress : function(e) { // overrides Ext.form.TextField.onKeyPress            
1978             if (!this.isDirty() && (this.getValue() === this.defaultPrompt)) {
1979                 this.beginEdit = true;
1980                 this.setValue('');
1981                 this.removeClass('x-form-textarea-prompt');
1982                 this.addClass('x-form-textarea-on-focus');
1983             }
1984             if (e.getKey() === e.F9 && e.charCode !== e.F9 && !tagBar.getButton('sendbutton').hidden) {
1985                 inputPanel.addContribution();
1986                 this.removeClass('x-form-textarea-on-focus');
1987             }
1988             this.fireEvent('keypress', this, e);
1989         },
1990         processValue: function(value) { // overrides Ext.form.TextField.processValue
1991             if (!this.beginEdit && this.getValue() === '') {
1992                 this.removeClass('x-form-textarea-on-focus');
1993                 if (this.defaultPrompt !== ''){
1994                   this.setValue(this.defaultPrompt);
1995                 }
1996                 this.addClass('x-form-textarea-prompt');
1997                 this.selectText(0, 0);
1998             }
1999             this.beginEdit = false;
2000             return value;
2001         }
2002     });
2003 
2004     var contributionEntry = new Ext.Panel({
2005         layout: 'column',
2006         header: false,
2007         style: 'background-color:white; padding-top: 4px;',
2008         items: [
2009             {
2010                 xtype: 'label', text: '.', width: 8, style: 'color:white;'
2011             }, {
2012                 xtype: 'iconbutton',
2013                 id: 'entryicon' + acGlobalDelimiter + componentId+ superiorContributionId,
2014                 scale: 'small',
2015                 iconAlign: 'right',
2016                 width: 16,
2017                 icon: defaultIcon
2018             }, {
2019                 xtype: 'label', text: '.', width: 5, style: 'color:white;'
2020             },  textArea
2021         ],
2022         onClick:function(e){
2023             var target = e.getTarget();
2024             if (target !== textArea.el.dom){
2025                 textArea.handleOnFocus();
2026             }
2027         }
2028     });
2029 
2030     var tagBar = new Ext.Panel({
2031         region:'south',
2032         layout: 'column',
2033         header: false,
2034         style: 'padding-bottom: 0px; margin-bottom: 0px;',
2035         height: 29,
2036         getButton: function (itemname) {
2037             var formItem = this.items.map[itemname + acGlobalDelimiter + componentId+ superiorContributionId];
2038             return formItem;
2039         },
2040         items: [
2041             {
2042                 xtype: 'styledbutton',
2043                 text: 'SEND',
2044                 buttonClass: 'small orange standard',
2045                 id: 'sendbutton' + acGlobalDelimiter + componentId+ superiorContributionId,
2046                 style: 'margin-left: 4px; margin-right: 4px; margin-bottom: 4px',
2047                 hideMode: 'offsets',
2048                 width: 60
2049             }, {
2050                 xtype: 'styledbutton',
2051                 id: 'updatebutton' + acGlobalDelimiter + componentId+ superiorContributionId,
2052                 buttonClass: 'small orange standard',
2053                 style: 'margin-left: 4px; margin-bottom: 4px',
2054                 text: 'UPDATE',
2055                 hideMode: 'offsets',
2056                 hidden: true,
2057                 width: 60
2058             }, {
2059                 xtype: 'styledbutton',
2060                 buttonClass: 'small orange standard',
2061                 style: 'margin-left: 4px; margin-right: 4px; margin-bottom: 4px',
2062                 id: 'cancelbutton' + acGlobalDelimiter + componentId+ superiorContributionId,
2063                 text: 'CANCEL',
2064                 hideMode: 'offsets',
2065                 hidden: true,
2066                 width: 60
2067             }
2068         ]
2069     });
2070 
2071     var inputPanelHeight = parseInt(component.getPropertyValue("inputPanelHeight"));
2072     if ('percent' === component.getPropertyValue("inputPanelHeightUnit")) {
2073         inputPanelHeight += '%';
2074     }
2075     var inputPanel =
2076         new Ext.Panel({// this panel is used to present the layouts chosen
2077             anchorNode: null,
2078             region: 'south',
2079             height: inputPanelHeight,
2080             minHeight: 100,
2081             margins:  '1 2 2 2',
2082             cmargins: '1 2 2 2',
2083             split: true,
2084             collapsible: true,
2085             titleCollapse: true,
2086             floatable: false,
2087             collapsed: !openInputOnStartup,
2088             header: false,
2089             collapsedTitle:           component.getPropertyValue("collapsedTitle"),
2090             collapsedTitleColor:      component.getPropertyValue("collapsedTitleColor"),
2091             collapsedTitleFontFamily: component.getPropertyValue("collapsedTitleFontFamily"),
2092             collapsedTitleFontSize:   component.getPropertyValue("collapsedTitleFontSize"),
2093             collapsedTooltip:         component.getPropertyValue("collapsedTitle"),
2094             layout: 'fit',
2095             id: 'inputPanel' + acGlobalDelimiter + componentId+ superiorContributionId,
2096             editMode: false,
2097             contributionarea: contributionEntry,
2098             textarearef: textArea,
2099             renderer: renderer,
2100             items: [{
2101                 xtype: 'form',
2102                 frame: true,
2103                 labelWidth: 42,
2104                 items: [
2105                     placePanel,
2106                     typePanel,
2107                     {
2108                         xtype: 'panel',
2109                         id: 'contributionEntrytagBar' + acGlobalDelimiter + componentId+ superiorContributionId,
2110                         cls: 'x-panel-body-orange',
2111                         width: '99%',
2112                         style: 'padding-left: 1px; padding-right: 1px; padding-top: 1px; padding-bottom: 1px;',
2113                         items: [contributionEntry, tagBar]
2114                     }
2115                 ]
2116             }],
2117             listeners:{
2118                 'afterRender':function(){
2119                     this.mon(this.el,'click',this.onClick,this);
2120                 },
2121                 'expand': function(panel){
2122                     var outputPanel = this.ownerCt.outlinerPanel;
2123                     var t = outputPanel.maintreegrid;
2124                     var sm = t.selModel;
2125                     sm.clearSelections();
2126                     this.textarearef.handleOnFocus();
2127                 }
2128             },
2129             onClick:function(e){
2130                 var outputPanel = this.ownerCt.outlinerPanel;
2131                 var t = outputPanel.maintreegrid;
2132                 var sm = t.selModel;
2133                 sm.clearSelections();
2134             },
2135             onBodyResize: function (w, h) {
2136                 this.fireEvent('bodyresize', this, w, h);
2137                 if (h !== undefined) {
2138                     var typePanel = this.getFormItem('typePanel');
2139                     var typePanelHt = 0;
2140                     if ((typePanel.rendered && !typePanel.isVisible()) ||
2141                             (!typePanel.rendered && !populationRulesUtil.hasAmbiguities())) {
2142                         typePanelHt = 28;
2143                     }
2144                     if (placePanel && placePanel.rendered) {
2145                         // placePanel is not visible on the first render
2146                         placePanel.doLayout(false, true);
2147                     }
2148                     if (!this.editMode) {
2149                         this.contributionarea.setHeight(h - 108 + typePanelHt);
2150                     } else {
2151                         this.contributionarea.setHeight(h - 77 + typePanelHt);
2152                     }
2153                 }
2154             },
2155 
2156             getFormItem: function (itemname) {
2157                 var formItem = this.findById(itemname + acGlobalDelimiter + componentId+ superiorContributionId);
2158                 return formItem;
2159             },
2160             addContribution : function () {
2161                 var inputTxt = this.getFormItem('name').getValue();
2162                 //var matches = inputTxt.match(''+this.getFormItem('name').defaultPrompt+'');
2163                 var match = false;
2164                 if (inputTxt === this.getFormItem('name').defaultPrompt){
2165                     match = true;
2166                 }
2167                 if (inputTxt !== '' && !match) { // if the entered text is not the same as the input prompt
2168                     var afterContributionId = null;
2169                     var beforeContributionId = null;
2170                     var superiorContributionId = null;
2171                     var superiorContributionType = null;
2172                     if (!this.anchorNode) {
2173                         superiorContributionId = this.ownerCt.contributionId;
2174                         superiorContributionType = 'AC_ComponentSuperior';
2175                     } else {
2176                         switch(this.getFormItem('place').getValue().inputValue) {
2177                             case 'Append':
2178                                 superiorContributionId = this.anchorNode.parentNode.contributionId;
2179                                 superiorContributionType = this.anchorNode.parentNode.type;
2180                                 break;
2181                             case 'Before':
2182                                 superiorContributionId = this.anchorNode.parentNode.contributionId;
2183                                 superiorContributionType = this.anchorNode.parentNode.type;
2184                                 beforeContributionId = this.anchorNode.contributionId;
2185                                 break;
2186                             case 'After':
2187                                 superiorContributionId = this.anchorNode.parentNode.contributionId;
2188                                 superiorContributionType = this.anchorNode.parentNode.type;
2189                                 afterContributionId = this.anchorNode.contributionId;
2190                                 break;
2191                             case 'Sub':
2192                                 superiorContributionId = this.anchorNode.contributionId;
2193                                 superiorContributionType = this.anchorNode.type;
2194                                 break;
2195                         }
2196                     }
2197                     var subordinateContributionType = this.getFormItem('type').getValue();
2198                     var relationshipType = populationRulesUtil.getRelationshipTypeFor(subordinateContributionType, superiorContributionType);
2199 
2200                     actionCenterAPI.addRelationship(superiorContributionId, null, relationshipType, afterContributionId,
2201                         beforeContributionId, subordinateContributionType, {name: inputTxt}, this, this.anchorNewContribution);
2202                 }
2203                 this.handleTypeChange(true);
2204                 renderer.onSend();
2205             },
2206             initiateEdit: function () {
2207                 if (this.anchorNode) {
2208                     this.editContributionId = this.anchorNode.contributionId;
2209                     actionCenterAPI.lockContribution(this.editContributionId, this, this.editContribution);
2210                 }
2211             },
2212             editContribution: function (msg) {
2213                 var result = actionCenterJSON.getMsgProperty(msg, 'data.result');
2214                 if (result === 'success') {
2215                     this.editMode = true;
2216                     if (this.collapsed) {
2217                         this.expand(false);
2218                     }
2219                     if (this.textarearef.disabled) {
2220                         this.textarearef.setDisabled(false);
2221                     }
2222                     this.getFormItem('placePanel').hide();
2223 
2224                     var typeItem = this.getFormItem('type');
2225                     var subordinates = populationRulesUtil.getSubordinatesOfType(this.anchorNode.parentNode.type);
2226                     var isTypePickerEnabled = subordinates.length > 1 || this.anchorNode.attributes.isInvalidType;
2227                     if (!isTypePickerEnabled) {
2228                         this.getFormItem('typePanel').hide();
2229                     } else if (!this.getFormItem('typePanel').isVisible()) {
2230                         this.getFormItem('typePanel').show();
2231                     }
2232                     this.onBodyResize(this.getWidth(), this.getHeight());
2233 
2234                     var subordinate;
2235                     var dataList = [];
2236                     for (var i = 0; i < subordinates.length; i++) {
2237                         subordinate = subordinates[i];
2238                         dataList.push([
2239                             subordinate.subordinate_type,
2240                             subordinate.subordinate_type,
2241                             AC.util.StandardIcons.getImageURL(subordinate.normalIcon, true, 16)
2242                         ]);
2243                     }
2244                     if (this.anchorNode.attributes.isInvalidType) { // add the invalid type to the type-picker
2245                         var iconId = populationRulesUtil.getRuleProperty(this.anchorNode.type, null, 'normalIcon');
2246                         dataList.push([this.anchorNode.type, this.anchorNode.type, AC.util.StandardIcons.getImageURL(iconId, true, 16)]);
2247                     }
2248                     var store = new Ext.data.ArrayStore({
2249                         id: 0,
2250                         fields: ['selectValue', 'displayText', 'iconURL'],
2251                         data: dataList
2252                     });
2253                     typeItem.bindStore(store);
2254                     typeItem.setValue(this.anchorNode.type);
2255                     this.getFormItem('name').setValue(this.anchorNode.attributes.name);
2256                     this.getFormItem('name').removeClass('x-form-textarea-prompt');
2257                     var iconURL = this.anchorNode.attributes.icon;
2258                     if (iconURL.indexOf("scale=16") === -1) {
2259                         iconURL = iconURL + '&' + 'scale=16';
2260                     }
2261                     this.getFormItem('entryicon').setIcon(iconURL);
2262                     tagBar.getButton('sendbutton').hide();
2263                     tagBar.getButton('updatebutton').show();
2264                     tagBar.getButton('cancelbutton').show();
2265                     this.getFormItem('name').focus(true);
2266                     this.ownerCt.items.items[1].getButton('editbutton').disable();
2267                 }
2268             },
2269             updateContribution: function () {
2270                 var contributionProperties = {name: this.getFormItem('name').getValue()};
2271                 var newType = this.getFormItem('type').getValue();
2272                 actionCenterAPI.editContribution(this.editContributionId, contributionProperties, null, null, null, true, newType);
2273                 this.editMode = false;
2274                 this.cancelEditContribution();
2275             },
2276             cancelEditContribution: function () {
2277                 if (this.editMode) {
2278                     actionCenterAPI.unlockContribution(this.editContributionId);
2279                     this.editMode = false;
2280                 }
2281                 this.editContributionId = null;
2282                 this.getFormItem('placePanel').show();
2283                 if (populationRulesUtil.hasAmbiguities()) {
2284                     this.getFormItem('typePanel').show();
2285                 } else {
2286                     this.getFormItem('typePanel').hide();
2287                 }
2288                 this.collapse(false);
2289                 tagBar.getButton('updatebutton').hide();
2290                 tagBar.getButton('cancelbutton').hide();
2291                 tagBar.getButton('sendbutton').show();
2292                 this.expand(false);
2293                 this.handleTypeChange(true);
2294                 this.handleAnchorChange(outlinerPanel.maintreegrid, this.anchorNode);
2295                 this.ownerCt.items.items[1].getButton('editbutton').enable();
2296             },
2297             handleAnchorChange: function (treeGrid, anchorNode) {
2298                 this.anchorNode = anchorNode;
2299                 if (this.anchorNode === null) {
2300                     return;
2301                 }
2302                 var locRadioGroup = this.getFormItem('place');
2303                 var previousValue = locRadioGroup.getValue().inputValue;
2304                 var allowSiblings = populationRulesUtil.hasSubordinatesOfType(this.anchorNode.parentNode.type);
2305                 var allowSub      = populationRulesUtil.hasSubordinatesOfType(this.anchorNode.type);
2306                 locRadioGroup.items.map['sub'    + acGlobalDelimiter + componentId+ superiorContributionId].setDisabled(!allowSub);
2307                 locRadioGroup.items.map['sub'    + acGlobalDelimiter + componentId+ superiorContributionId].setVisible(allowSub);
2308                 locRadioGroup.items.map['append' + acGlobalDelimiter + componentId+ superiorContributionId].setDisabled(!allowSiblings);
2309                 locRadioGroup.items.map['before' + acGlobalDelimiter + componentId+ superiorContributionId].setDisabled(!allowSiblings);
2310                 locRadioGroup.items.map['after'  + acGlobalDelimiter + componentId+ superiorContributionId].setDisabled(!allowSiblings);
2311                 var allDisabled = false;
2312                 if (!allowSiblings) {
2313                     locRadioGroup.setValue('Sub');
2314                     if (locRadioGroup.items.map['sub' + acGlobalDelimiter + componentId+ superiorContributionId].disabled) {
2315                         allDisabled = true;
2316                     }
2317                 } else if (previousValue === 'Sub') {
2318                     locRadioGroup.setValue('Append');
2319                 }
2320                 this.textarearef.setDisabled(!allowSiblings && !allowSub);
2321                 this.handleLocationChange(true);
2322             },
2323             handleLocationChange: function (keepFocus) {
2324                 if (!this.anchorNode || this.editMode) {
2325                     this.getFormItem('name').focus();
2326                     return;
2327                 }
2328                 var placeValue = this.getFormItem('place').getValue().inputValue;
2329                 var subordinates = [];
2330                 if ("Append" === placeValue || "Before" === placeValue || "After" === placeValue) {
2331                     subordinates = populationRulesUtil.getSubordinatesOfType(this.anchorNode.parentNode.type);
2332                 } else if ("Sub" === placeValue) {
2333                     subordinates = populationRulesUtil.getSubordinatesOfType(this.anchorNode.type);
2334                 }
2335                 var dataList = [];
2336                 var defaultType = '';
2337                 var txtArea  = this.getFormItem('name');
2338                 var typeItem = this.getFormItem('type');
2339                 var prevType = typeItem.getValue();
2340                 var prevPrompt = txtArea.defaultPrompt;
2341                 var subordinate;
2342                 for (var i = 0; i < subordinates.length; i++) {
2343                     subordinate = subordinates[i];
2344                     dataList.push([
2345                         subordinate.subordinate_type,
2346                         subordinate.subordinate_type,
2347                         AC.util.StandardIcons.getImageURL(subordinate.normalIcon, true, 16)
2348                     ]);
2349                     if (i === 0) {
2350                         defaultType = subordinate.subordinate_type;
2351                         txtArea.defaultPrompt = subordinate.inputPrompt;
2352                     }
2353                     if (prevType === subordinate.subordinate_type) { // remember previously selected values
2354                         defaultType = prevType;
2355                         txtArea.defaultPrompt = prevPrompt;
2356                     }
2357                 }
2358                 var store = new Ext.data.ArrayStore({
2359                     id: 0,
2360                     fields: ['selectValue', 'displayText', 'iconURL'],
2361                     data: dataList
2362                 });
2363                 typeItem.bindStore(store);
2364                 if (!this.anchorNode.attributes.isInvalidType && ("Before" === placeValue || "After" === placeValue)) {
2365                     typeItem.setValue(this.anchorNode.type);
2366                 } else {
2367                     typeItem.setValue(defaultType);
2368                 }
2369                 typeItem.qtip = typeItem.getValue();
2370                 if (this.anchorNode.ui.anchor === document.activeElement){
2371                     this.handleTypeChange(false, true);
2372                 } else {
2373                     this.handleTypeChange(false, keepFocus);
2374                 }
2375             },
2376 
2377             /**
2378              * handling the "change" event in the "place" radiogroup
2379              *
2380              * @param radiogroup
2381              *          the radiogroup
2382              * @param checkedRadio
2383              *          the radio button that is checked in the radiogroup
2384              */
2385             handleLocationChangeEvent: function(radiogroup, checkedRadio){
2386                 this.handleLocationChange(false);
2387             },
2388             /**
2389              * Updates the icon and the input prompt in response to type changes.
2390              *
2391              * @param resetInput
2392              *          a boolean to indicate if the old content of the text area should be replaced by the input prompt
2393              * @param keepFocus
2394              *          a boolean to indicate whether to return the focus to the text area in the input panel.
2395              */
2396             handleTypeChange: function (resetInput, keepFocus) {
2397                 var iconURL = this.getFormItem('type').getIconURL();
2398                 if (iconURL.indexOf("scale=16") === -1) {
2399                     iconURL = iconURL + '&' + 'scale=16';
2400                 }
2401                 this.getFormItem('entryicon').setIcon(iconURL);
2402 
2403                 var txtArea = this.getFormItem('name');
2404                 var selectedType = this.getFormItem('type').getValue();
2405                 var newPrompt = populationRulesUtil.getRuleProperty(selectedType, null, 'inputPrompt');
2406                 if (newPrompt === null){
2407                     newPrompt = '';
2408                 }
2409                 txtArea.defaultPrompt = newPrompt;
2410                 if (resetInput === true) {
2411                     txtArea.setValue(newPrompt);
2412                     txtArea.addClass('x-form-textarea-prompt');
2413                     txtArea.removeClass('x-form-textarea-on-focus');
2414                     txtArea.originalValue = newPrompt;
2415                     txtArea.selectText(0, 0);
2416                 } else {
2417                     if (keepFocus) {
2418                         if (!txtArea.disabled && !txtArea.isDirty()) {
2419                             txtArea.setValue(newPrompt);
2420                             txtArea.addClass('x-form-textarea-prompt');
2421                             txtArea.originalValue = newPrompt;
2422                         }
2423                     } else {
2424                         if (txtArea.isDirty()) {
2425                             txtArea.selectText(txtArea.cursorStart, txtArea.cursorEnd);
2426                             txtArea.focus(false, true);
2427                         } else {
2428                             txtArea.setValue(newPrompt);
2429                             txtArea.addClass('x-form-textarea-prompt');
2430                             txtArea.originalValue = newPrompt;
2431                             txtArea.selectText(0, 0);
2432                             txtArea.focus(false, true);
2433                         }
2434                     }
2435                 }
2436             },
2437 
2438             /**
2439              * handling the "select" event in the "type" combobox
2440              *
2441              * @param combo
2442              *          the combobox
2443              * @param record
2444              *          the record of the combobox
2445              * @param index
2446              *          the index of the item selected in the combobox
2447              */
2448             handleTypeChangeEvent: function(combo, record, index){
2449                 this.handleTypeChange(false, false);
2450             },
2451 
2452             anchorNewContribution: function (msg) {
2453                 var newConId = msg.data.subordinateContributionId;
2454                 var outputPanel = this.ownerCt.outlinerPanel;
2455                 var t = outputPanel.maintreegrid;
2456                 var sm = t.selModel;
2457                 var rootNode = t.root;
2458 
2459                 var inputPanelInFocus, inputPanelEl = this.getFormItem('name').el;
2460                 if (inputPanelEl.dom == document.activeElement) {
2461                     inputPanelInFocus = true;
2462                 } else {
2463                     inputPanelInFocus = false;
2464                 }
2465 
2466                 rootNode.cascade(function () {
2467                     if (this.contributionId === newConId) {
2468                         if (inputPanelInFocus) {
2469                             t.innerBody.scrollChildIntoView(this.ui.elNode);
2470                             sm.clearSelections();
2471                             sm.anchorNode(this, true);
2472                             return false;
2473                         } else {
2474                             t.innerBody.scrollChildIntoView(this.ui.elNode);
2475                             sm.clearSelections();
2476                             sm.anchorNode(this);
2477                             return false;
2478                         }
2479                     }
2480                     return true;
2481                 });
2482 
2483                 // if this contribution is the only one inside the parent of a PC shell, trigger the child
2484                 if (rootNode.childNodes.length === 1) {
2485                     for (var i = 0; i < outputPanel.subComponentRenderers.length; i++) {
2486                         if (outputPanel.subComponentRenderers[i].type &&
2487                             outputPanel.subComponentRenderers[i].type === 'pcChildComponentRenderer') {
2488                             var anchoredNode = sm.anchoredNode;
2489                             var childTriggerCell = anchoredNode.getCellObject(t, anchoredNode, t.columns[i + 1]);
2490                             if (childTriggerCell) {
2491                                 childTriggerCell.launchSubCompWindow();
2492                                 // return cursor to parent's input panel?
2493                             }
2494                             break;
2495                         }
2496                     }
2497                 }
2498 
2499                 // for IYO
2500                 var txtArea = this.getFormItem('name');
2501                 var task = new Ext.util.DelayedTask(txtArea.calcLocaterArrow, txtArea);
2502                 task.delay(10);
2503             }
2504         });
2505     //####################################### end input panel assembly #####################################
2506 
2507     //####################################### outliner border panel ########################################
2508     var outlinerBorderPanel = new Ext.Panel({
2509         header: false,
2510         title: 'Outliner',
2511         layout: 'border',
2512         itemId: 'subcomponentContainer',
2513         superiorId: null,
2514         componentId: null,
2515         ctCls: 'x-panel-noborder',
2516         bodyStyle: 'background-color: white;',
2517         bodyBorder: false,
2518         collapseUnspecifiedIcon: collapseUnspecifiedIcon,
2519         lines: lines,
2520         lineNumbering: lineNumberEnable,
2521         outlinerPanel: outlinerPanel,
2522         items: isHeaderVisible ? [headerPanel, outlinerPanel, inputPanel] : [outlinerPanel, inputPanel],
2523         afterRender: function () {
2524             Ext.BoxComponent.superclass.afterRender.call(this);
2525             this.boxReady = true;
2526             this.setSize(this.width, this.height);
2527             if (this.x || this.y) {
2528                 this.setPosition(this.x, this.y);
2529             } else if (this.pageX || this.pageY) {
2530                 this.setPagePosition(this.pageX, this.pageY);
2531             }
2532 
2533             if (this.layout) {
2534                 if (typeof this.layout == 'string') {
2535                         this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig);
2536                 }
2537                 this.setLayout(this.layout);
2538 
2539                  if (this.activeItem !== undefined) {
2540                         var item = this.activeItem;
2541                         delete this.activeItem;
2542                         this.layout.setActiveItem(item);
2543                         return;
2544                  }
2545              }
2546              this.ownerCt.doLayout();
2547             if (this.actionCenterListener == null) {
2548                     this.actionCenterListener = new ActionCenterListener();
2549             }
2550             actionCenterAPI.startBatch();
2551             this.outlinerPanel.buildBaseTreeNode();
2552             actionCenterUtility.startClientMessageListener();
2553             actionCenterAPI.endBatch();
2554         },
2555         destroy: function () {
2556             if (inputPanel.editMode) {
2557                 inputPanel.updateContribution();
2558             } else {
2559                 var txt = inputPanel.getFormItem('name').getValue();
2560                 var match = false;
2561                 if (txt === inputPanel.getFormItem('name').defaultPrompt){
2562                     match = true;
2563                 }
2564                 //var matches = txt.match(inputPanel.getFormItem('name').defaultPrompt);
2565                 if (!match && txt != "") {
2566                     inputPanel.addContribution();
2567                 }
2568             }
2569             Ext.Panel.superclass.destroy.apply(this, arguments);
2570         },
2571         reload: function (newSuperiorContributionId) {
2572             outlinerPanel.reload(newSuperiorContributionId);
2573         },
2574         busyEl: null,
2575         listeners: {
2576             'swap': function () {
2577                 tagBar.getButton('sendbutton').disable();
2578                 if (!this.busyEl) {
2579                     // create an indicator indicating that the system is swapping
2580                     this.busyEl = Ext.fly(inputPanel.el).createChild({
2581                         html: 'Swapping...'
2582                     });
2583                     this.busyEl.addClass('loading-indicator');
2584                     this.busyEl.setStyle('z-index', '15000');
2585                     this.busyEl.setVisible(true);
2586                 }
2587 
2588                 var task = new Ext.util.DelayedTask(function() {
2589                     if (this.busyEl) {
2590                         Ext.destroy(this.busyEl); // remove the busy indicator
2591                         this.busyEl = null;
2592                     }
2593                 }, this);
2594                 task.delay(250); // display the busy indicator for quarter of a second
2595             }
2596         }
2597     });
2598     //####################################### end outliner border panel ####################################
2599 
2600     outlinerBorderPanel.superiorId = superiorContributionId;
2601     outlinerBorderPanel.componentId = componentId;
2602     var outlinerFitPanel = new Ext.Panel({// outermost panel of an outliner
2603         layout: 'fit',
2604         bodyStyle: 'background-color: white;',
2605         items: [outlinerBorderPanel],
2606         reload: function(newSuperiorContributionId) {
2607             outlinerBorderPanel.reload(newSuperiorContributionId);
2608         }
2609     });
2610     outlinerBorderPanel.doLayout();
2611     outlinerFitPanel.doLayout();
2612     this.getPanel = function () {
2613         return outlinerFitPanel;
2614     }
2615 
2616     if (target && target.length > 0) {
2617         var divConfig = {};
2618         divConfig.renderTo = target;
2619         divConfig.layout = 'fit';
2620             divConfig.items = [outlinerFitPanel];
2621             AC.pss.divViewportManager.push(new Ext.ux.DivViewport(divConfig));
2622         }
2623  };
2624 
2625 // Begin AC.pss.Button definition ///////////////////////////////////////////////////////////////////
2626 /**
2627  * Default constructor.
2628  *
2629  * @class The generic class for the Button of the PSS.
2630  * These buttons do not have minimum size and have their text and icon configurable.
2631  *
2632  * @extends Ext.Container
2633  *
2634  */
2635 AC.pss.Button = Ext.extend(Ext.Container,{
2636     layout:'hbox',
2637     layoutConfig: {
2638         align: 'stretch'
2639     },
2640     bodyBorder: false,
2641 
2642     /**
2643      * @config buttonIcon
2644      *         the id used to specify the icon for this button.
2645      *
2646      * @default null
2647      */
2648     buttonIcon: null,
2649     /**
2650      * @config buttonLabel
2651      *         the label for this button.
2652      *
2653      * @default null
2654      */
2655     buttonLabel: null,
2656     /**
2657      * initialize the button.
2658      *
2659      * @return void
2660      */
2661     initComponent: function(){
2662         var img, txt;
2663         var buttonIcon = this.initialConfig.buttonIcon;
2664         var buttonLabel = this.initialConfig.buttonLabel;
2665 
2666         if ((buttonIcon != null) && (buttonIcon.length > 5)) {
2667             img = AC.util.StandardIcons.getImageServlet() + buttonIcon +'&scale=16';
2668         } else {
2669             img = '';
2670         }
2671 
2672         if (buttonLabel !== null) {
2673             txt = buttonLabel;
2674         } else {
2675             txt = '';
2676         }
2677         this.items = new Ext.Button({
2678             flex: 1,
2679             icon: img,
2680             text: txt,
2681             scope: this,
2682             handler: function(){
2683                 this.handler();
2684             }
2685         });
2686         AC.pss.Button.superclass.initComponent.call(this);
2687     },
2688     /**
2689      * initialize the control in the PSS.
2690      *
2691      * @return void
2692      */
2693     handler: function(){
2694 
2695     }
2696 });
2697 /////////////////////////////////////////////////////////////////////////////////////////////////////
2698 
2699 // Begin AC.pss.Control definition //////////////////////////////////////////////////////////////////
2700 /**
2701  * Default constructor.
2702  *
2703  * @class The generic class for the Control of the PSS.
2704  *
2705  * @param componentId
2706  *
2707  * @param renderer
2708  *
2709  * @param subrenderer
2710  *
2711  * @param target
2712  *
2713  */
2714 AC.pss.Control = function (componentId, renderer, subrenderer, target) {
2715     this.componentId = componentId;
2716     this.renderer = renderer;
2717     this.subrenderer = subrenderer;
2718     this.target = target;
2719     this.configuration = renderer.getComponentConfiguration();
2720     this.initComponent();
2721 };
2722 
2723 AC.pss.Control.prototype = {
2724     /**
2725      * Check whether the control is set up in "display as button"(isPopup = true) or not.
2726      *
2727      * @default null
2728      */
2729     isPopup: null,
2730 
2731     /**
2732      * The pop up window of this control.
2733      *
2734      * @default null
2735      */
2736     subComponentWindow: null,
2737 
2738     /**
2739      * The title of the pop up window of this control.
2740      *
2741      * @default null
2742      */
2743     windowTitle: null,
2744 
2745     /**
2746      * Initialize the control in the PSS.
2747      *
2748      * @return void
2749      */
2750     initComponent: function() {
2751         this.windowTitle = this.configuration.getPropertyValue('windowTitle');
2752         if (this.isPopup === null) {
2753            this.isPopup = this.configuration.getPropertyValue("isPopup") === 'Y' ? true : false;
2754         }
2755         var content;
2756         var control = this.getControlPanel();
2757         if (this.isPopup){
2758             if (control){
2759                 this.initSubComponentWindow(control);
2760             }
2761             content = this.initButton();
2762         } else {
2763             content = control;
2764         }
2765         var divConfig = {
2766            renderTo: this.target,
2767            layout: 'fit',
2768            items: [content]
2769         };
2770         AC.pss.divViewportManager.push(new Ext.ux.DivViewport(divConfig));
2771     },
2772 
2773     /**
2774      * The handler for the button when the button is clicked.
2775      *
2776      * @return void
2777      */
2778     initButton: function() {
2779         var buttonIcon = this.configuration.getPropertyValue('icon');
2780         var buttonLabel = this.configuration.getPropertyValue('buttonLabel');
2781         var pssButton = new AC.pss.Button({
2782             buttonIcon: buttonIcon,
2783             buttonLabel: buttonLabel,
2784             controlObj: this,
2785             handler: function() {
2786                 this.controlObj.buttonHandler();
2787             }
2788         });
2789         return pssButton;
2790     },
2791 
2792     /**
2793      * The handler for the button when the button is clicked. It will display the pop up window by default
2794      *
2795      * @return void
2796      */
2797     buttonHandler: function() {
2798         if (this.subComponentWindow) {
2799             this.subComponentWindow.show();
2800         }
2801     },
2802 
2803     /**
2804      * Initialize the pop up window for the "Display as button" mode. The content of the control will be
2805      * attached to this window as a child item
2806      * @param {Object} control
2807      *                 the content of the control
2808      * @return void
2809      */
2810     initSubComponentWindow: function(control){
2811         var popupHeight = this.configuration.getPropertyValue('popupHeight');
2812         var popupWidth  = this.configuration.getPropertyValue('popupWidth');
2813         var browserDim = actionCenterUtility.getBrowserDimensions();
2814         this.subComponentWindow = new AC.Window({
2815             title: this.windowTitle ? this.windowTitle : '',
2816             layout: 'fit',
2817             height: browserDim.height * parseInt(popupHeight, 10) / 100,
2818             width:  browserDim.width  * parseInt(popupWidth,  10) / 100,
2819             items: [control]
2820         });
2821     },
2822 
2823     /**
2824      * Get the content of the control. This function is to be overidden in the subclasses
2825      *
2826      * @return {Object} control
2827      */
2828     getControlPanel: function() {
2829 
2830     }
2831 };
2832 
2833