Ticket #859: QControlBase.class.php

File QControlBase.class.php, 63.4 KB (added by mikederfler, 9 months ago)
Line 
1<?php
2        /**
3         * QControlBase is the base class of all QControls and shares their common properties
4         *
5         * Please note that not every control will utilize every single one of these properties.
6         * Keep in mind that Controls that are not Enabled or not Visible will not go through the form's
7         * Validation routine.
8         * All Controls must implement the following abstract functions:
9         * <ul>
10         *              <li>{@link QControlBase::GetControlHtml()}</li>
11         *              <li>{@link QControlBase::ParsePostData()}</li>
12         *              <li>{@link QControlBase::Validate()}</li>
13         * </ul>
14         *
15         * @package Controls
16         *
17         * @property string $AccessKey allows you to specify what Alt-Letter combination will automatically focus that control on the form
18         * @property boolean $ActionsMustTerminate
19         * @property mixed $ActionParameter This property allows you to pass your own parameters to the handlers for actions applied to this control.
20         *                       this can be a string or an object of type QJsClosure. If you pass in a QJsClosure it is possible to return javascript objects/arrays
21         *                       when using an ajax or server action.
22         * @property string $BackColor sets the CSS background-color of the control
23         * @property string $BorderColor sets the CSS border-color of the control
24         * @property string $BorderWidth sets the CSS border-width of the control
25         * @property string $BorderStyle is used to set CSS border-style by {@link QBorderStyle}
26         * @property mixed $CausesValidation flag says whether or not the form should run through its validation routine if this control has an action defined and is acted upon
27         * @property-read string $ControlId returns the id of this control
28         * @property string $CssClass sets or returns the CSS class for this control
29         * @property string $Cursor is used to set CSS cursor property by {@link QCursor}
30         * @property boolean $Display shows or hides the control using the CSS display property.  In either case, the control is still rendered on the page. See the Visible property if you wish to not render a control.
31         * @property string $DisplayStyle is used to set CSS display property by {@link QDisplayStyle}
32         * @property boolean $Enabled specifies whether or not this is enabled (it will grey out the control and make it inoperable if set to true)
33         * @property boolean $FontBold sets the font bold or normal
34         * @property boolean $FontItalic sets the Font italic or normal
35         * @property string $FontNames sets the name of used fonts
36         * @property boolean $FontOverline
37         * @property string $FontSize sets the font-size of the control
38         * @property boolean $FontStrikeout 
39         * @property boolean $FontUnderline sets the font underlined
40         * @property string $ForeColor sets the forecolor of the control (like fontcolor)
41         * @property-read QForm $Form returns the parent form object
42         * @property-read string $FormAttributes
43         * @property string $Height
44         * @property string $HtmlAfter HTML that is shown after the control {@link QControl::RenderWithName}
45         * @property string $HtmlBefore HTML that is shown before the control {@link QControl::RenderWithName}
46         * @property string $Instructions instructions that is shown next to the control's name label {@link QControl::RenderWithName}
47         * @property-read string $JavaScripts
48         * @property string $Left CSS left property
49         * @property-read boolean $Modified indicates if the control has been changed. Used to tell Qcubed to rerender the control or not (Ajax calls).
50         * @property boolean $Moveable
51         * @property boolean $Resizable
52         * @property string $Name sets the Name of the Control (see {@link QControl::RenderWithName})
53         * @property-read boolean $OnPage is true if the control is connected to the form
54         * @property integer $Opacity sets the opacity of the control (0-100)
55         * @property string $Overflow is used to set CSS overflow property by {@link QOverflow}
56         * @property-read QForm|QControl $ParentControl returns the parent control
57         * @property string $Position is used to set CSS position property by {@link QPosition}
58         * @property-read boolean $Rendered
59         * @property-read boolean $Rendering
60         * @property-read string $RenderMethod carries the name of the function, which were initially used for rendering
61         * @property boolean $Required specifies whether or not this is required (will cause a validation error if the form is trying to be validated and this control is left blank)
62         * @property-read string $StyleSheets
63         * @property integer $TabIndex specifies the index/tab order on a form
64         * @property string $ToolTip specifies the text to be displayed when the mouse is hovering over the control
65         * @property string $Top
66         * @property-read string $ValidationError is the string that contains the validation error (if applicable) or will be blank if (1) the form did not undergo its validation routine or (2) this control had no error
67         * @property boolean $Visible specifies whether or not the control should be rendered in the page.  This is in contrast to Display, which will just hide the control via CSS styling.
68         * @property string $Warning is warning text (looks like an error, but it can be user defined) that will be shown next to the control's name label {@link QControl::RenderWithName}
69         * @property string $Width
70         * @property boolean $UseWrapper defaults to true
71         * @property-read boolean $WrapperModified
72         * @property string $WrapperCssClass
73         */
74        abstract class QControlBase extends QBaseClass {
75                ///////////////////////////
76                // Private Member Variables
77                ///////////////////////////
78
79                // APPEARANCE
80                protected $strBackColor = null;
81                protected $strBorderColor = null;
82                protected $strBorderStyle = QBorderStyle::NotSet;
83                protected $strBorderWidth = null;
84                protected $strCssClass = null;
85                protected $blnDisplay = true;
86                protected $strDisplayStyle = QDisplayStyle::NotSet;
87                protected $blnFontBold = false;
88                protected $blnFontItalic = false;
89                protected $strFontNames = null;
90                protected $blnFontOverline = false;
91                protected $strFontSize = null;
92                protected $blnFontStrikeout = false;
93                protected $blnFontUnderline = false;
94                protected $strForeColor = null;
95                protected $intOpacity = null;
96
97                // BEHAVIOR
98                protected $strAccessKey = null;
99                protected $mixCausesValidation = false;
100                protected $strCursor = QCursor::NotSet;
101                protected $blnEnabled = true;
102                protected $blnRequired = false;
103                protected $intTabIndex = 0;
104                protected $strToolTip = null;
105                protected $strValidationError = null;
106                protected $blnVisible = true;
107                protected $strPreferedRenderMethod = 'Render';
108       
109                // LAYOUT
110                protected $strHeight = null;
111                protected $strWidth = null;
112
113                protected $strHtmlBefore = null;
114                protected $strHtmlAfter = null;
115                protected $strInstructions = null;
116                protected $strWarning = null;
117
118                protected $strOverflow = QOverflow::NotSet;
119                protected $strPosition = QPosition::NotSet;
120                protected $strTop = null;
121                protected $strLeft = null;
122
123                protected $objDraggable = null;
124                protected $objResizable = null;
125                protected $objDroppable = null;
126
127                // MISC
128                protected $strControlId;
129                protected $objForm = null;
130                protected $objParentControl = null;
131                protected $objChildControlArray = array();
132                protected $strName = null;
133                protected $blnRendered = false;
134                protected $blnRendering = false;
135                protected $blnOnPage = false;
136                protected $blnModified = false;
137                protected $blnWrapperModified = false;
138                protected $strRenderMethod;
139                protected $strCustomAttributeArray = null;
140                protected $strCustomStyleArray = null;
141                protected $objActionArray = array();
142                protected $mixActionParameter = null;
143                protected $strWrapperCssClass = null;
144                protected $blnUseWrapper = true;
145
146                // SETTINGS
147                protected $strJavaScripts = null;
148                protected $strStyleSheets = null;
149                protected $strFormAttributes = null;
150                protected $blnActionsMustTerminate = false;
151                protected $blnIsBlockElement = false;
152
153                //////////
154                // Methods
155                //////////
156                /**
157                 * Creates a QControlBase object
158                 *
159                 * This constructor will generally not be used to create a QControlBase object.  Instead it is used by the
160                 * classes which extend the class.  Only the parent object parameter is required.  If the option strControlId
161                 * parameter is not used, QCubed will generate the id.
162                 *
163                 * @param QControl|QForm $objParentObject
164                 * @param string $strControlId
165                 *              optional id of this Control. In html, this will be set as the value of the id attribute. The id can only
166                 *    contain alphanumeric characters.  If this parameter is not passed, QCubed will generate the id
167                 */
168                public function __construct($objParentObject, $strControlId = null) {
169                        if ($objParentObject instanceof QForm)
170                                $this->objForm = $objParentObject;
171                        else if ($objParentObject instanceof QControl) {
172                                $this->objParentControl = $objParentObject;
173//                              $this->objParentControl->blnModified = true;
174                                $this->objForm = $objParentObject->Form;
175                        } else
176                                throw new QCallerException('ParentObject must be either a QForm or QControl object');
177
178                        if (strlen($strControlId) == 0)
179                                $this->strControlId = $this->objForm->GenerateControlId();
180                        else {
181                                // Verify ControlId is only AlphaNumeric Characters
182                                if (ctype_alnum($strControlId))
183                                        $this->strControlId = $strControlId;
184                                else
185                                        throw new QCallerException('ControlIDs must be only alphanumeric chacters: ' . $strControlId);
186                        }
187                        try {
188                                $this->objForm->AddControl($this);
189                                if ($this->objParentControl)
190                                        $this->objParentControl->AddChildControl($this);
191                        } catch (QCallerException $objExc) {
192                                $objExc->IncrementOffset();
193                                throw $objExc;
194                        }
195                }
196
197                public static function CreatePersistent($strClassName, $objParentObject, $strControlId) {
198                        if ($objParentObject instanceof QForm) {
199                                $objForm = $objParentObject;
200                                $objParentControl = null;
201                        } else if ($objParentObject instanceof QControl) {
202                                $objForm = $objParentObject->Form;
203                                $objParentControl = $objParentObject;
204                        } else
205                                throw new QCallerException('Parent Object must be a QForm or QControl');
206
207                        if (array_key_exists($objForm->FormId . '_' . $strControlId, $_SESSION) && $_SESSION[$objForm->FormId . '_' . $strControlId]) {
208                                $objToReturn = unserialize($_SESSION[$objForm->FormId . '_' . $strControlId]);
209                                $objToReturn->objParentControl = $objParentControl;
210                                $objToReturn->objForm = $objForm;
211                                try {
212                                        $objToReturn->objForm->AddControl($objToReturn);
213                                        if ($objToReturn->objParentControl)
214                                                $objToReturn->objParentControl->AddChildControl($objToReturn);
215                                } catch (QCallerException $objExc) {
216                                        $objExc->IncrementOffset();
217                                        throw $objExc;
218                                }
219                        } else {
220                                $objToReturn = new $strClassName($objParentObject, $strControlId);
221                        }
222
223                        $objForm->PersistControl($objToReturn);
224                        return $objToReturn;
225                }
226
227                protected function PersistPrepare() {
228                        $this->objForm = null;
229                        $this->objParentControl = null;
230                        $this->objActionArray = array();
231                        $this->objChildControlArray = array();
232                        $this->blnRendered = null;
233                        $this->blnRendering = null;
234                        $this->blnOnPage = null;
235                        $this->blnModified = null;
236                        $this->mixCausesValidation = null;
237                }
238                public function Persist() {
239                        $objControl = clone($this);
240                        $objControl->PersistPrepare();
241                        $_SESSION[$this->objForm->FormId . '_' . $this->strControlId] = serialize($objControl);
242                }
243
244                /**
245                 * Adds a control as a child of this control.
246                 *
247                 * @param QControl $objControl the control to add
248                 */
249                public function AddChildControl(QControl $objControl) {
250                        $this->blnModified = true;
251                        $this->objChildControlArray[$objControl->ControlId] = $objControl;
252                        $objControl->objParentControl = $this;
253                }
254
255                /**
256                 * Returns all child controls as an array
257                 *
258                 * @param boolean $blnUseNumericIndexes
259                 * @return array an array of QControls
260                 */
261                public function GetChildControls($blnUseNumericIndexes = true) {
262                        if ($blnUseNumericIndexes) {
263                                $objToReturn = array();
264                                foreach ($this->objChildControlArray as $objChildControl)
265                                        array_push($objToReturn, $objChildControl);
266                                return $objToReturn;
267                        } else
268                                return $this->objChildControlArray;
269                }
270
271                /**
272                 * Returns the child control with the given id
273                 * @param string $strControlId
274                 * @return QControl
275                 */
276                public function GetChildControl($strControlId) {
277                        if (array_key_exists($strControlId, $this->objChildControlArray))
278                                return $this->objChildControlArray[$strControlId];
279                        else
280                                return null;
281                }
282
283                /**
284                 * Removes all child controls
285                 * @param boolean $blnRemoveFromForm
286                 */
287                public function RemoveChildControls($blnRemoveFromForm) {
288                        foreach ($this->objChildControlArray as $objChildControl) {
289                                $this->RemoveChildControl($objChildControl->ControlId, $blnRemoveFromForm);
290                        }
291                }
292
293                /**
294                 * Removes the child control with the given id
295                 * @param string $strControlId
296                 * @param boolean $blnRemoveFromForm should the control be removed from the form, too?
297                 */
298                public function RemoveChildControl($strControlId, $blnRemoveFromForm) {
299                        $this->blnModified = true;
300                        if (array_key_exists($strControlId, $this->objChildControlArray)) {
301                                $objChildControl = $this->objChildControlArray[$strControlId];
302                                $objChildControl->objParentControl = null;
303                                unset($this->objChildControlArray[$strControlId]);
304
305                                if ($blnRemoveFromForm)
306                                        $this->objForm->RemoveControl($objChildControl->ControlId);
307                        }
308                }
309
310                /**
311                 * Adds an action to the control
312                 * @param QEvent $objEvent
313                 * @param QAction $objAction
314                 */
315                public function AddAction($objEvent, $objAction) {
316                        if (!($objEvent instanceof QEvent)) {
317                                throw new QCallerException('First parameter of AddAction is expecting an object of type QEvent');
318                        }
319
320                        if (!($objAction instanceof QAction)) {
321                                throw new QCallerException('Second parameter of AddAction is expecting an object of type QAction');
322                        }
323
324                        // Modified
325                        $this->blnModified = true;
326
327                        // Store the Event object in the Action object
328                        if ($objAction->Event) {
329                                //this Action is in use -> clone it
330                                $objAction = clone($objAction);
331                        }
332                        $objAction->Event = $objEvent;
333
334                        // Pull out the Event Name
335                        $strEventName = $objEvent->EventName;
336
337                        if (!array_key_exists($strEventName, $this->objActionArray))
338                                $this->objActionArray[$strEventName] = array();
339                        array_push($this->objActionArray[$strEventName], $objAction);
340                }
341
342                /**
343                 * Adds an array of actions to the control
344                 * @param QEvent $objEvent
345                 * @param array $objActionArray
346                 */
347                public function AddActionArray($objEvent, $objActionArray) {
348                        if (!($objEvent instanceof QEvent)) {
349                                throw new QCallerException('First parameter of AddAction is expecting on object of type QEvent');
350                        }
351
352                        foreach ($objActionArray as $objAction) {
353                                $objAction = clone($objAction);
354                                $this->AddAction($objEvent, $objAction);
355                        }
356                }
357
358                /**
359                 * Removes all events for a given event name.
360                 *
361                 * Be sure and use a QFooEvent::EventName constant here
362                 * (QClickEvent::EventName, for example).
363                 *
364                 * @param string $strEventName
365                 */
366                public function RemoveAllActions($strEventName) {
367                        // Modified
368                        $this->blnModified = true;
369
370                        $this->objActionArray[$strEventName] = array();
371                }
372
373                /**
374                 * Returns all actions that are connected with specific events
375                 * @param string $strEventType
376                 *  the type of the event. Be sure and use a
377                 *  QFooEvent::EventName here. (QClickEvent::EventName, for example)
378                 * @param $strActionType if given only actions of this type will be
379                 *  returned
380                 * @return array
381                 */
382                public function GetAllActions($strEventType, $strActionType = null) {
383                        $objArrayToReturn = array();
384                        if ($this->objActionArray) foreach ($this->objActionArray as $objActionArray) {
385                                foreach ($objActionArray as $objAction)
386                                        if (get_class($objAction->Event) == $strEventType) {
387                                                if ((!$strActionType) ||
388                                                        ($objAction instanceof $strActionType))
389                                                        array_push($objArrayToReturn, $objAction);
390                                        }
391                        }
392
393                        return $objArrayToReturn;
394                }
395
396                /**
397                 * Sets one custom attribute
398                 *
399                 * Custom Attributes refers to the html name-value pairs that can be rendered within the control that are not
400                 * covered by an explicit method. For example, on a textbox, you can render any number of additional name-value
401                 * pairs, to assign additional javascript actions, additional formatting, etc.
402                 * <code>
403                 * <?php
404                 * $txtTextbox = new Textbox("txtTextbox");
405                 * $txtTextbox->SetCustomAttribute("onfocus", "alert('You are about to edit this field');");
406                 * $txtTextbox->SetCustomAttribute("nowrap", "nowrap");
407                 * $txtTextbox->SetCustomAttribute("blah", "foo");
408                 * ?>
409                 * </code>
410                 * Will render:
411                 * <code>
412                 *   <input type="text" ...... onfocus="alert('You are about to edit this field');" nowrap="nowrap" blah="foo" />
413                 * </code>
414                 *
415                 * @param string $strName
416                 * @param string $strValue
417                 */
418                public function SetCustomAttribute($strName, $strValue) {
419                        $this->blnModified = true;
420                        if (!is_null($strValue))
421                                $this->strCustomAttributeArray[$strName] = $strValue;
422                        else {
423                                $this->strCustomAttributeArray[$strName] = null;
424                                unset($this->strCustomAttributeArray[$strName]);
425                        }
426                }
427
428                /**
429                 * Returns the value of a custom attribute
430                 * @param string $strName
431                 * @return string
432                 */
433                public function GetCustomAttribute($strName) {
434                        if ((is_array($this->strCustomAttributeArray)) && (array_key_exists($strName, $this->strCustomAttributeArray)))
435                                return $this->strCustomAttributeArray[$strName];
436                        else
437                                throw new QCallerException(sprintf("Custom Attribute does not exist in Control '%s': %s", $this->strControlId, $strName));
438                }
439
440                /**
441                 * Removes the given custom attribute
442                 * @param string $strName
443                 */
444                public function RemoveCustomAttribute($strName) {
445                        $this->blnModified = true;
446                        if ((is_array($this->strCustomAttributeArray)) && (array_key_exists($strName, $this->strCustomAttributeArray))) {
447                                $this->strCustomAttributeArray[$strName] = null;
448                                unset($this->strCustomAttributeArray[$strName]);
449                        } else
450                                throw new QCallerException(sprintf("Custom Attribute does not exist in Control '%s': %s", $this->strControlId, $strName));
451                }
452
453                /**
454                 * Adds a custom style property/value to the html style attribute
455                 *
456                 * Sets a custom css property. For example:
457                 * <code>
458                 * <?php
459                 * $txtTextbox = new Textbox("txtTextbox");
460                 * $txtTextbox->SetCustomStyle("white-space", "nowrap");
461                 * $txtTextbox->SetCustomStyle("margin", "10px");
462                 * ?>
463                 * </code>
464                 * Will render:
465                 * <code>
466                 *              <input type="text" ...... style="white-space:nowrap;margin:10px" />
467                 * </code>
468                 *
469                 * @param string $strName
470                 * @param string $strValue
471                 */
472                public function SetCustomStyle($strName, $strValue) {
473                        $this->blnModified = true;
474                        if (!is_null($strValue))
475                                $this->strCustomStyleArray[$strName] = $strValue;
476                        else {
477                                $this->strCustomStyleArray[$strName] = null;
478                                unset($this->strCustomStyleArray[$strName]);
479                        }
480                }
481
482                /**
483                 * Returns the value of the given custom style
484                 * @param string $strName
485                 * @return string
486                 */
487                public function GetCustomStyle($strName) {
488                        if ((is_array($this->strCustomStyleArray)) && (array_key_exists($strName, $this->strCustomStyleArray)))
489                                return $this->strCustomStyleArray[$strName];
490                        else
491                                throw new QCallerException(sprintf("Custom Style does not exist in Control '%s': %s", $this->strControlId, $strName));
492                }
493
494                /**
495                 * Deletes the given custom style
496                 * @param string $strName
497                 */
498                public function RemoveCustomStyle($strName) {
499                        $this->blnModified = true;
500                        if ((is_array($this->strCustomStyleArray)) && (array_key_exists($strName, $this->strCustomStyleArray))) {
501                                $this->strCustomStyleArray[$strName] = null;
502                                unset($this->strCustomStyleArray[$strName]);
503                        } else
504                                throw new QCallerException(sprintf("Custom Style does not exist in Control '%s': %s", $this->strControlId, $strName));
505                }
506
507                public function AddJavascriptFile($strJsFileName) {
508                        if($this->strJavaScripts) {
509                                $this->strJavaScripts .= ','.$strJsFileName;
510                        } else {
511                                $this->strJavaScripts = $strJsFileName;
512                        }
513                }
514
515                public function AddPluginJavascriptFile($strPluginName, $strJsFileName) {
516                        // Relative path based on the path of the core JS files
517                        $this->AddJavascriptFile("../../plugins/" . $strPluginName . "/js/" . $strJsFileName);
518                }
519
520                public function AddCssFile($strCssFileName) {
521                        if($this->strStyleSheets) {
522                                $this->strStyleSheets .= ','.$strCssFileName;
523                        } else {
524                                $this->strStyleSheets = $strCssFileName;
525                        }
526                }
527
528                public function AddPluginCssFile($strPluginName, $strCssFileName) {
529                        // Relative path based on the path of the core JS files
530                        $this->AddCssFile("../../plugins/" . $strPluginName . "/css/" . $strCssFileName);
531                }
532
533                /**
534                 * This will add a CssClass name to the CssClass property (if it does not yet exist),
535                 * updating the CssClass property accordingly.
536                 * @param string $strCssClassName
537                 */
538                public function AddCssClass($strCssClassName) {
539                        $blnAdded = false;
540                        $strNewCssClass = '';
541                        $strCssClassName = trim($strCssClassName);
542
543                        foreach (explode(' ', $this->strCssClass) as $strCssClass)
544                                if ($strCssClass = trim($strCssClass)) {
545                                        if ($strCssClass == $strCssClassName)
546                                                $blnAdded = true;
547                                        $strNewCssClass .= $strCssClass . ' ';
548                                }
549                        if (!$blnAdded)
550                                $this->CssClass = $strNewCssClass . $strCssClassName;
551                        else
552                                $this->CssClass = trim($strNewCssClass);
553                }
554
555                /**
556                 * This will remove a CssClass name from the CssClass property (if it exists),
557                 * updating the CssClass property accordingly.
558                 * @param string $strCssClassName
559                 */
560                public function RemoveCssClass($strCssClassName) {
561                        $strNewCssClass = '';
562                        $strCssClassName = trim($strCssClassName);
563                        foreach (explode(' ', $this->strCssClass) as $strCssClass)
564                                if ($strCssClass = trim($strCssClass)) {
565                                        if ($strCssClass != $strCssClassName)
566                                                $strNewCssClass .= $strCssClass . ' ';
567                                }
568                        $this->CssClass = trim($strNewCssClass);
569                }
570
571                /**
572                 * ParsePostData parses the value of this control from FormState
573                 *
574                 * This abstract method must be implemented by all controls.
575                 *
576                 * When utilizing formgen, the programmer should never access form variables directly (e.g.
577                 * via the $_FORM array). It can be assumed that at *ANY* given time, a control's
578                 * values/properties will be "up to date" with whatever the webuser has entered in.
579                 *
580                 * When a Form is Created via Form::Create(string), the form will go through to check and
581                 * see if it is a first-run of a form, or if it is a post-back.  If it is a postback, it
582                 * will go through its own private array of controls and call ParsePostData on EVERY control
583                 * it has.  Each control is responsible for "knowing" how to parse the $_POST data to update
584                 * its own values/properties based on what was returned to via the postback.
585                 */
586                abstract public function ParsePostData();
587
588
589                /**
590                 * Returns all attributes in the correct HTML format
591                 *
592                 * This is utilized by Render methods to display various name-value HTML attributes for the
593                 * control.
594                 *
595                 * ControlBase's implementation contains the very-basic set of HTML attributes... it is expected
596                 * that most subclasses will extend this method's functionality to add Control-specific HTML
597                 * attributes (e.g. textbox will likely add the maxlength html attribute, etc.)
598                 *
599                 * @param boolean $blnIncludeCustom
600                 * @param boolean $blnIncludeAction
601                 * @return string
602                 */
603                public function GetAttributes($blnIncludeCustom = true, $blnIncludeAction = true) {
604                        $blnIncludeAction = false;
605                        $strToReturn = "";
606
607                        if (!$this->blnEnabled)
608                                $strToReturn .= 'disabled="disabled" ';
609                        if ($this->intTabIndex)
610                                $strToReturn .= sprintf('tabindex="%s" ', $this->intTabIndex);
611                        if ($this->strToolTip)
612                                $strToReturn .= sprintf('title="%s" ', QApplication::HtmlEntities($this->strToolTip));
613                        if ($this->strCssClass)
614                                $strToReturn .= sprintf('class="%s" ', $this->strCssClass);
615                        if ($this->strAccessKey)
616                                $strToReturn .= sprintf('accesskey="%s" ', $this->strAccessKey);
617
618                        if ($blnIncludeCustom)
619                                $strToReturn .= $this->GetCustomAttributes();
620
621                        if ($blnIncludeAction)
622                                $strToReturn .= $this->GetActionAttributes();
623
624                        return $strToReturn;
625                }
626
627                /**
628                 * Returns the custom attributes HTML formatted
629                 *
630                 * All attributes will be returned as concatened the string of the form
631                 * key1="value1" key2="value2"
632                 *
633                 * @return string
634                 */
635                public function GetCustomAttributes() {
636                        $strToReturn = '';
637                        if ($this->strCustomAttributeArray)
638                                foreach ($this->strCustomAttributeArray as $strKey => $strValue) {
639                                        $strToReturn .= sprintf('%s="%s" ', $strKey, $strValue);
640                                }
641
642                        return $strToReturn;
643                }
644
645                /**
646                 * Returns all action attributes
647                 *
648                 * @return string
649                 */
650                public function GetActionAttributes() {
651                        $strToReturn = '';
652                        foreach ($this->objActionArray as $strEventName => $objActions)
653                                $strToReturn .= $this->GetJavaScriptForEvent($strEventName);
654                        return $strToReturn;
655                }
656
657
658                public function GetJavaScriptForEvent($strEventName) {
659                        return QAction::RenderActions($this, $strEventName, $this->objActionArray[$strEventName]);
660                }
661
662                /**
663                 * Returns all style-attributes
664                 *
665                 * Similar to GetAttributes, but specifically for CSS name/value pairs that will render
666                 * within a control's HTML "style" attribute
667                 *
668                 * <code>
669                 * <?php
670                 * $txtTextbox = new Textbox("txtTextbox");
671                 * $txtTextbox->SetCustomStyle("white-space", "nowrap");
672                 * $txtTextbox->SetCustomStyle("margin", "10px");
673                 * $txtTextBox->Height = 20;
674                 * $txtTextBox->GetStyleAttributes();
675                 * ?>
676                 * will return:
677                 * white-space:nowrap;margin:10px;height:20px;
678                 *
679                 * @return string
680                 */
681                public function GetStyleAttributes() {
682                        $strToReturn = "";
683
684                        if ($this->strWidth) {
685                                if (is_numeric($this->strWidth))
686                                        $strToReturn .= sprintf("width:%spx;", $this->strWidth);
687                                else
688                                        $strToReturn .= sprintf("width:%s;", $this->strWidth);
689                        }
690                        if ($this->strHeight) {
691                                if (is_numeric($this->strHeight))
692                                        $strToReturn .= sprintf("height:%spx;", $this->strHeight);
693                                else
694                                        $strToReturn .= sprintf("height:%s;", $this->strHeight);
695                        }
696                        if ($this->blnUseWrapper) {
697                                if (($this->strDisplayStyle) && ($this->strDisplayStyle != QDisplayStyle::NotSet)) {
698                                        $strToReturn .= sprintf("display:%s;", $this->strDisplayStyle);
699                                }
700                        } else {
701                                if (($this->blnDisplay) &&($this->strDisplayStyle) && ($this->strDisplayStyle != QDisplayStyle::NotSet)) {
702                                        //only apply a display style if it should be displayed and a style is set
703                                        //in case of blnDisplay == false the "display:none;" is set in GetWrapperStyleAttributes
704                                        $strToReturn .= sprintf("display:%s;", $this->strDisplayStyle); 
705                                }
706                                $strToReturn .= $this->GetWrapperStyleAttributes();
707                        }
708                        if ($this->strForeColor)
709                                $strToReturn .= sprintf("color:%s;", $this->strForeColor);
710                        if ($this->strBackColor)
711                                $strToReturn .= sprintf("background-color:%s;", $this->strBackColor);
712                        if ($this->strBorderColor)
713                                $strToReturn .= sprintf("border-color:%s;", $this->strBorderColor);
714                        if (strlen(trim($this->strBorderWidth)) > 0) {
715                                $strBorderWidth = null;
716                                try {
717                                        $strBorderWidth = QType::Cast($this->strBorderWidth, QType::Integer);
718                                } catch (QInvalidCastException $objExc) {}
719
720                                if (is_null($strBorderWidth))
721                                        $strToReturn .= sprintf('border-width:%s;', $this->strBorderWidth);
722                                else
723                                        $strToReturn .= sprintf('border-width:%spx;', $this->strBorderWidth);
724
725                                if ((!$this->strBorderStyle) || ($this->strBorderStyle == QBorderStyle::NotSet))
726                                        // For "No Border Style" -- apply a "solid" style because width is set
727                                                $strToReturn .= "border-style:solid;";
728                        }
729                        if (($this->strBorderStyle) && ($this->strBorderStyle != QBorderStyle::NotSet))
730                                $strToReturn .= sprintf("border-style:%s;", $this->strBorderStyle);
731
732                        if ($this->strFontNames)
733                                $strToReturn .= sprintf("font-family:%s;", $this->strFontNames);
734                        if ($this->strFontSize) {
735                                if (is_numeric($this->strFontSize))
736                                        $strToReturn .= sprintf("font-size:%spx;", $this->strFontSize);
737                                else
738                                        $strToReturn .= sprintf("font-size:%s;", $this->strFontSize);
739                        }
740                        if ($this->blnFontBold)
741                                $strToReturn .= "font-weight:bold;";
742                        if ($this->blnFontItalic)
743                                $strToReturn .= "font-style:italic;";
744
745                        $strTextDecoration = "";
746                        if ($this->blnFontUnderline)
747                                $strTextDecoration .= "underline ";
748                        if ($this->blnFontOverline)
749                                $strTextDecoration .= "overline ";
750                        if ($this->blnFontStrikeout)
751                                $strTextDecoration .= "line-through ";
752
753                        if ($strTextDecoration) {
754                                $strTextDecoration = trim($strTextDecoration);
755                                $strToReturn .= sprintf("text-decoration:%s;", $strTextDecoration);
756                        }
757
758                        if (($this->strCursor) && ($this->strCursor != QCursor::NotSet))
759                                $strToReturn .= sprintf("cursor:%s;", $this->strCursor);
760
761                        if (($this->strOverflow) && ($this->strOverflow != QOverflow::NotSet))
762                                $strToReturn .= sprintf("overflow:%s;", $this->strOverflow);
763
764                        if (!is_null($this->intOpacity)) {
765                                if (QApplication::IsBrowser(QBrowserType::InternetExplorer))
766                                        $strToReturn .= sprintf('filter:alpha(opacity=%s);', $this->intOpacity);
767                                else
768                                        $strToReturn .= sprintf('opacity:%s;', $this->intOpacity / 100.0);
769                        }
770                        if ($this->strCustomStyleArray) foreach ($this->strCustomStyleArray as $strKey => $strValue)
771                                $strToReturn .= sprintf('%s:%s;', $strKey, $strValue);
772
773                        return $strToReturn;
774                }
775
776                /**
777                 * Returns all wrapper-style-attributes
778                 *
779                 * Similar to GetStyleAttributes, but specifically for CSS name/value pairs that will render
780                 * within a wrapper's HTML "style" attribute
781                 *
782                 * @return string
783                 */
784                protected function GetWrapperStyleAttributes($blnIsBlockElement=false) {
785                        $strStyle = '';
786                        if (($this->strPosition) && ($this->strPosition != QPosition::NotSet))
787                                $strStyle .= sprintf('position:%s;', $this->strPosition);
788
789                        if (!$this->blnDisplay)
790                                $strStyle .= 'display:none;';
791                        else if ($blnIsBlockElement)
792                                $strStyle .= 'display:inline;';
793
794                        if (strlen(trim($this->strLeft)) > 0) {
795                                $strLeft = null;
796                                try {
797                                        $strLeft = QType::Cast($this->strLeft, QType::Integer);
798                                } catch (QInvalidCastException $objExc) {}
799
800                                if (is_null($strLeft))
801                                        $strStyle .= sprintf('left:%s;', $this->strLeft);
802                                else
803                                        $strStyle .= sprintf('left:%spx;', $this->strLeft);
804                        }
805
806                        if (strlen(trim($this->strTop)) > 0) {
807                                $strTop = null;
808                                try {
809                                        $strTop = QType::Cast($this->strTop, QType::Integer);
810                                } catch (QInvalidCastException $objExc) {}
811
812                                if (is_null($strTop))
813                                        $strStyle .= sprintf('top:%s;', $this->strTop);
814                                else
815                                        $strStyle .= sprintf('top:%spx;', $this->strTop);
816                        }
817                       
818                        return $strStyle;
819                }
820               
821                /**
822                 * RenderHelper should be called from all "Render" functions FIRST in order to check for and
823                 * perform attribute overides (if any).
824                 *
825                 * All render methods should take in an optional first boolean parameter blnDisplayOutput
826                 * (default to true), and then any number of attribute overrides.
827                 *
828                 * Any "Render" method (e.g. Render, RenderWithName, RenderWithError) should call the
829                 * RenderHelper FIRST in order to:
830                 * <ul>
831                 * <li>Check for and perform attribute overrides</li>
832                 * <li>Check to see if this control is "Visible".  If it is Visible=false, then
833                 *      the renderhelper will cause the method to immedaitely return</li>
834                 * </ul>
835                 *
836                 * Proper usage within the first line of any Render() method is:
837                 *      <code>$this->RenderHelper(func_get_args(), __FUNCTION__);</code>
838                 * See {@link QControl::RenderWithName()} as example.
839                 *
840                 * @param $mixParameterArray the parameters given to the render call
841                 * @param $strRenderMethod the method which has been used to render the
842                 *      control. This is important for ajax rerendering
843                 * @see QControlBase::RenderOutput()
844                 */
845                protected function RenderHelper($mixParameterArray, $strRenderMethod) {
846                        // Make sure the form is already "RenderBegun"
847                        if ((!$this->objForm) || ($this->objForm->FormStatus != QForm::FormStatusRenderBegun)) {
848                                if (!$this->objForm)
849                                        $objExc = new QCallerException('Control\'s form does not exist.  It could be that you are attempting to render after RenderEnd() has been called on the form.');
850                                else if ($this->objForm->FormStatus == QForm::FormStatusRenderEnded)
851                                        $objExc = new QCallerException('Control cannot be rendered after RenderEnd() has been called on the form.');
852                                else
853                                        $objExc = new QCallerException('Control cannot be rendered until RenderBegin() has been called on the form.');
854
855                                // Incremement because we are two-deep below the call stack
856                                // (e.g. the Render function call, and then this RenderHelper call)
857                                $objExc->IncrementOffset();
858                                throw $objExc;
859                        }
860
861                        // Make sure this hasn't yet been rendered
862                        if (($this->blnRendered) || ($this->blnRendering)) {
863                                $objExc = new QCallerException('This control has already been rendered: ' . $this->strControlId);
864
865                                // Incremement because we are two-deep below the call stack
866                                // (e.g. the Render function call, and then this RenderHelper call)
867                                $objExc->IncrementOffset();
868                                throw $objExc;
869                        }
870
871                        // Let's remember *which* render method was used to render this control
872                        $this->strRenderMethod = $strRenderMethod;
873
874                        // Apply any overrides (if applicable)
875                        if (count($mixParameterArray) > 0) {
876                                if (gettype($mixParameterArray[0]) != QType::String) {
877                                        // Pop the first item off the array
878                                        $mixParameterArray = array_reverse($mixParameterArray);
879                                        array_pop($mixParameterArray);
880                                        $mixParameterArray = array_reverse($mixParameterArray);
881                                }
882
883                                // Override
884                                try {
885                                        $this->OverrideAttributes($mixParameterArray);
886                                } catch (QCallerException $objExc) {
887                                        // Incremement Twice because we are two-deep below the call stack
888                                        // (e.g. the Render function call, and then this RenderHelper call)
889                                        $objExc->IncrementOffset();
890                                        $objExc->IncrementOffset();
891                                        throw $objExc;
892                                }
893                        }
894
895                        // Because we may be re-rendering a parent control, we need to make sure all "children" controls are marked as NOT being on the page.
896                        foreach ($this->GetChildControls() as $objChildControl)
897                                $objChildControl->blnOnPage = false;
898
899                        // Finally, let's specify that we have begun rendering this control
900                        $this->blnRendering = true;
901                }
902
903                protected function GetNonWrappedHtml() {}
904
905                /**
906                 * Sets focus to this control
907                 */
908                public function Focus() {
909                        QApplication::ExecuteJavaScript(sprintf('qc.getW("%s").focus();', $this->strControlId));
910                }
911
912                /**
913                 * Same as "Focus": Sets focus to this control
914                 */
915                public function SetFocus() {
916                        QApplication::ExecuteJavaScript(sprintf('qc.getW("%s").focus()', $this->strControlId));
917                }
918
919                /**
920                 * Let this control blink
921                 *
922                 * @param string $strFromColor start color
923                 * @param string $strToColor blink color
924                 */
925                public function Blink($strFromColor = '#ffff66', $strToColor = '#ffffff') {
926                        QApplication::ExecuteJavaScript(sprintf('qc.getW("%s").blink("%s", "%s");', $this->strControlId, $strFromColor, $strToColor));
927                }
928
929                /**
930                 * Returns all Javscript that needs to be executed after rendering of this control
931                 *
932                 * For any JavaScript calls that need to be made whenever this control is rendered or
933                 * re-rendered return here your custom javascript code.
934                 *
935                 * Remember to call $strToReturn = parent::GetEndScript if you want to have basic moveable support.
936                 *
937                 * @return string
938                 */
939                public function GetEndScript() {
940
941                        $strToReturn = $this->GetActionAttributes();
942
943                        if ($this->objResizable)
944                                $strToReturn = sprintf('%s; %s', $this->objResizable->GetControlJavaScript(), $strToReturn);
945
946                        if ($this->objDraggable)
947                                $strToReturn = sprintf('%s; %s', $this->objDraggable->GetControlJavaScript(), $strToReturn);
948
949                        if ($this->objDroppable)
950                                $strToReturn = sprintf('%s; %s', $this->objDroppable->GetControlJavaScript(), $strToReturn);
951
952                        return $strToReturn;
953                }
954
955                /**
956                 * For any HTML code that needs to be rendered at the END of the QForm when this control is
957                 * INITIALLY rendered.
958                 *
959                 * This function is never used throughout the whole framework. So it probably should be
960                 * deprecated. Only Call to this function is in QFormBase Line 1171.
961                 * @deprecated
962                 * @return unknown_type
963                 */
964                public function GetEndHtml() {}
965
966                /**
967                 * Refreshes the control
968                 *
969                 * If not yet rendered during this ajax event, will set the Modified variable to true.  This will
970                 * have the effect of forcing a refresh of this control when it is supposed to be rendered.
971                 * Otherwise, this will do nothing
972                 */
973                public function Refresh() {
974                        if ((!$this->blnRendered) && (!$this->blnRendering))
975                                $this->blnModified = true;
976                }
977
978                /**
979                 * RenderOutput should be the last call in your custom RenderMethod.
980                 *
981                 * RenderOutput wraps your content with valid divs and control-identifiers, echos your code
982                 * to the content buffer or simply returns it. See {@link QControlBase::RenderHelper()}.
983                 *
984                 * @param string $strOutput
985                 *                      Your html-code which should be given out
986                 * @param boolean $blnDisplayOutput
987                 *                      should it be given out, or just be returned?
988                 * @param boolean $blnForceAsBlockElement
989                 *                      should it be given out as a block element, regardless of its configured tag?
990                 * @return string
991                 */
992                protected function RenderOutput($strOutput, $blnDisplayOutput, $blnForceAsBlockElement = false, $strWrapperAttributes = '') {
993                        // First, let's mark this control as being rendered and is ON the Page
994                        $this->blnRendering = false;
995                        $this->blnRendered = true;
996                        $this->blnOnPage = true;
997
998                        $strWrapperStyle='';
999                        // Determine whether or not $strOutput is considered a XHTML "Block" Element
1000                        $blnIsBlockElement = $blnForceAsBlockElement || $this->blnIsBlockElement;
1001                        if($this->blnUseWrapper) {
1002                                // Check for Visibility
1003                                if (!$this->blnVisible)
1004                                        $strOutput = '';
1005
1006                                $strWrapperStyle = $this->GetWrapperStyleAttributes($blnIsBlockElement);
1007
1008                                if ($this->strWrapperCssClass)
1009                                        $strWrapperAttributes .= sprintf(' class="%s"', $this->strWrapperCssClass);
1010                        } else if (!$this->blnVisible) {
1011                                /*no wrapper is used + the control should not be visible
1012                                 *      --> render a span with the control id and display:none
1013                                 *  This allows us to change blnVisible to true in an Ajax call
1014                                 *  as the span will get replaced with the real control
1015                                 */
1016                                $strOutput = sprintf('<span id="%s" style="display:none;"></span>', $this->strControlId);
1017                        }
1018
1019                        switch ($this->objForm->CallType) {
1020                                case QCallType::Ajax:
1021                                        // If we have a ParentControl and the ParentControl has NOT been rendered, then output
1022                                        // as standard HTML
1023                                        if (($this->objParentControl) && ($this->objParentControl->Rendered || $this->objParentControl->Rendering)) {
1024                                                if ($strWrapperStyle)
1025                                                        $strWrapperStyle = sprintf('style="%s"', $strWrapperStyle);
1026                                                if($this->blnUseWrapper) {
1027                                                        if ($blnIsBlockElement)
1028                                                                $strOutput = sprintf('<div id="%s_ctl" %s%s>%s</div>%s', $this->strControlId, $strWrapperStyle, $strWrapperAttributes, $strOutput, $this->GetNonWrappedHtml());
1029                                                        else
1030                                                                $strOutput = sprintf('<span id="%s_ctl" %s%s>%s</span>%s', $this->strControlId, $strWrapperStyle, $strWrapperAttributes, $strOutput, $this->GetNonWrappedHtml());
1031                                                } else {
1032                                                        $strOutput = $strOutput . $this->GetNonWrappedHtml();
1033                                                }
1034                                        } else {
1035                                                // Otherwise, we are rendering as a top-level AJAX response
1036                                                // Surround Output HTML around CDATA tags
1037                                                $strOutput = QString::XmlEscape($strOutput);
1038                                                // use the wrapper attribute to pass in the special attribute data-hasrel (if no wrappers are used and RenderWithError or similar methods are called)
1039                                                $strOutput = sprintf('<control id="%s" %s>%s</control>', $this->strControlId,$strWrapperAttributes, $strOutput);
1040
1041                                                if (($this->blnWrapperModified) && ($this->blnVisible) && ($this->blnUseWrapper)) {
1042                                                        QApplication::ExecuteJavaScript(sprintf('w = qc.getW("%s"); w.style.cssText = "%stext-decoration:inherit;"; w.className = "%s";', $this->strControlId, $strWrapperStyle, $this->strWrapperCssClass));
1043                                                }
1044                                        }
1045                                        break;
1046
1047                                default:
1048                                        if ($strWrapperStyle)
1049                                                $strWrapperStyle = sprintf('style="%s"', $strWrapperStyle);
1050
1051                                        if ($this->blnUseWrapper) {
1052                                                if ($blnIsBlockElement)
1053                                                        $strOutput = sprintf('<div id="%s_ctl" %s%s>%s</div>%s', $this->strControlId, $strWrapperStyle, $strWrapperAttributes, $strOutput, $this->GetNonWrappedHtml());
1054                                                else
1055                                                        $strOutput = sprintf('<span id="%s_ctl" %s%s>%s</span>%s', $this->strControlId, $strWrapperStyle, $strWrapperAttributes, $strOutput, $this->GetNonWrappedHtml());
1056                                        } else {
1057                                                $strOutput = $strOutput . $this->GetNonWrappedHtml();
1058                                        }
1059                                        break;
1060                        }
1061
1062                        // Output or Return
1063                        if ($blnDisplayOutput)
1064                                print($strOutput);
1065                        else
1066                                return $strOutput;
1067                }
1068
1069                /**
1070                 * This method will render the control, itself, and will return the rendered HTML as a string
1071                 *
1072                 * As an abstract method, any class extending QControlBase must implement it.  This ensures that
1073                 * each control has its own specific html.
1074                 * @return string
1075                 */
1076                abstract protected function GetControlHtml();
1077
1078                /**
1079                 * This render method is the most basic render-method available.
1080                 *
1081                 * It will perform attribute overiding (if any) and will either display the rendered
1082                 * HTML (if blnDisplayOutput is true, which it is by default), or it will return the
1083                 * rendered HTML as a string.
1084                 *
1085                 * @param boolean $blnDisplayOutput render the control or return as string
1086                 * @return string
1087                 */
1088                public function Render($blnDisplayOutput = true) {
1089                        // Call RenderHelper
1090                        $this->RenderHelper(func_get_args(), __FUNCTION__);
1091
1092                        try {
1093                                $strOutput = sprintf('%s%s%s',
1094                                        $this->strHtmlBefore,
1095                                        $this->GetControlHtml(),
1096                                        $this->strHtmlAfter
1097                                );
1098                        } catch (QCallerException $objExc) {
1099                                $objExc->IncrementOffset();
1100                                throw $objExc;
1101                        }
1102
1103                        // Call RenderOutput, Returning its Contents
1104                        return $this->RenderOutput($strOutput, $blnDisplayOutput);
1105                }
1106
1107                /**
1108                 * RenderAjax will be called during an Ajax-Rerendering of the controls do to it being modified
1109                 * @param boolean $blnDisplayOutput render the control or return as string
1110                 * @return string
1111                 */
1112                public function RenderAjax($blnDisplayOutput = true) {
1113                        // Only render if this control has been modified at all
1114                        if ($this->blnModified) {
1115
1116                                // Render if (1) object has no parent or (2) parent was not rendered nor currently being rendered
1117                                if ((!$this->objParentControl) || ((!$this->objParentControl->Rendered) && (!$this->objParentControl->Rendering))) {
1118                                        $strRenderMethod = $this->strRenderMethod;
1119                                        if ($strRenderMethod)
1120                                                return $this->$strRenderMethod($blnDisplayOutput);
1121                                }
1122                        }
1123                }
1124
1125                /**
1126                 * Renders all Children
1127                 * @param boolean $blnDisplayOutput display output (echo out) or just return as string
1128                 * @return string
1129                 */
1130                protected function RenderChildren($blnDisplayOutput = true) {
1131                        $strToReturn = "";
1132
1133                        foreach ($this->GetChildControls() as $objControl) {
1134                                if (!$objControl->Rendered) {
1135                                        $renderMethod = $objControl->strPreferedRenderMethod;
1136                                        $strToReturn .= $objControl->$renderMethod($blnDisplayOutput);
1137                                }
1138                        }
1139
1140                        if ($blnDisplayOutput) {
1141                                print($strToReturn);
1142                                return null;
1143                        } else
1144                                return $strToReturn;
1145                }
1146
1147                /**
1148                 * This render method will render the control with additional output of
1149                 * any validation errors, that might occur
1150                 *
1151                 * @param boolean $blnDisplayOutput display output (echo out) or just return as string
1152                 * @return string
1153                 */
1154                public function RenderWithError($blnDisplayOutput = true) {
1155                        // Call RenderHelper
1156                        $this->RenderHelper(func_get_args(), __FUNCTION__);
1157
1158                        /*if we do not use a wrapper we have to ensure that the error element
1159                                gets removed on an ajax update.
1160                                ==> we pass a special attribute to the top level ajax response element
1161                                (called "control" <== created in RenderOutput)
1162                                If this attribute is present, all elements that have an attribute
1163                                data-rel="controlid_of_the_related_control" are removed before updating
1164                            the control --> no duplication of error/warning controls
1165                         */
1166                        $strWrapperAttributes = '';
1167                        $strDataRel = '';
1168                        if($this->blnUseWrapper == false) {
1169                                $strWrapperAttributes = "data-hasrel='1'";
1170                                $strDataRel = sprintf("data-rel='#%s' ", $this->strControlId);
1171                        }
1172                       
1173                        try {
1174                                $strOutput = $this->GetControlHtml();
1175
1176                                if ($this->strValidationError)
1177                                        $strOutput .= sprintf('<br %s/><span %sclass="warning">%s</span>', $strDataRel,$strDataRel,$this->strValidationError);
1178                                else if ($this->strWarning)
1179                                        $strOutput .= sprintf('<br %s/><span %sclass="warning">%s</span>', $strDataRel,$strDataRel,$this->strWarning);
1180                        } catch (QCallerException $objExc) {
1181                                $objExc->IncrementOffset();
1182                                throw $objExc;
1183                        }
1184
1185                        // Call RenderOutput, Returning its Contents
1186                        return $this->RenderOutput($strOutput, $blnDisplayOutput, false, $strWrapperAttributes);
1187                }
1188
1189
1190                /**
1191                 * Helper method to render the control using some other class/method.
1192                 *
1193                 * Useful for plugins that want to override the render behavior for the controls
1194                 * without modifying the control code.
1195                 */
1196                public function RenderExtensionRenderer($classname, $methodname, $args=array()){
1197                        $RenderExtensionInstance = new $classname;
1198                        return $RenderExtensionInstance->{$methodname}($args);
1199                }
1200
1201                /**
1202                 * Checks if this controls contains a valid value.
1203                 *
1204                 * This abstract method defines how a control should validate itself based on the value/
1205                 * properties it has. It should also include the handling of ensuring the "Required"
1206                 * requirements are obeyed if this control's "Required" flag is set to true.
1207                 *
1208                 * For Controls that can't realistically be "validated" (e.g. labels, datagrids, etc.),
1209                 * those controls should simply have Validate() return true.
1210                 *
1211                 * @return boolean
1212                 */
1213                abstract public function Validate();
1214
1215
1216
1217                // The following three methods are only intended to be called by code within the Form class.
1218                // It must be declared as public so that a form object can have access ot them, but it really should never be
1219                // called by user code.
1220                public function ResetFlags() {
1221                        $this->blnRendered = false;
1222                        $this->blnModified = false;
1223                        $this->blnWrapperModified = false;
1224                }
1225
1226                public function ResetOnPageStatus() {
1227                        $this->blnOnPage = false;
1228                }
1229
1230                public function MarkAsModified() {
1231                        $this->blnModified = true;
1232                }
1233
1234                public function MarkAsWrapperModified() {
1235                        $this->blnWrapperModified = true;
1236                }
1237
1238                public function MarkAsRendered() {
1239                        $this->blnRendered = true;
1240                }
1241
1242                public function SetForm($objForm) {
1243                        $this->objForm = $objForm;
1244                }
1245
1246                public function SetParentControl($objControl) {
1247                        // Mark this object as modified
1248                        $this->MarkAsModified();
1249
1250                        // Mark the old parent (if applicable) as modified
1251                        if ($this->objParentControl)
1252                                $this->objParentControl->RemoveChildControl($this->ControlId, false);
1253
1254                        // Mark the new parent (if applicable) as modified
1255                        if ($objControl)
1256                                $objControl->AddChildControl($this);
1257                }
1258
1259                public function ValidationReset() {
1260                        if (($this->strValidationError) || ($this->strWarning))
1261                                $this->blnModified = true;
1262                        $this->strValidationError = null;
1263                        $this->strWarning = null;
1264                }
1265
1266                public function VarExport($blnReturn = true) {
1267                        if ($this->objForm)
1268                                $this->objForm = $this->objForm->FormId;
1269                        if ($this->objParentControl)
1270                                $this->objParentControl = $this->objParentControl->ControlId;
1271                        if ($blnReturn)
1272                                return var_export($this, true);
1273                }
1274
1275                /**
1276                 * Used by jQuery UI wrapper controls to find the element on which to apply the jQuery function
1277                 *
1278                 * NOTE: Some controls that use jQuery will get wrapped with extra divs by the jQuery library.
1279                 * If such a control then gets replaced by Ajax, the jQuery effects will be deleted. To solve this,
1280                 * the corresponding QCubed control should set UseWrapper to true, attach the jQuery effect to
1281                 * the wrapper, and override this function to return the id of the wrapper. See QDialogBase.class.php for
1282                 * an exaple.
1283                 *
1284                 * @return string the DOM element id on which to apply the jQuery UI function
1285                 */
1286                public function getJqControlId() {
1287                        return $this->ControlId;
1288                }
1289
1290                /////////////////////////
1291                // Public Properties: GET
1292                /////////////////////////
1293                public function __get($strName) {
1294                        switch ($strName) {
1295                                // APPEARANCE
1296                                case "BackColor": return $this->strBackColor;
1297                                case "BorderColor": return $this->strBorderColor;
1298                                case "BorderStyle": return $this->strBorderStyle;
1299                                case "BorderWidth": return $this->strBorderWidth;
1300                                case "CssClass": return $this->strCssClass;
1301                                case "Display": return $this->blnDisplay;
1302                                case "DisplayStyle": return $this->strDisplayStyle;
1303                                case "FontBold": return $this->blnFontBold;
1304                                case "FontItalic": return $this->blnFontItalic;
1305                                case "FontNames": return $this->strFontNames;
1306                                case "FontOverline": return $this->blnFontOverline;
1307                                case "FontSize": return $this->strFontSize;
1308                                case "FontStrikeout": return $this->blnFontStrikeout;
1309                                case "FontUnderline": return $this->blnFontUnderline;
1310                                case "ForeColor": return $this->strForeColor;
1311                                case "Opacity": return $this->intOpacity;
1312
1313                                // BEHAVIOR
1314                                case "AccessKey": return $this->strAccessKey;
1315                                case "CausesValidation": return $this->mixCausesValidation;
1316                                case "Cursor": return $this->strCursor;
1317                                case "Enabled": return $this->blnEnabled;
1318                                case "Required": return $this->blnRequired;
1319                                case "TabIndex": return $this->intTabIndex;
1320                                case "ToolTip": return $this->strToolTip;
1321                                case "ValidationError": return $this->strValidationError;
1322                                case "Visible": return $this->blnVisible;
1323                                case "PreferedRenderMethod": return $this->strPreferedRenderMethod;
1324
1325                                // LAYOUT
1326                                case "Height": return $this->strHeight;
1327                                case "Width": return $this->strWidth;
1328                                case "HtmlBefore": return $this->strHtmlBefore;
1329                                case "HtmlAfter": return $this->strHtmlAfter;
1330                                case "Instructions": return $this->strInstructions;
1331                                case "Warning": return $this->strWarning;
1332
1333                                case "Overflow": return $this->strOverflow;
1334                                case "Position": return $this->strPosition;
1335                                case "Top": return $this->strTop;
1336                                case "Left": return $this->strLeft;
1337
1338                                case "Moveable": return $this->objDraggable && !$this->objDraggable->Disabled;
1339                                case "Resizable": return $this->objResizable && !$this->objResizable->Disabled;
1340                                case "Droppable": return $this->objDroppable && !$this->objDroppable->Disabled;;
1341                                case "DragObj": return $this->objDraggable;
1342                                case "ResizeObj": return $this->objResizable;
1343                                case "DropObj": return $this->objDroppable;
1344
1345                                // MISC
1346                                case "ControlId": return $this->strControlId;
1347                                case "Form": return $this->objForm;
1348                                case "ParentControl": return $this->objParentControl;
1349
1350                                case "Name": return $this->strName;
1351                                case "Rendered": return $this->blnRendered;
1352                                case "Rendering": return $this->blnRendering;
1353                                case "OnPage": return $this->blnOnPage;
1354                                case "RenderMethod": return $this->strRenderMethod;
1355                                case "Modified": return $this->blnModified;
1356                                case "WrapperModified": return $this->blnWrapperModified;
1357                                case "strActionParameter": //for backward compatibility
1358                                case "ActionParameter": return $this->mixActionParameter;
1359                                case "ActionsMustTerminate": return $this->blnActionsMustTerminate;
1360                                case "WrapperCssClass": return $this->strWrapperCssClass;
1361                                case "UseWrapper": return $this->blnUseWrapper;
1362
1363                                // SETTINGS
1364                                case "JavaScripts": return $this->strJavaScripts;
1365                                case "StyleSheets": return $this->strStyleSheets;
1366                                case "FormAttributes": return (array) $this->strFormAttributes;
1367
1368                                default:
1369                                        try {
1370                                                return parent::__get($strName);
1371                                        } catch (QCallerException $objExc) {
1372                                                $objExc->IncrementOffset();
1373                                                throw $objExc;
1374                                        }
1375                        }
1376                }
1377
1378                /////////////////////////
1379                // Public Properties: SET
1380                /////////////////////////
1381                public function __set($strName, $mixValue) {
1382                        $this->blnModified = true;
1383
1384                        switch ($strName) {
1385                                // APPEARANCE
1386                                case "BackColor":
1387                                        try {
1388                                                $this->strBackColor = QType::Cast($mixValue, QType::String);
1389                                                break;
1390                                        } catch (QInvalidCastException $objExc) {
1391                                                $objExc->IncrementOffset();
1392                                                throw $objExc;
1393                                        }
1394                                case "BorderColor":
1395                                        try {
1396                                                $this->strBorderColor = QType::Cast($mixValue, QType::String);
1397                                                break;
1398                                        } catch (QInvalidCastException $objExc) {
1399                                                $objExc->IncrementOffset();
1400                                                throw $objExc;
1401                                        }
1402                                case "BorderStyle":
1403                                        try {
1404                                                $this->strBorderStyle = QType::Cast($mixValue, QType::String);
1405                                                break;
1406                                        } catch (QInvalidCastException $objExc) {
1407                                                $objExc->IncrementOffset();
1408                                                throw $objExc;
1409                                        }
1410                                case "BorderWidth":
1411                                        try {
1412                                                $this->strBorderWidth = QType::Cast($mixValue, QType::String);
1413                                                break;
1414                                        } catch (QInvalidCastException $objExc) {
1415                                                $objExc->IncrementOffset();
1416                                                throw $objExc;
1417                                        }
1418                                case "CssClass":
1419                                        try {
1420                                                $this->strCssClass = QType::Cast($mixValue, QType::String);
1421                                                break;
1422                                        } catch (QInvalidCastException $objExc) {
1423                                                $objExc->IncrementOffset();
1424                                                throw $objExc;
1425                                        }
1426                                case "Display":
1427                                        try {
1428                                                $this->blnDisplay = QType::Cast($mixValue, QType::Boolean);
1429                                                $this->MarkAsWrapperModified();
1430                                                break;
1431                                        } catch (QInvalidCastException $objExc) {
1432                                                $objExc->IncrementOffset();
1433                                                throw $objExc;
1434                                        }
1435                                case "DisplayStyle":
1436                                        try {
1437                                                $this->strDisplayStyle = QType::Cast($mixValue, QType::String);
1438                                                if (($this->strDisplayStyle == QDisplayStyle::Block) ||
1439                                                        ($this->strDisplayStyle == QDisplayStyle::Inline))
1440                                                        $this->strDisplayStyle = $this->strDisplayStyle;
1441                                                break;
1442                                        } catch (QInvalidCastException $objExc) {
1443                                                $objExc->IncrementOffset();
1444                                                throw $objExc;
1445                                        }
1446                                case "FontBold":
1447                                        try {
1448                                                $this->blnFontBold = QType::Cast($mixValue, QType::Boolean);
1449                                                break;
1450                                        } catch (QInvalidCastException $objExc) {
1451                                                $objExc->IncrementOffset();
1452                                                throw $objExc;
1453                                        }
1454                                case "FontItalic":
1455                                        try {
1456                                                $this->blnFontItalic = QType::Cast($mixValue, QType::Boolean);
1457                                                break;
1458                                        } catch (QInvalidCastException $objExc) {
1459                                                $objExc->IncrementOffset();
1460                                                throw $objExc;
1461                                        }
1462                                case "FontNames":
1463                                        try {
1464                                                $this->strFontNames = QType::Cast($mixValue, QType::String);
1465                                                break;
1466                                        } catch (QInvalidCastException $objExc) {
1467                                                $objExc->IncrementOffset();
1468                                                throw $objExc;
1469                                        }
1470                                case "FontOverline":
1471                                        try {
1472                                                $this->blnFontOverline = QType::Cast($mixValue, QType::Boolean);
1473                                                break;
1474                                        } catch (QInvalidCastException $objExc) {
1475                                                $objExc->IncrementOffset();
1476                                                throw $objExc;
1477                                        }
1478                                case "FontSize":
1479                                        try {
1480                                                $this->strFontSize = QType::Cast($mixValue, QType::String);
1481                                                break;
1482                                        } catch (QInvalidCastException $objExc) {
1483                                                $objExc->IncrementOffset();
1484                                                throw $objExc;
1485                                        }
1486                                case "FontStrikeout":
1487                                        try {
1488                                                $this->blnFontStrikeout = QType::Cast($mixValue, QType::Boolean);
1489                                                break;
1490                                        } catch (QInvalidCastException $objExc) {
1491                                                $objExc->IncrementOffset();
1492                                                throw $objExc;
1493                                        }
1494                                case "FontUnderline":
1495                                        try {
1496                                                $this->blnFontUnderline = QType::Cast($mixValue, QType::Boolean);
1497                                                break;
1498                                        } catch (QInvalidCastException $objExc) {
1499                                                $objExc->IncrementOffset();
1500                                                throw $objExc;
1501                                        }
1502                                case "ForeColor":
1503                                        try {
1504                                                $this->strForeColor = QType::Cast($mixValue, QType::String);
1505                                                break;
1506                                        } catch (QInvalidCastException $objExc) {
1507                                                $objExc->IncrementOffset();
1508                                                throw $objExc;
1509                                        }
1510                                case "Opacity":
1511                                        try {
1512                                                $this->intOpacity = QType::Cast($mixValue, QType::Integer);
1513                                                if (($this->intOpacity < 0) || ($this->intOpacity > 100))
1514                                                        throw new QCallerException('Opacity must be an integer value between 0 and 100');
1515                                                break;
1516                                        } catch (QInvalidCastException $objExc) {
1517                                                $objExc->IncrementOffset();
1518                                                throw $objExc;
1519                                        }
1520
1521                                // BEHAVIOR
1522                                case "AccessKey":
1523                                        try {
1524                                                $this->strAccessKey = QType::Cast($mixValue, QType::String);
1525                                                break;
1526                                        } catch (QInvalidCastException $objExc) {
1527                                                $objExc->IncrementOffset();
1528                                                throw $objExc;
1529                                        }
1530                                case "CausesValidation":
1531                                        try {
1532                                                $this->mixCausesValidation = $mixValue;
1533                                                break;
1534                                        } catch (QInvalidCastException $objExc) {
1535                                                $objExc->IncrementOffset();
1536                                                throw $objExc;
1537                                        }
1538                                case "Cursor":
1539                                        try {
1540                                                $this->strCursor = QType::Cast($mixValue, QType::String);
1541                                                break;
1542                                        } catch (QInvalidCastException $objExc) {
1543                                                $objExc->IncrementOffset();
1544                                                throw $objExc;
1545                                        }
1546                                case "Enabled":
1547                                        try {
1548                                                $this->blnEnabled = QType::Cast($mixValue, QType::Boolean);
1549                                                break;
1550                                        } catch (QInvalidCastException $objExc) {
1551                                                $objExc->IncrementOffset();
1552                                                throw $objExc;
1553                                        }
1554                                case "Required":
1555                                        try {
1556                                                $this->blnRequired = QType::Cast($mixValue, QType::Boolean);
1557                                                break;
1558                                        } catch (QInvalidCastException $objExc) {
1559                                                $objExc->IncrementOffset();
1560                                                throw $objExc;
1561                                        }
1562                                case "TabIndex":
1563                                        try {
1564                                                $this->intTabIndex = QType::Cast($mixValue, QType::Integer);
1565                                                break;
1566                                        } catch (QInvalidCastException $objExc) {
1567                                                $objExc->IncrementOffset();
1568                                                throw $objExc;
1569                                        }
1570                                case "ToolTip":
1571                                        try {
1572                                                $this->strToolTip = QType::Cast($mixValue, QType::String);
1573                                                break;
1574                                        } catch (QInvalidCastException $objExc) {
1575                                                $objExc->IncrementOffset();
1576                                                throw $objExc;
1577                                        }
1578                                case "Visible":
1579                                        try {
1580                                                $this->blnVisible = QType::Cast($mixValue, QType::Boolean);
1581                                                break;
1582                                        } catch (QInvalidCastException $objExc) {
1583                                                $objExc->IncrementOffset();
1584                                                throw $objExc;
1585                                        }
1586                                case "PreferedRenderMethod":
1587                                        try {
1588                                                $this->strPreferedRenderMethod = QType::Cast($mixValue, QType::String);
1589                                                break;
1590                                        } catch (QInvalidCastException $objExc) {
1591                                                $objExc->IncrementOffset();
1592                                                throw $objExc;
1593                                        }
1594
1595                                // LAYOUT
1596                                case "Height":
1597                                        try {
1598                                                $this->strHeight = QType::Cast($mixValue, QType::String);
1599                                                break;
1600                                        } catch (QInvalidCastException $objExc) {
1601                                                $objExc->IncrementOffset();
1602                                                throw $objExc;
1603                                        }
1604                                case "Width":
1605                                        try {
1606                                                $this->strWidth = QType::Cast($mixValue, QType::String);
1607                                                break;
1608                                        } catch (QInvalidCastException $objExc) {
1609                                                $objExc->IncrementOffset();
1610                                                throw $objExc;
1611                                        }
1612                                case "HtmlBefore":
1613                                        try {
1614                                                $this->strHtmlBefore = QType::Cast($mixValue, QType::String);
1615                                                break;
1616                                        } catch (QInvalidCastException $objExc) {
1617                                                $objExc->IncrementOffset();
1618                                                throw $objExc;
1619                                        }
1620                                case "HtmlAfter":
1621                                        try {
1622                                                $this->strHtmlAfter = QType::Cast($mixValue, QType::String);
1623                                                break;
1624                                        } catch (QInvalidCastException $objExc) {
1625                                                $objExc->IncrementOffset();
1626                                                throw $objExc;
1627                                        }
1628                                case "Instructions":
1629                                        try {
1630                                                $this->strInstructions = QType::Cast($mixValue, QType::String);
1631                                                break;
1632                                        } catch (QInvalidCastException $objExc) {
1633                                                $objExc->IncrementOffset();
1634                                                throw $objExc;
1635                                        }
1636                                case "Warning":
1637                                        try {
1638                                                $this->strWarning = QType::Cast($mixValue, QType::String);
1639                                                break;
1640                                        } catch (QInvalidCastException $objExc) {
1641                                                $objExc->IncrementOffset();
1642                                                throw $objExc;
1643                                        }
1644
1645                                case "Overflow":
1646                                        try {
1647                                                $this->strOverflow = QType::Cast($mixValue, QType::String);
1648                                                break;
1649                                        } catch (QInvalidCastException $objExc) {
1650                                                $objExc->IncrementOffset();
1651                                                throw $objExc;
1652                                        }
1653                                case "Position":
1654                                        try {
1655                                                $this->strPosition = QType::Cast($mixValue, QType::String);
1656                                                $this->MarkAsWrapperModified();
1657                                                break;
1658                                        } catch (QInvalidCastException $objExc) {
1659                                                $objExc->IncrementOffset();
1660                                                throw $objExc;
1661                                        }
1662                                case "Top":
1663                                        try {
1664                                                $this->strTop = QType::Cast($mixValue, QType::String);
1665                                                $this->MarkAsWrapperModified();
1666                                                break;
1667                                        } catch (QInvalidCastException $objExc) {
1668                                                $objExc->IncrementOffset();
1669                                                throw $objExc;
1670                                        }
1671                                case "Left":
1672                                        try {
1673                                                $this->strLeft = QType::Cast($mixValue, QType::String);
1674                                                $this->MarkAsWrapperModified();
1675                                                break;
1676                                        } catch (QInvalidCastException $objExc) {
1677                                                $objExc->IncrementOffset();
1678                                                throw $objExc;
1679                                        }
1680
1681                                case "Moveable":
1682                                        try {
1683                                                if (QType::Cast($mixValue, QType::Boolean)) {
1684                                                        if (!$this->objDraggable) {
1685                                                                $this->objDraggable = new QDraggable($this);
1686                                                        } else {
1687                                                                $this->objDraggable->Disabled = false;
1688                                                        }
1689                                                }
1690                                                else {
1691                                                        if ($this->objDraggable) {
1692                                                                $this->objDraggable->Disabled = true;
1693                                                        }
1694                                                }
1695                                                break;
1696                                        } catch (QInvalidCastException $objExc) {
1697                                                $objExc->IncrementOffset();
1698                                                throw $objExc;
1699                                        }
1700
1701                                case "Resizable":
1702                                        try {
1703                                                if (QType::Cast($mixValue, QType::Boolean)) {
1704                                                        if (!$this->objResizable) {
1705                                                                $this->objResizable = new QResizable($this);
1706                                                        } else {
1707                                                                $this->objResizable->Disabled = false;
1708                                                        }
1709                                                }
1710                                                else {
1711                                                        if ($this->objResizable) {
1712                                                                $this->objResizable->Disabled = true;
1713                                                        }
1714                                                }
1715                                                break;
1716                                        } catch (QInvalidCastException $objExc) {
1717                                                $objExc->IncrementOffset();
1718                                                throw $objExc;
1719                                        }
1720
1721                                case "Droppable":
1722                                        try {
1723                                                if (QType::Cast($mixValue, QType::Boolean)) {
1724                                                        if (!$this->objDroppable) {
1725                                                                $this->objDroppable = new QDroppable($this);
1726                                                        } else {
1727                                                                $this->objDroppable->Disabled = false;
1728                                                        }
1729                                                }
1730                                                else {
1731                                                        if ($this->objDroppable) {
1732                                                                $this->objDroppable->Disabled = true;
1733                                                        }
1734                                                }
1735                                                break;
1736                                        } catch (QInvalidCastException $objExc) {
1737                                                $objExc->IncrementOffset();
1738                                                throw $objExc;
1739                                        }
1740
1741                                // MISC
1742                                case "Name":
1743                                        try {
1744                                                $this->strName = QType::Cast($mixValue, QType::String);
1745                                                break;
1746                                        } catch (QInvalidCastException $objExc) {
1747                                                $objExc->IncrementOffset();
1748                                                throw $objExc;
1749                                        }
1750                                case "strActionParameter": // for backward compatibility
1751                                case "ActionParameter":
1752                                        try {
1753                                                $this->mixActionParameter = ($mixValue instanceof QJsClosure) ? $mixValue : QType::Cast($mixValue, QType::String);
1754                                                break;
1755                                        } catch (QInvalidCastException $objExc) {
1756                                                $objExc->IncrementOffset();
1757                                                throw $objExc;
1758                                        }
1759
1760                                case "WrapperCssClass":
1761                                        try {
1762                                                $this->strWrapperCssClass = QType::Cast($mixValue, QType::String);
1763                                                $this->MarkAsWrapperModified();
1764                                                break;
1765                                        } catch (QInvalidCastException $objExc) {
1766                                                $objExc->IncrementOffset();
1767                                                throw $objExc;
1768                                        }
1769                                case "UseWrapper":
1770                                        try {
1771                                                if($this->blnUseWrapper != QType::Cast($mixValue, QType::Boolean)) {
1772                                                        $this->blnUseWrapper = !$this->blnUseWrapper;
1773                                                        //need to render the parent again (including its children)
1774                                                        if ($this->ParentControl) {
1775                                                                $this->ParentControl->MarkAsModified();
1776                                                        }
1777                                                }
1778                                                break;
1779                                        } catch (QInvalidCastException $objExc) {
1780                                                $objExc->IncrementOffset();
1781                                                throw $objExc;
1782                                        }
1783                                default:
1784                                        try {
1785                                                parent::__set($strName, $mixValue);
1786                                                break;
1787                                        } catch (QCallerException $objExc) {
1788                                                $objExc->IncrementOffset();
1789                                                throw $objExc;
1790                                        }
1791                        }
1792                }
1793        }
1794?>