Overview

Packages

  • Actions
  • Codegen
  • Controls
    • Base
  • DatabaseAdapters
  • Events
  • None
  • Sessions
  • Tests

Classes

  • AbstractControl_CodeGenerator
  • AjaxTimingForm
  • BasicForm
  • BasicOrmTests
  • BBCodeParser
  • CacheTests
  • CalculatorForm
  • CalculatorWidget
  • ComplexColumn
  • DataRepeaterExample
  • Event
  • ExampleCheckColumn1
  • ExampleCheckColumn2
  • ExampleForm
  • Examples
  • ExampleService
  • ExamplesForm
  • ExampleSingleForm
  • ExpandAsArrayTests
  • HtmlJqDoc
  • InjectForm
  • JavaScriptHelper
  • JqAttributes
  • JqControlGen
  • JqDoc
  • JqIcon
  • Method
  • ModelConnectorTests
  • MyControl
  • MyQSlider_ChangeEvent
  • NavPanel
  • NestedTabForm
  • Option
  • Order
  • PaginatorForm
  • ParamsForm
  • PersistentExampleForm
  • PersonEditPanel
  • PluginEditForm
  • PluginManagerForm
  • Project
  • ProjectEditPanel
  • ProjectListForm
  • ProjectPickerListBox
  • ProjectViewPanel
  • QAbstractCacheProvider
  • QAbstractHtmlTableColumn
  • QAbstractHtmlTableDataColumn
  • QAccordion
  • QAccordion_ActivateEvent
  • QAccordion_BeforeActivateEvent
  • QAccordion_CreateEvent
  • QAccordionBase
  • QAccordionGen
  • QAction
  • QActionControl
  • QAjaxAction
  • QAjaxControlAction
  • QAjaxResponse
  • QAlertAction
  • QApplication
  • QApplicationBase
  • QArchive
  • QAutocomplete
  • QAutocomplete_ChangeEvent
  • QAutocomplete_CloseEvent
  • QAutocomplete_CodeGenerator
  • QAutocomplete_CreateEvent
  • QAutocomplete_FocusEvent
  • QAutocomplete_OpenEvent
  • QAutocomplete_ResponseEvent
  • QAutocomplete_SearchEvent
  • QAutocomplete_SelectEvent
  • QAutocomplete_SourceEvent
  • QAutocompleteBase
  • QAutocompleteBase_CodeGenerator
  • QAutocompleteGen
  • QAutocompleteListItem
  • QBackspaceKeyEvent
  • QBaseClass
  • QBlockControl
  • QBlurControlAction
  • QBlurEvent
  • QBorderCollapse
  • QBorderStyle
  • QBrowserType
  • QButton
  • QButtonBase
  • QCache
  • QCacheDeleteAction
  • QCacheDeleteAllAction
  • QCacheProviderAPC
  • QCacheProviderLocalMemory
  • QCacheProviderLocalMemoryTest
  • QCacheProviderMemcache
  • QCacheProviderNoCache
  • QCacheProviderProxy
  • QCacheSetAction
  • QCalendar
  • QCalendarType
  • QCallType
  • QCausesValidation
  • QCellClickEvent
  • QChangeEvent
  • QCheckBox
  • QCheckBox_CodeGenerator
  • QCheckBoxBase_CodeGenerator
  • QCheckBoxLegacyColumn
  • QCheckBoxList
  • QCheckBoxList_CodeGenerator
  • QCheckBoxListBase_CodeGenerator
  • QClickEvent
  • QCodeGen
  • QCodeGenBase
  • QConfirmAction
  • QContextMenuEvent
  • QControl
  • QControl_CodeGenerator
  • QControlBase
  • QControlBase_CodeGenerator
  • QControlBaseTests
  • QControlCategoryType
  • QControlGrouping
  • QControlLabel
  • QControlProxy
  • QConvertNotation
  • QConvertNotationBase
  • QCrossScripting
  • QCryptography
  • QCss
  • QCssAction
  • QCssClassAction
  • QCssTests
  • QCsvTextBox
  • QCursor
  • QDatabaseBase
  • QDatabaseCodeGen
  • QDatabaseFieldBase
  • QDatabaseFieldType
  • QDatabaseForeignKey
  • QDatabaseIndex
  • QDatabaseResultBase
  • QDatabaseRowBase
  • QDatabaseTests
  • QDataGrid
  • QDataGrid_CheckBoxColumn
  • QDataGrid_CodeGenerator
  • QDataGrid_SortEvent
  • QDataGridBase
  • QDataGridBase_CodeGenerator
  • QDataGridLegacy
  • QDataGridLegacyBase
  • QDataGridLegacyColumn
  • QDataGridLegacyRow
  • QDataGridLegacyRowStyle
  • QDataRepeater
  • QDatepicker
  • QDatepicker_BeforeShowDayEvent
  • QDatepicker_BeforeShowEvent
  • QDatepicker_CalculateWeekEvent
  • QDatepicker_ChangeMonthYearEvent
  • QDatepicker_CloseEvent
  • QDatepicker_SelectEvent
  • QDatepicker_SelectEvent2
  • QDatepickerBase
  • QDatepickerBox
  • QDatepickerBox_BeforeShowDayEvent
  • QDatepickerBox_BeforeShowEvent
  • QDatepickerBox_CalculateWeekEvent
  • QDatepickerBox_ChangeMonthYearEvent
  • QDatepickerBox_CloseEvent
  • QDatepickerBox_CodeGenerator
  • QDatepickerBox_SelectEvent
  • QDatepickerBoxBase
  • QDatepickerBoxBase_CodeGenerator
  • QDatepickerBoxGen
  • QDatepickerGen
  • QDateTime
  • QDateTimePicker
  • QDateTimePicker_CodeGenerator
  • QDateTimePickerBase_CodeGenerator
  • QDateTimePickerFormat
  • QDateTimePickerType
  • QDateTimeSpan
  • QDateTimeTests
  • QDateTimeTextBox
  • QDbBackedFormStateHandler
  • QDbBackedSessionHandler
  • QDialog
  • QDialog_BeforeCloseEvent
  • QDialog_ButtonEvent
  • QDialog_CloseEvent
  • QDialog_CreateEvent
  • QDialog_DragEvent
  • QDialog_DragStartEvent
  • QDialog_DragStopEvent
  • QDialog_FocusEvent
  • QDialog_OpenEvent
  • QDialog_ResizeEvent
  • QDialog_ResizeStartEvent
  • QDialog_ResizeStopEvent
  • QDialogBase
  • QDialogBox
  • QDialogGen
  • QDisplayStyle
  • QDoubleClickEvent
  • QDownArrowKeyEvent
  • QDragDropEvent
  • QDraggable
  • QDraggable_CreateEvent
  • QDraggable_DragEvent
  • QDraggable_StartEvent
  • QDraggable_StopEvent
  • QDraggableBase
  • QDraggableGen
  • QDroppable
  • QDroppable_ActivateEvent
  • QDroppable_CreateEvent
  • QDroppable_DeactivateEvent
  • QDroppable_DropEvent
  • QDroppable_OutEvent
  • QDroppable_OverEvent
  • QDroppableBase
  • QDroppableGen
  • QDropZoneGrouping
  • QEmailAttachment
  • QEmailMessage
  • QEmailServer
  • QEmailStringAttachment
  • QEmailTextBox
  • QEnterKeyEvent
  • QErrorAttribute
  • QEscapeKeyEvent
  • QEvent
  • QFieldset
  • QFile
  • QFileAsset
  • QFileAssetBase
  • QFileAssetDialog
  • QFileAssetType
  • QFileControl
  • QFileFormStateHandler
  • QFilterType
  • QFloatTextBox
  • QFloatTextBox_CodeGenerator
  • QFloatTextBoxBase_CodeGenerator
  • QFocusControlAction
  • QFocusEvent
  • QFocusInEvent
  • QFocusOutEvent
  • QFolder
  • QFontFamily
  • QForm
  • QFormBase
  • QFormGen
  • QFormStateHandler
  • QGridLines
  • QHideCalendarAction
  • QHideDialog
  • QHideDialogBox
  • QHListControl
  • QHListItem
  • QHorizontalAlign
  • QHtml
  • QHtmlAttributeManager
  • QHtmlAttributeManagerBase
  • QHtmlReporter
  • QHtmlTable
  • QHtmlTable_CodeGenerator
  • QHtmlTableBase
  • QHtmlTableCallableColumn
  • QHtmlTableCheckBoxColumn
  • QHtmlTableCheckBoxColumn_ClickEvent
  • QHtmlTableIndexedColumn
  • QHtmlTableLinkColumn
  • QHtmlTableNodeColumn
  • QHtmlTablePropertyColumn
  • QI18n
  • QI18nTests
  • QImageBase
  • QImageBrowser
  • QImageBrowserBase
  • QImageBrowserNav
  • QImageBrowserThumbnails
  • QImageButton
  • QImageControl
  • QImageControlBase
  • QImageFileAsset
  • QImageLabel
  • QImageLabelBase
  • QImageRollover
  • QImageType
  • QIndex
  • QInformixPdoDatabase
  • QInformixPdoDatabaseField
  • QInformixPdoDatabaseResult
  • QInformixPdoDatabaseRow
  • QInputEvent
  • QInstallationValidationResult
  • QInstallationValidator
  • QIntegerTextBox
  • QIntegerTextBox_CodeGenerator
  • QIntegerTextBoxBase_CodeGenerator
  • QJavaScriptAction
  • QJQAction
  • QJQBounceAction
  • QJqButton
  • QJqButton_CreateEvent
  • QJqButtonBase
  • QJqButtonGen
  • QJqCheckBox
  • QJqCheckBox_CreateEvent
  • QJqCheckBoxBase
  • QJqCheckBoxGen
  • QJQHideAction
  • QJQHideEffectAction
  • QJQHighlightAction
  • QJQPulsateAction
  • QJqRadioButton
  • QJqRadioButton_CreateEvent
  • QJqRadioButtonBase
  • QJqRadioButtonGen
  • QJQShakeAction
  • QJQShowAction
  • QJQShowEffectAction
  • QJQSizeAction
  • QJQToggleAction
  • QJQToggleEffectAction
  • QJQTransferAction
  • QJqUiEvent
  • QJqUiPropertyEvent
  • QJsClosure
  • QJsFunction
  • QJsNoQuoteKey
  • QJsParameterList
  • QJsPriority
  • QJsTimer
  • QJsTimerBase
  • QJsVarName
  • QKeyDownEvent
  • QKeyPressEvent
  • QKeyUpEvent
  • QLabel
  • QLabel_CodeGenerator
  • QLabelBase_CodeGenerator
  • QLexer
  • QLinkButton
  • QListBox
  • QListBox_CodeGenerator
  • QListBoxBase
  • QListBoxBase_CodeGenerator
  • QListControl
  • QListControl_CodeGenerator
  • QListControlBase_CodeGenerator
  • QListItem
  • QListItemBase
  • QListItemStyle
  • QManyToManyReference
  • QMenu
  • QMenu_BlurEvent
  • QMenu_CreateEvent
  • QMenu_FocusEvent
  • QMenu_SelectEvent
  • QMenuBase
  • QMenuGen
  • QMimeType
  • QModelConnectorArgumentType
  • QModelConnectorCreateType
  • QModelConnectorEditDlg
  • QModelConnectorOptions
  • QModelConnectorParam
  • QMouseDownEvent
  • QMouseEnterEvent
  • QMouseLeaveEvent
  • QMouseMoveEvent
  • QMouseOutEvent
  • QMouseOverEvent
  • QMouseUpEvent
  • QMultiLevelCacheProvider
  • QMySqlDatabase
  • QMySqlDatabaseField
  • QMySqlDatabaseResult
  • QMySqli5ClusterDatabase
  • QMySqli5Database
  • QMySqli5DatabaseField
  • QMySqli5DatabaseResult
  • QMySqliDatabase
  • QMySqliDatabaseField
  • QMySqliDatabaseResult
  • QMySqliDatabaseRow
  • QNoScriptAjaxAction
  • QNumericTextBox
  • QOnEvent
  • QOracleDatabase
  • QOracleDatabaseField
  • QOracleDatabaseResult
  • QOracleDatabaseRow
  • QOrderedListType
  • QOverflow
  • QPaginatedControl
  • QPaginator
  • QPaginatorBase
  • QPanel
  • QPartialQueryBuilder
  • QPdoDatabase
  • QPdoDatabaseResult
  • QPgConditionILike
  • QPgConditionJsonContains
  • QPgQ
  • QPosition
  • QPostgreSqlDatabase
  • QPostgreSqlDatabaseField
  • QPostgreSqlDatabaseResult
  • QPostgreSqlDatabaseRow
  • QPostgreSqlPdoDatabase
  • QPostgreSqlPdoDatabaseField
  • QPostgreSqlPdoDatabaseResult
  • QPostgreSqlPdoDatabaseRow
  • QProgressbar
  • QProgressbar_ChangeEvent
  • QProgressbar_CompleteEvent
  • QProgressbar_CreateEvent
  • QProgressbarBase
  • QProgressbarGen
  • QQ
  • QQAggregationClause
  • QQAliasTests
  • QQAssociationNode
  • QQAverage
  • QQClause
  • QQColumnNode
  • QQCondition
  • QQConditionAll
  • QQConditionAnd
  • QQConditionBetween
  • QQConditionComparison
  • QQConditionEqual
  • QQConditionExists
  • QQConditionGreaterOrEqual
  • QQConditionGreaterThan
  • QQConditionIn
  • QQConditionIsNotNull
  • QQConditionIsNull
  • QQConditionLessOrEqual
  • QQConditionLessThan
  • QQConditionLike
  • QQConditionLogical
  • QQConditionNone
  • QQConditionNot
  • QQConditionNotBetween
  • QQConditionNotEqual
  • QQConditionNotExists
  • QQConditionNotIn
  • QQConditionNotLike
  • QQConditionOr
  • QQCount
  • QQDistinct
  • QQExpand
  • QQExpandAsArray
  • QQExpandVirtualNode
  • QQFuncTests
  • QQFunctionNode
  • QQGroupBy
  • QQHavingClause
  • QQLimitInfo
  • QQMathNode
  • QQMathOpTests
  • QQMaximum
  • QQMinimum
  • QQNamedValue
  • QQNode
  • QQNoParentNode
  • QQOrderBy
  • QQReverseReferenceNode
  • QQSelect
  • QQSubQueryCountNode
  • QQSubQueryNode
  • QQSubQuerySqlNode
  • QQSum
  • QQTableNode
  • QQuery
  • QQueryBuilder
  • QQueryExpansion
  • QQVirtualNode
  • QRadioButton
  • QRadioButtonList
  • QRadioButtonList_CodeGenerator
  • QRadioButtonListBase_CodeGenerator
  • QRedirectAction
  • QReference
  • QRegex
  • QRegisterClickPositionAction
  • QRepeatDirection
  • QRequestMode
  • QResetTimerAction
  • QResizable
  • QResizable_CreateEvent
  • QResizable_ResizeEvent
  • QResizable_StartEvent
  • QResizable_StopEvent
  • QResizableBase
  • QResizableGen
  • QResizeHandleDirection
  • QRestServiceCodeGen
  • QReverseReference
  • QRssCategory
  • QRssFeed
  • QRssImage
  • QRssItem
  • QSampleControl
  • QSampleTranslation
  • QSelectable
  • QSelectable_CreateEvent
  • QSelectable_SelectedEvent
  • QSelectable_SelectingEvent
  • QSelectable_StartEvent
  • QSelectable_StopEvent
  • QSelectable_UnselectedEvent
  • QSelectable_UnselectingEvent
  • QSelectableBase
  • QSelectableGen
  • QSelectControlAction
  • QSelectEvent
  • QSelectionMode
  • QSelectMenu
  • QSelectMenu_ChangeEvent
  • QSelectMenu_CloseEvent
  • QSelectMenu_CreateEvent
  • QSelectMenu_FocusEvent
  • QSelectMenu_OpenEvent
  • QSelectMenu_SelectEvent
  • QSelectMenuBase
  • QSelectMenuGen
  • QServerAction
  • QServerControlAction
  • QSessionFormStateHandler
  • QSetValueAction
  • QShowCalendarAction
  • QShowDialog
  • QShowDialogBox
  • QSlider
  • QSlider_ChangeEvent
  • QSlider_CodeGenerator
  • QSlider_CreateEvent
  • QSlider_SlideEvent
  • QSlider_StartEvent
  • QSlider_StopEvent
  • QSliderBase
  • QSliderBase_CodeGenerator
  • QSliderGen
  • QSoapMethod
  • QSoapParameter
  • QSoapService
  • QSortable
  • QSortable_ActivateEvent
  • QSortable_BeforeStopEvent
  • QSortable_ChangeEvent
  • QSortable_CreateEvent
  • QSortable_DeactivateEvent
  • QSortable_OutEvent
  • QSortable_OverEvent
  • QSortable_ReceiveEvent
  • QSortable_RemoveEvent
  • QSortable_SortEvent
  • QSortable_StartEvent
  • QSortable_StopEvent
  • QSortable_UpdateEvent
  • QSortableBase
  • QSortableGen
  • QSpinner
  • QSpinner_ChangeEvent
  • QSpinner_CreateEvent
  • QSpinner_SpinEvent
  • QSpinner_StartEvent
  • QSpinner_StopEvent
  • QSpinnerBase
  • QSpinnerGen
  • QSqlColumn
  • QSqLite3PdoDatabase
  • QSqLite3PdoDatabaseField
  • QSqLite3PdoDatabaseResult
  • QSqLite3PdoDatabaseRow
  • QSqlServer2005Database
  • QSqlServer2005DatabaseField
  • QSqlServer2005DatabaseResult
  • QSqlServer2005DatabaseRow
  • QSqlServerDatabase
  • QSqlServerDatabaseField
  • QSqlServerDatabaseResult
  • QSqlServerDatabaseRow
  • QSqlTable
  • QStack
  • QStopPropagationAction
  • QString
  • QStringTest
  • QTabKeyEvent
  • QTabs
  • QTabs_ActivateEvent
  • QTabs_BeforeActivateEvent
  • QTabs_BeforeLoadEvent
  • QTabs_CreateEvent
  • QTabs_LoadEvent
  • QTabsBase
  • QTabsGen
  • QTag
  • QTagStyler
  • QTerminateAction
  • QTestControl
  • QTestForm
  • QTextAlign
  • QTextBox
  • QTextBox_CodeGenerator
  • QTextBoxBase
  • QTextBoxBase_CodeGenerator
  • QTextMode
  • QTimer
  • QTimerExpiredEvent
  • QTimerTests
  • QToggleCssClassAction
  • QToggleDisplayAction
  • QToggleEnableAction
  • QTranslationPoParser
  • QTreeNav
  • QTreeNavItem
  • QType
  • QTypeTable
  • QTypeTests
  • QUnitTestCaseBase
  • QUnorderedListStyle
  • QUpArrowKeyEvent
  • QUrlTextBox
  • QVerticalAlign
  • QVirtualAttributeColumn
  • QWaitIcon
  • QWatcher
  • QWatcherBase
  • QWatcherCache
  • QWatcherDB
  • QWatcherNone
  • QWriteBox
  • RecordsSummary
  • RefreshForm
  • SampleComposite
  • SampleForm
  • SelectableLabel
  • SelectForm
  • SpeedForm
  • TestImageBrowser
  • UrlForm

Interfaces

  • ICacheAction
  • QDataList_CodeGenerator_Interface
  • QTranslationBase

Traits

  • QDataBinder
  • QListItemManager
  • QModelTrait

Exceptions

  • QCallerException
  • QCrossScriptingException
  • QCryptographyException
  • QDatabaseExceptionBase
  • QDataBindException
  • QDateTimeNullException
  • QEmailException
  • QIndexOutOfRangeException
  • QInformixPdoDatabaseException
  • QInvalidCastException
  • QInvalidFormStateException
  • QMySqliDatabaseException
  • QOptimisticLockingException
  • QOracleDatabaseException
  • QPdoDatabaseException
  • QPoParserException
  • QPostgreSqlDatabaseException
  • QPostgreSqlPdoDatabaseException
  • QRemoteAdminDeniedException
  • QSqLite3PdoDatabaseException
  • QSqlServer2005DatabaseException
  • QSqlServerDatabaseException
  • QUndefinedMethodException
  • QUndefinedPrimaryKeyException
  • QUndefinedPropertyException

Functions

  • __database_check_error
  • __QForm_EvaluateTemplate_ObHandler
  • _b
  • _indent
  • _nl
  • _p
  • _r
  • _t
  • _tp
  • _tr
  • array_trim
  • beginsWith
  • CamelCaseFromDash
  • CastToInt
  • DataGridEvalHandleError
  • DisplayMonospacedText
  • endsWith
  • GO_BACK
  • jq_anytime_gen
  • jq_control_gen
  • jq_inc_gen
  • jq_indent
  • PrintExplainStatement
  • PrintInstructions
  • QcubedHandleCodeGenParseError
  • QcubedHandleError
  • QcubedHandleException
  • QCubedShutdown
  • QDateTimeErrorHandler
  • trimOffEnd
  • trimOffFront
  • Overview
  • Package
  • Class
   1: <?php
   2: 
   3:     /**
   4:      * Represents a column for a QHtmlTable. Different subclasses (see below) allow accessing and fetching the data
   5:      * for each cells in a variety of ways
   6:      *
   7:      * @property string                 $Name           name of the column
   8:      * @property string                 $CssClass       CSS class of the column. This will be applied to every cell in the column. Use ColStyper
   9:      *                                                  to set the class for the actual 'col' tag if using col tags.
  10:      * @property string                 $HeaderCssClass CSS class of the column's cells when it's rendered in a table header
  11:      * @property boolean                $HtmlEntities   if true, cell values will be converted using htmlentities()
  12:      * @property boolean                $RenderAsHeader if true, all cells in the column will be rendered with a <<th>> tag instead of <<td>>
  13:      * @property integer                $Id             HTML id attribute to put in the col tag
  14:      * @property integer                $Span           HTML span attribute to put in the col tag
  15:      * @property-read QHtmlTableBase  $ParentTable    parent table of the column
  16:      * @property-write QHtmlTableBase $_ParentTable   Parent table of this column
  17:      * @property-write callable $CellParamsCallback A callback to set the html parameters of a generated cell
  18:      * @property boolean                $Visible        Whether the column will be drawn. Defaults to true.
  19:      * @property-read QTagStyler        $CellStyler     The tag styler for the cells in the column
  20:      * @property-read QTagStyler        $HeaderCellStyler       The tag styler for the header cells in the column
  21:      * @property-read QTagStyler        $ColStyler      The tag styler for the col tag in the column
  22:      */
  23:     abstract class QAbstractHtmlTableColumn extends QBaseClass {
  24:         /** @var string */
  25:         protected $strName;
  26:         /** @var string */
  27:         protected $strCssClass = null;
  28:         /** @var string */
  29:         protected $strHeaderCssClass = null;
  30:         /** @var boolean */
  31:         protected $blnHtmlEntities = true;
  32:         /** @var boolean */
  33:         protected $blnRenderAsHeader = false;
  34:         /** @var QHtmlTableBase */
  35:         protected $objParentTable = null;
  36:         /** @var integer */
  37:         protected $intSpan = 1;
  38:         /** @var string optional id for column tag rendering and datatables */
  39:         protected $strId = null;
  40:         /** @var bool Easy way to hide a column without removing the column. */
  41:         protected $blnVisible = true;
  42:         /** @var Callable Callback to modify the html attributes of the generated cell. */
  43:         protected $cellParamsCallback = null;
  44:         /** @var QTagStyler Styles for each cell. Usually this should be done in css for efficient code generation. */
  45:         protected $objCellStyler;
  46:         /** @var QTagStyler Styles for each header cell. Usually this should be done in css for efficient code generation. */
  47:         protected $objHeaderCellStyler;
  48:         /** @var QTagStyler Styles for each col. Usually this should be done in css for efficient code generation. */
  49:         protected $objColStyler;
  50: 
  51: 
  52: 
  53:         /**
  54:          * @param string $strName Name of the column
  55:          */
  56:         public function __construct($strName) {
  57:             $this->strName = $strName;
  58:         }
  59: 
  60:         /**
  61:          * 
  62:          * Render the header cell including opening and closing tags. 
  63:          * 
  64:          * This will be called by the data table if ShowHeader is on, and will only
  65:          * be called for the top line item.
  66:          * 
  67:          */
  68:         public function RenderHeaderCell() {
  69:             if (!$this->blnVisible) return '';
  70: 
  71:             $cellValue = $this->FetchHeaderCellValue();
  72:             if ($this->blnHtmlEntities)
  73:                 $cellValue = QApplication::HtmlEntities($cellValue);
  74:             if ($cellValue == '' && QApplication::IsBrowser(QBrowserType::InternetExplorer)) {
  75:                 $cellValue = '&nbsp;';
  76:             }
  77:             
  78:             return QHtml::RenderTag('th', $this->GetHeaderCellParams(), $cellValue);
  79:         }
  80:         
  81:         /**
  82:          * Returns the text to print in the header cell, if one is to be drawn. Override if you want
  83:          * something other than the default.
  84:          */
  85:         public function FetchHeaderCellValue() {
  86:             return $this->strName;
  87:         }
  88: 
  89:         /**
  90:          * Returns an array of key/value pairs to insert as parameters in the header cell. Override and add
  91:          * more if you need them.
  92:          * @return array
  93:          */
  94:         public function GetHeaderCellParams () {
  95:             $aParams['scope'] = 'col';
  96:             if ($this->strHeaderCssClass) {
  97:                 $aParams['class'] = $this->strHeaderCssClass;
  98:             }
  99:             if ($this->objHeaderCellStyler) {
 100:                 $aParams = $this->objHeaderCellStyler->GetHtmlAttributes($aParams);
 101:             }
 102:             return $aParams;        
 103:         }
 104:         
 105:         /**
 106:          * Render a cell.
 107:          * Called by data table for each cell. Override and call with $blnHeader = true if you want
 108:          * this individual cell to render with <<th>> tags instead of <<td>>.
 109:          *
 110:          * @param mixed   $item
 111:          * @param boolean $blnAsHeader
 112:          *
 113:          * @return string
 114:          */
 115:         public function RenderCell($item, $blnAsHeader = false) {
 116:             if (!$this->blnVisible) return '';
 117: 
 118:             $cellValue = $this->FetchCellValue($item);
 119:             if ($this->blnHtmlEntities)
 120:                 $cellValue = QApplication::HtmlEntities($cellValue);
 121:             if ($cellValue == '' && QApplication::IsBrowser(QBrowserType::InternetExplorer)) {
 122:                 $cellValue = '&nbsp;';
 123:             }
 124:     
 125:             if ($blnAsHeader || $this->blnRenderAsHeader) {
 126:                 $strTag = 'th';
 127:             } else {
 128:                 $strTag = 'td';
 129:             }
 130:             
 131:             return QHtml::RenderTag($strTag, $this->GetCellParams($item), $cellValue);
 132:         }
 133: 
 134:         /**
 135:          * Return a key/val array of items to insert inside the cell tag.
 136:          * Handles class, style, and id already. Override to add additional items, like an onclick handler.
 137:          *
 138:          * @param mixed $item
 139:          *
 140:          * @return array
 141:          */
 142:         protected function GetCellParams ($item) {
 143:             $aParams = array();
 144: 
 145:             if ($strClass = $this->GetCellClass ($item)) {
 146:                 $aParams['class'] = $strClass;
 147:             }
 148:             
 149:             if ($strId = $this->GetCellId ($item)) {
 150:                 $aParams['id'] = $strId;
 151:             }
 152:             
 153:             if ($this->blnRenderAsHeader) {
 154:                 // assume this means it is a row header
 155:                 $aParams['scope'] = 'row';
 156:             }
 157: 
 158:             $strStyle = $this->GetCellStyle ($item);
 159: 
 160:             if ($this->objCellStyler) {
 161:                 $aStyles = null;
 162:                 if ($strStyle) {
 163:                     $aStyles = explode (';', $strStyle);
 164:                 }
 165:                 $aParams = $this->objCellStyler->GetHtmlAttributes($aParams, $aStyles);
 166:             } elseif ($strStyle) {
 167:                 $aParams['style'] = $strStyle;
 168:             }
 169: 
 170:             if ($this->cellParamsCallback) {
 171:                 $a = call_user_func($this->cellParamsCallback, $item);
 172:                 $aParams = array_merge ($aParams, $a);
 173:             }
 174: 
 175:             return $aParams;        
 176:         }
 177:         
 178:         /**
 179:          * Return the class of the cell.
 180:          *
 181:          * @param mixed $item
 182:          *
 183:          * @return string
 184:          */
 185:         protected function GetCellClass ($item) {
 186:             if ($this->strCssClass) {
 187:                 return $this->strCssClass;
 188:             }
 189:             return '';
 190:         }
 191:         
 192:         /**
 193:          * Return the id of the cell.
 194:          *
 195:          * @param mixed $item
 196:          *
 197:          * @return string
 198:          */
 199:         protected function GetCellId ($item) {
 200:             return '';
 201:         }
 202:         
 203:         /**
 204:          * Return the style string for the cell.
 205:          *
 206:          * @param mixed $item
 207:          *
 208:          * @return string
 209:          */
 210:         protected function GetCellStyle ($item) {
 211:             return '';
 212:         }
 213:         
 214:         /**
 215:          * Return the raw string that represents the cell value. 
 216:          * 
 217:          * @param mixed $item
 218:          */
 219:         abstract public function FetchCellValue($item);
 220: 
 221:         /**
 222:          * Render the column tag.
 223:          * This special tag can control specific features of columns, but is generally optional on a table.
 224:          *
 225:          * @return string
 226:          */
 227:         public function RenderColTag() {
 228:             return QHtml::RenderTag('col', $this->GetColParams(), null, true);
 229:         }
 230: 
 231:         /**
 232:          * Return a key/value array of parameters to put in the col tag.
 233:          * Override to add parameters.
 234:          */
 235:         protected function GetColParams () {
 236:             $aParams = array();
 237:             if ($this->intSpan > 1) {
 238:                 $aParams['span'] = $this->intSpan;
 239:             }
 240:             if ($this->strId) {
 241:                 $aParams['id'] = $this->strId;
 242:             }
 243: 
 244:             if ($this->objColStyler) {
 245:                 $aParams = $this->objColStyler->GetHtmlAttributes($aParams);
 246:             }
 247: 
 248:             return $aParams;        
 249:         }
 250: 
 251:         /**
 252:          * Prepare to serialize references to the form.
 253:          */
 254:         public function Sleep() {
 255:             $this->cellParamsCallback = QControl::SleepHelper($this->cellParamsCallback);
 256:         }
 257: 
 258:         /**
 259:          * The object has been unserialized, so fix up pointers to embedded objects.
 260:          * @param QForm $objForm
 261:          */
 262:         public function Wakeup(QForm $objForm) {
 263:             $this->cellParamsCallback = QControl::WakeupHelper($objForm, $this->cellParamsCallback);
 264:         }
 265: 
 266:         /**
 267:          * Override to check for post data in your column if needed.
 268:          */
 269:         public function ParsePostData() {
 270:         }
 271: 
 272:         /**
 273:          * PHP magic method
 274:          *
 275:          * @param string $strName
 276:          *
 277:          * @return bool|int|mixed|QHtmlTableBase|string
 278:          * @throws Exception
 279:          * @throws QCallerException
 280:          */
 281:         public function __get($strName) {
 282:             switch ($strName) {
 283:                 case 'Name':
 284:                     return $this->strName;
 285:                 case 'CssClass':
 286:                     return $this->strCssClass;
 287:                 case 'HeaderCssClass':
 288:                     return $this->strHeaderCssClass;
 289:                 case 'HtmlEntities':
 290:                     return $this->blnHtmlEntities;
 291:                 case 'RenderAsHeader':
 292:                     return $this->blnRenderAsHeader;
 293:                 case 'ParentTable':
 294:                     return $this->objParentTable;
 295:                 case 'Span':
 296:                     return $this->intSpan;
 297:                 case 'Id':
 298:                     return $this->strId;
 299:                 case 'Visible':
 300:                     return $this->blnVisible;
 301:                 case 'CellStyler':
 302:                     if (!$this->objCellStyler) {
 303:                         $this->objCellStyler = new QTagStyler();
 304:                     }
 305:                     return $this->objCellStyler;
 306:                 case 'HeaderCellStyler':
 307:                     if (!$this->objHeaderCellStyler) {
 308:                         $this->objHeaderCellStyler = new QTagStyler();
 309:                     }
 310:                     return $this->objHeaderCellStyler;
 311:                 case 'ColStyler':
 312:                     if (!$this->objColStyler) {
 313:                         $this->objColStyler = new QTagStyler();
 314:                     }
 315:                     return $this->objColStyler;
 316: 
 317: 
 318:                 default:
 319:                     try {
 320:                         return parent::__get($strName);
 321:                     } catch (QCallerException $objExc) {
 322:                         $objExc->IncrementOffset();
 323:                         throw $objExc;
 324:                     }
 325:             }
 326:         }
 327: 
 328:         /**
 329:          * PHP Magic method
 330:          *
 331:          * @param string $strName
 332:          * @param string $mixValue
 333:          *
 334:          * @return mixed|void
 335:          * @throws Exception
 336:          * @throws QCallerException
 337:          * @throws QInvalidCastException
 338:          */
 339:         public function __set($strName, $mixValue) {
 340:             switch ($strName) {
 341:                 case "Name":
 342:                     try {
 343:                         $this->strName = QType::Cast($mixValue, QType::String);
 344:                         break;
 345:                     } catch (QInvalidCastException $objExc) {
 346:                         $objExc->IncrementOffset();
 347:                         throw $objExc;
 348:                     }
 349: 
 350:                 case "CssClass":
 351:                     try {
 352:                         $this->strCssClass = QType::Cast($mixValue, QType::String);
 353:                         break;
 354:                     } catch (QInvalidCastException $objExc) {
 355:                         $objExc->IncrementOffset();
 356:                         throw $objExc;
 357:                     }
 358: 
 359:                 case "HeaderCssClass":
 360:                     try {
 361:                         $this->strHeaderCssClass = QType::Cast($mixValue, QType::String);
 362:                         break;
 363:                     } catch (QInvalidCastException $objExc) {
 364:                         $objExc->IncrementOffset();
 365:                         throw $objExc;
 366:                     }
 367: 
 368:                 case "HtmlEntities":
 369:                     try {
 370:                         $this->blnHtmlEntities = QType::Cast($mixValue, QType::Boolean);
 371:                         break;
 372:                     } catch (QInvalidCastException $objExc) {
 373:                         $objExc->IncrementOffset();
 374:                         throw $objExc;
 375:                     }
 376:                     
 377:                 case "RenderAsHeader":
 378:                     try {
 379:                         $this->blnRenderAsHeader = QType::Cast($mixValue, QType::Boolean);
 380:                         break;
 381:                     } catch (QInvalidCastException $objExc) {
 382:                         $objExc->IncrementOffset();
 383:                         throw $objExc;
 384:                     }
 385:                     
 386:                 case "Span":
 387:                     try {
 388:                         $this->intSpan = QType::Cast($mixValue, QType::Integer);
 389:                         if ($this->intSpan < 1) {
 390:                             throw new Exception("Span must be 1 or greater.");
 391:                         }
 392:                         break;
 393:                     } catch (QInvalidCastException $objExc) {
 394:                         $objExc->IncrementOffset();
 395:                         throw $objExc;
 396:                     }
 397: 
 398:                 case "Id":
 399:                     try {
 400:                         $this->strId = QType::Cast($mixValue, QType::String);
 401:                         break;
 402:                     } catch (QInvalidCastException $objExc) {
 403:                         $objExc->IncrementOffset();
 404:                         throw $objExc;
 405:                     }
 406: 
 407:                 case "Visible":
 408:                     try {
 409:                         $this->blnVisible = QType::Cast($mixValue, QType::Boolean);
 410:                         break;
 411:                     } catch (QInvalidCastException $objExc) {
 412:                         $objExc->IncrementOffset();
 413:                         throw $objExc;
 414:                     }
 415: 
 416:                 case "CellParamsCallback":
 417:                     $this->cellParamsCallback = $mixValue;
 418:                     break;
 419: 
 420:                 case "_ParentTable":
 421:                     try {
 422:                         $this->objParentTable = QType::Cast($mixValue, 'QHtmlTableBase');
 423:                         break;
 424:                     } catch (QInvalidCastException $objExc) {
 425:                         $objExc->IncrementOffset();
 426:                         throw $objExc;
 427:                     }
 428: 
 429:                 default:
 430:                     try {
 431:                         parent::__set($strName, $mixValue);
 432:                         break;
 433:                     } catch (QCallerException $objExc) {
 434:                         $objExc->IncrementOffset();
 435:                         throw $objExc;
 436:                     }
 437:             }
 438:         }
 439:     }
 440:     
 441:     /**
 442:      * An abstract column designed to work with QDataGrid and other tables that require more than basic columns.
 443:      * Supports post processing of cell contents for further formatting, and OrderBy clauses.
 444:      *
 445:      * @property mixed          $OrderByClause        order by info for sorting the column in ascending order. Used by subclasses.
 446:      *    Most often this is a QQ::Clause, but can be any data needed.
 447:      * @property mixed          $ReverseOrderByClause order by info for sorting the column in descending order.
 448:      * @property string         $Format               the default format to use for FetchCellValueFormatted(). Used by QDataTables plugin.
 449:      *    For date columns it should be a format accepted by QDateTime::qFormat()
 450:      * @property-write string   $PostMethod           after the cell object is retrieved, call this method on the obtained object
 451:      * @property-write callback $PostCallback         after the cell object is retrieved, call this callback on the obtained object.
 452:      *    If $PostMethod is also set, this will be called after that method call.
 453:      */
 454:     abstract class QAbstractHtmlTableDataColumn extends QAbstractHtmlTableColumn {
 455:         /** @var mixed Order By information. Can be a QQ::Clause, or any kind of object depending on your need */
 456:         protected $objOrderByClause = null;
 457:         /** @var mixed */
 458:         protected $objReverseOrderByClause = null;
 459:         /** @var string */
 460:         protected $strFormat = null;
 461:         /** @var string */
 462:         protected $strPostMethod = null;
 463:         /** @var callback */
 464:         protected $objPostCallback = null;
 465: 
 466:         /**
 467:          * Return the raw string that represents the cell value.
 468:          * This version uses a combination of post processing strategies so that you can set
 469:          * column options to format the raw data. If no
 470:          * options are set, then $item will just pass through, or __toString() will be called
 471:          * if its an object. If none of these work for you, just override FetchCellObject and
 472:          * return your formatted string from there.
 473:          *
 474:          * @param mixed $item
 475:          *
 476:          * @return mixed|string
 477:          */
 478:         public function FetchCellValue($item) {
 479:             $cellValue = $this->FetchCellObject($item);
 480:                         
 481:             if ($cellValue !== null && $this->strPostMethod) {
 482:                 $strPostMethod = $this->strPostMethod;
 483:                 assert ('is_callable([$cellValue, $strPostMethod])');   // Malformed post method, or the item is not an object
 484:                 $cellValue = $cellValue->$strPostMethod();
 485:             }
 486:             if ($this->objPostCallback) {
 487:                 $cellValue = call_user_func($this->objPostCallback, $cellValue);
 488:             }
 489:             if ($cellValue === null) {
 490:                 return '';
 491:             }
 492: 
 493:             if ($cellValue instanceof QDateTime) {
 494:                 return $cellValue->qFormat($this->strFormat);
 495:             }
 496:             if (is_object($cellValue)) {
 497:                 $cellValue = $cellValue->__toString();
 498:             }
 499:             if ($this->strFormat)
 500:                 return sprintf($this->strFormat, $cellValue);
 501: 
 502:             return $cellValue;
 503:         }
 504: 
 505:         /**
 506:          * Return the value of the cell. FetchCellValue will process this more if needed.
 507:          * Default returns an entire data row and relies on FetchCellValue to extract the needed data.
 508:          * 
 509:          * @param mixed $item
 510:          */
 511:         abstract public function FetchCellObject($item);
 512: 
 513:         /**
 514:          * Fix up possible embedded reference to the form.
 515:          */
 516:         public function Sleep() {
 517:             $this->objPostCallback = QControl::SleepHelper($this->objPostCallback);
 518:             parent::Sleep();
 519:         }
 520: 
 521:         /**
 522:          * The object has been unserialized, so fix up pointers to embedded objects.
 523:          * @param QForm $objForm
 524:          */
 525:         public function Wakeup(QForm $objForm) {
 526:             parent::Wakeup($objForm);
 527:             $this->objPostCallback = QControl::WakeupHelper($objForm, $this->objPostCallback);
 528:         }
 529: 
 530:         /**
 531:          * PHP magic method
 532:          *
 533:          * @param string $strName
 534:          *
 535:          * @return bool|int|mixed|QHtmlTableBase|string
 536:          * @throws Exception
 537:          * @throws QCallerException
 538:          */
 539:         public function __get($strName) {
 540:             switch ($strName) {
 541:                 case "OrderByClause":
 542:                     return $this->objOrderByClause;
 543:                 case "ReverseOrderByClause":
 544:                     return $this->objReverseOrderByClause;
 545:                 case "Format":
 546:                     return $this->strFormat;
 547: 
 548:                 default:
 549:                     try {
 550:                         return parent::__get($strName);
 551:                     } catch (QCallerException $objExc) {
 552:                         $objExc->IncrementOffset();
 553:                         throw $objExc;
 554:                     }
 555:             }
 556:         }
 557: 
 558:         /**
 559:          * PHP magic method
 560:          *
 561:          * @param string $strName
 562:          * @param string $mixValue
 563:          *
 564:          * @return mixed|void
 565:          * @throws Exception
 566:          * @throws QCallerException
 567:          * @throws QInvalidCastException
 568:          */
 569:         public function __set($strName, $mixValue) {
 570:             switch ($strName) {
 571:                 case "OrderByClause":
 572:                     try {
 573:                         $this->objOrderByClause = $mixValue;
 574:                         break;
 575:                     } catch (QInvalidCastException $objExc) {
 576:                         $objExc->IncrementOffset();
 577:                         throw $objExc;
 578:                     }
 579: 
 580:                 case "ReverseOrderByClause":
 581:                     try {
 582:                         $this->objReverseOrderByClause = $mixValue;
 583:                         break;
 584:                     } catch (QInvalidCastException $objExc) {
 585:                         $objExc->IncrementOffset();
 586:                         throw $objExc;
 587:                     }
 588: 
 589:                 case "Format":
 590:                     try {
 591:                         $this->strFormat = QType::Cast($mixValue, QType::String);
 592:                         break;
 593:                     } catch (QInvalidCastException $objExc) {
 594:                         $objExc->IncrementOffset();
 595:                         throw $objExc;
 596:                     }
 597: 
 598:                 case "PostMethod":
 599:                     try {
 600:                         $this->strPostMethod = QType::Cast($mixValue, QType::String);
 601:                         break;
 602:                     } catch (QInvalidCastException $objExc) {
 603:                         $objExc->IncrementOffset();
 604:                         throw $objExc;
 605:                     }
 606: 
 607:                 case "PostCallback":
 608:                     $this->objPostCallback = $mixValue;
 609:                     break;
 610: 
 611:                 default:
 612:                     try {
 613:                         parent::__set($strName, $mixValue);
 614:                         break;
 615:                     } catch (QCallerException $objExc) {
 616:                         $objExc->IncrementOffset();
 617:                         throw $objExc;
 618:                     }
 619:             }
 620:         }
 621:     }
 622: 
 623:     /**
 624:      * Displays a  property of an object, as in $object->Property
 625:      * If your DataSource is an array of objects, use this column to display a particular property of each object.
 626:      * Can search with depth to, as in $obj->Prop1->Prop2.
 627:      *
 628:      * @property string  $Property the property to use when accessing the objects in the DataSource array. Can be a s
 629:      *  series of properties separated with '->', i.e. 'Prop1->Prop2->Prop3' will find the Prop3 item inside the Prop2 object,
 630:      *  inside the Prop1 object, inside the current object.
 631:      * @property boolean $NullSafe if true the value fetcher will check for nulls before accessing the properties
 632:      */
 633:     class QHtmlTablePropertyColumn extends QAbstractHtmlTableDataColumn {
 634:         protected $strProperty;
 635:         protected $strPropertiesArray;
 636:         protected $blnNullSafe = true;
 637: 
 638:         /**
 639:          * @param string      $strName     name of the column
 640:          * @param string|null $strProperty the property name to use when accessing the DataSource row object.
 641:          *                                 Can be null, in which case object will have the ->__toString() function called on it.
 642:          * @param QQNode      $objBaseNode if not null, the OrderBy and ReverseOrderBy clauses will be created using the property path and the given database node
 643:          */
 644:         public function __construct($strName, $strProperty, $objBaseNode = null) {
 645:             parent::__construct($strName);
 646:             $this->Property = $strProperty;
 647: 
 648:             if ($objBaseNode != null) {
 649:                 foreach ($this->strPropertiesArray as $strProperty) {
 650:                     $objBaseNode = $objBaseNode->$strProperty;
 651:                 }
 652: 
 653:                 $this->OrderByClause = QQ::OrderBy($objBaseNode);
 654:                 $this->ReverseOrderByClause = QQ::OrderBy($objBaseNode, 'desc');
 655:             }
 656:         }
 657: 
 658:         public function FetchCellObject($item) {
 659:             if ($this->blnNullSafe && $item == null)
 660:                 return null;
 661:             foreach ($this->strPropertiesArray as $strProperty) {
 662:                 $item = $item->$strProperty;
 663:                 if ($this->blnNullSafe && $item == null)
 664:                     break;
 665:             }
 666:             return $item;
 667:         }
 668: 
 669:         /**
 670:          * PHP magic method
 671:          *
 672:          * @param string $strName
 673:          *
 674:          * @return bool|int|mixed|QHtmlTableBase|string
 675:          * @throws Exception
 676:          * @throws QCallerException
 677:          */
 678:         public function __get($strName) {
 679:             switch ($strName) {
 680:                 case 'Property':
 681:                     return $this->strProperty;
 682:                 case 'NullSafe':
 683:                     return $this->blnNullSafe;
 684:                 default:
 685:                     try {
 686:                         return parent::__get($strName);
 687:                     } catch (QCallerException $objExc) {
 688:                         $objExc->IncrementOffset();
 689:                         throw $objExc;
 690:                     }
 691:             }
 692:         }
 693: 
 694:         /**
 695:          * PHP magic method
 696:          *
 697:          * @param string $strName
 698:          * @param string $mixValue
 699:          *
 700:          * @return mixed|void
 701:          * @throws Exception
 702:          * @throws QCallerException
 703:          * @throws QInvalidCastException
 704:          */
 705:         public function __set($strName, $mixValue) {
 706:             switch ($strName) {
 707:                 case "Property":
 708:                     try {
 709:                         $this->strProperty = QType::Cast($mixValue, QType::String);
 710:                         $this->strPropertiesArray = $this->strProperty ? explode('->', $this->strProperty) : array();
 711:                         break;
 712:                     } catch (QInvalidCastException $objExc) {
 713:                         $objExc->IncrementOffset();
 714:                         throw $objExc;
 715:                     }
 716: 
 717:                 case "NullSafe":
 718:                     try {
 719:                         $this->blnNullSafe = QType::Cast($mixValue, QType::Boolean);
 720:                         break;
 721:                     } catch (QInvalidCastException $objExc) {
 722:                         $objExc->IncrementOffset();
 723:                         throw $objExc;
 724:                     }
 725: 
 726:                 default:
 727:                     try {
 728:                         parent::__set($strName, $mixValue);
 729:                         break;
 730:                     } catch (QCallerException $objExc) {
 731:                         $objExc->IncrementOffset();
 732:                         throw $objExc;
 733:                     }
 734:             }
 735:         }
 736:     }
 737: 
 738:     /**
 739:      * Class QHtmlTableNodeColumn
 740:      *
 741:      * A table column that displays the content of a database column represented by a QQNode object.
 742:      * The $objNodes can be a single node, or an array of nodes. If an array of nodes, the first
 743:      * node will be the display node, and the rest of the nodes will be used for sorting.
 744:      */
 745:     class QHtmlTableNodeColumn extends QHtmlTablePropertyColumn {
 746:         public function __construct($strName, $objNodes) {
 747:             if ($objNodes instanceof QQNode) {
 748:                 $objNodes = [$objNodes];
 749:             }
 750:             elseif (empty($objNodes) || !is_array($objNodes) || !$objNodes[0] instanceof QQNode) {
 751:                 throw new QCallerException('Pass either a QQNode or an array of QQNodes only');
 752:             }
 753: 
 754:             $objNode = $objNodes[0]; // First node is the data node, the rest are for sorting.
 755: 
 756:             if (!$objNode->_ParentNode) {
 757:                 throw new QCallerException('First QQNode cannot be a Top Level Node');
 758:             }
 759:             if (($objNode instanceof QQReverseReferenceNode) && !$objNode->IsUnique()) {
 760:                 throw new QCallerException('Content QQNode cannot go through any "To Many" association nodes.');
 761:             }
 762: 
 763:             $properties = array($objNode->_PropertyName);
 764:             while ($objNode = $objNode->_ParentNode) {
 765:                 if (!($objNode instanceof QQNode))
 766:                     throw new QCallerException('QQNode cannot go through any "To Many" association nodes.');
 767:                 if (($objNode instanceof QQReverseReferenceNode) && !$objNode->IsUnique())
 768:                     throw new QCallerException('QQNode cannot go through any "To Many" association nodes.');
 769:                 if ($strPropName = $objNode->_PropertyName) {
 770:                     $properties[] = $strPropName;
 771:                 }
 772:             }
 773:             $properties = array_reverse($properties);
 774:             $strProp = implode ('->', $properties);
 775:             parent::__construct($strName, $strProp, null);
 776: 
 777:             // build sort nodes
 778:             foreach ($objNodes as $objNode) {
 779:                 if ($objNode instanceof QQReverseReferenceNode) {
 780:                     $objNode = $objNode->_PrimaryKeyNode;
 781:                 }
 782:                 $objSortNodes[] = $objNode;
 783:                 $objReverseNodes[] = $objNode;
 784:                 $objReverseNodes[] = false;
 785:             }
 786: 
 787:             $this->OrderByClause = QQ::OrderBy($objSortNodes);
 788:             $this->ReverseOrderByClause = QQ::OrderBy($objReverseNodes);
 789:         }
 790:     }
 791: 
 792: 
 793:     /**
 794:      * A type of column that should be used when the DataSource items are arrays
 795:      *
 796:      * @property int|string $Index the index or key to use when accessing the arrays in the DataSource array
 797:      *
 798:      */
 799:     class QHtmlTableIndexedColumn extends QAbstractHtmlTableDataColumn {
 800:         protected $mixIndex;
 801: 
 802:         /**
 803:          * @param string $strName name of the column
 804:          * @param int|string $mixIndex the index or key to use when accessing the DataSource row array
 805:          */
 806:         public function __construct($strName, $mixIndex) {
 807:             parent::__construct($strName);
 808:             $this->mixIndex = $mixIndex;
 809:         }
 810: 
 811:         public function FetchCellObject($item) {
 812:             if (isset ($item[$this->mixIndex])) {
 813:                 return $item[$this->mixIndex];
 814:             } else {
 815:                 return '';
 816:             }
 817:         }
 818: 
 819:         /**
 820:          * PHP magic method
 821:          *
 822:          * @param string $strName
 823:          *
 824:          * @return bool|int|mixed|QHtmlTableBase|string
 825:          * @throws Exception
 826:          * @throws QCallerException
 827:          */
 828:         public function __get($strName) {
 829:             switch ($strName) {
 830:                 case 'Index':
 831:                     return $this->mixIndex;
 832:                 default:
 833:                     try {
 834:                         return parent::__get($strName);
 835:                     } catch (QCallerException $objExc) {
 836:                         $objExc->IncrementOffset();
 837:                         throw $objExc;
 838:                     }
 839:             }
 840:         }
 841: 
 842:         /**
 843:          * PHP magic method
 844:          *
 845:          * @param string $strName
 846:          * @param string $mixValue
 847:          *
 848:          * @return mixed|void
 849:          * @throws Exception
 850:          * @throws QCallerException
 851:          */
 852:         public function __set($strName, $mixValue) {
 853:             switch ($strName) {
 854:                 case "Index":
 855:                     $this->mixIndex = $mixValue;
 856:                     break;
 857: 
 858:                 default:
 859:                     try {
 860:                         parent::__set($strName, $mixValue);
 861:                         break;
 862:                     } catch (QCallerException $objExc) {
 863:                         $objExc->IncrementOffset();
 864:                         throw $objExc;
 865:                     }
 866:             }
 867:         }
 868:     }
 869: 
 870:     /**
 871:      * A type of column that lets you use a PHP 'callable'. However, you CANNOT send a PHP closure to this,
 872:      * since closures are not serializable. You CAN do things like array($this, 'method'), or 'Class::StaticMethod'.
 873:      *
 874:      * @property int|string $Index the index or key to use when accessing the arrays in the DataSource array
 875:      *
 876:      */
 877:     class QHtmlTableCallableColumn extends QAbstractHtmlTableDataColumn {
 878:         /** @var callback */
 879:         protected $objCallable;
 880:         /** @var array extra parameters passed to closure */
 881:         protected $mixParams;
 882: 
 883:         /**
 884:          * @param string $strName name of the column
 885:          * @param callback $objCallable a callable object. It should take a single argument, the item
 886:          *   of the array. Do NOT pass an actual Closure object, as they are not serializable. However,
 887:          *   you can pass a callable, like array($this, 'method'), or an object that has the __invoke method defined,
 888:          *   as long as its serializable. You can also pass static methods as a string, as in "Class::method"
 889:          * @param mixed $mixParams extra parameters to pass to the closure callback.
 890:          * will be called with the row of the DataSource as that single argument.
 891:          *
 892:          * @throws InvalidArgumentException
 893:          */
 894:         public function __construct($strName, callable $objCallable, $mixParams = null) {
 895:             parent::__construct($strName);
 896:             if ($objCallable instanceof Closure) {
 897:                 throw new InvalidArgumentException('Cannot be a Closure.');
 898:             }
 899:             $this->objCallable = $objCallable;
 900:             $this->mixParams = $mixParams;
 901:         }
 902: 
 903:         public function FetchCellObject($item) {
 904:             if ($this->mixParams) {
 905:                 return call_user_func($this->objCallable, $item, $this->mixParams);
 906:             } else {
 907:                 return call_user_func($this->objCallable, $item);
 908:             }
 909:         }
 910: 
 911:         /**
 912:          * Fix up possible embedded reference to the form.
 913:          */
 914:         public function Sleep() {
 915:             $this->objCallable = QControl::SleepHelper($this->objCallable);
 916:             parent::Sleep();
 917:         }
 918: 
 919:         /**
 920:          * Restore serialized references.
 921:          * @param QForm $objForm
 922:          */
 923:         public function Wakeup(QForm $objForm) {
 924:             parent::Wakeup($objForm);
 925:             $this->objCallable = QControl::WakeupHelper($objForm, $this->objCallable);
 926:         }
 927: 
 928:         /**
 929:          * PHP magic method
 930:          *
 931:          * @param string $strName
 932:          *
 933:          * @return bool|callable|int|mixed|QHtmlTableBase|string
 934:          * @throws Exception
 935:          * @throws QCallerException
 936:          */
 937:         public function __get($strName) {
 938:             switch ($strName) {
 939:                 case 'Callable':
 940:                     return $this->objCallable;
 941:                 default:
 942:                     try {
 943:                         return parent::__get($strName);
 944:                     } catch (QCallerException $objExc) {
 945:                         $objExc->IncrementOffset();
 946:                         throw $objExc;
 947:                     }
 948:             }
 949:         }
 950: 
 951:         /**
 952:          * PHP magic method
 953:          *
 954:          * @param string $strName
 955:          * @param string $mixValue
 956:          *
 957:          * @return mixed|void
 958:          * @throws Exception
 959:          * @throws QCallerException
 960:          * @throws QInvalidCastException
 961:          */
 962:         public function __set($strName, $mixValue) {
 963:             switch ($strName) {
 964:                 case "Callable":
 965:                     if (!is_callable($mixValue)) {
 966:                         throw new QInvalidCastException("Callable must be a callable object");
 967:                     }
 968:                     $this->objCallable = $mixValue;
 969:                     break;
 970: 
 971:                 default:
 972:                     try {
 973:                         parent::__set($strName, $mixValue);
 974:                         break;
 975:                     } catch (QCallerException $objExc) {
 976:                         $objExc->IncrementOffset();
 977:                         throw $objExc;
 978:                     }
 979:             }
 980:         }
 981:     }
 982:     
 983:     /**
 984:      * 
 985:      * A column to display a virtual attribute from a database record.
 986:      *
 987:      * @property string $Attribute
 988:      */
 989:     class QVirtualAttributeColumn extends QAbstractHtmlTableDataColumn {
 990:         protected $strAttribute;
 991:         
 992:         public function __construct($strName, $strAttribute = null) {
 993:             parent::__construct($strName);
 994:             if ($strAttribute) {
 995:                 $this->strAttribute = $strAttribute;
 996:             }
 997: 
 998:             $this->OrderByClause = QQ::OrderBy(QQ::Virtual($strAttribute));
 999:             $this->ReverseOrderByClause = QQ::OrderBy(QQ::Virtual($strAttribute), false);
1000: 
1001:         }
1002:         
1003:         public function FetchCellObject($item) {
1004:             return $item->GetVirtualAttribute ($this->strAttribute);
1005:         }
1006: 
1007:         /**
1008:          * PHP magic method
1009:          *
1010:          * @param string $strName
1011:          *
1012:          * @return bool|int|mixed|null|QHtmlTableBase|string
1013:          * @throws Exception
1014:          * @throws QCallerException
1015:          */
1016:         public function __get($strName) {
1017:             switch ($strName) {
1018:                 case 'Attribute':
1019:                     return $this->strAttribute;
1020:                 default:
1021:                     try {
1022:                         return parent::__get($strName);
1023:                     } catch (QCallerException $objExc) {
1024:                         $objExc->IncrementOffset();
1025:                         throw $objExc;
1026:                     }
1027:             }
1028:         }
1029: 
1030:         /**
1031:          * PHP magic method
1032:          *
1033:          * @param string $strName
1034:          * @param string $mixValue
1035:          *
1036:          * @return mixed|void
1037:          * @throws Exception
1038:          * @throws QCallerException
1039:          * @throws QInvalidCastException
1040:          */
1041:         public function __set($strName, $mixValue) {
1042:             switch ($strName) {
1043:                 case "Attribute":
1044:                     $this->strAttribute = QType::Cast ($mixValue, QType::String);
1045:                     break;
1046: 
1047:                 default:
1048:                     try {
1049:                         parent::__set($strName, $mixValue);
1050:                         break;
1051:                     } catch (QCallerException $objExc) {
1052:                         $objExc->IncrementOffset();
1053:                         throw $objExc;
1054:                     }
1055:             }
1056:         }
1057:         
1058:     }
1059:     
1060:     /**
1061:      * 
1062:      * A column of checkboxes. 
1063:      * 
1064:      * Prints checkboxes in a column, including the header. Override this class and implement whatever hooks you need. In
1065:      * particular implement the CheckId hooks, and IsChecked hooks.
1066:      *
1067:      * To get the checkbox values to post values back to PHP, each checkbox must have an id of the form:
1068:      *
1069:      * QcontrolId_index
1070:      *
1071:      * This class does not detect and record changes in the checkbox list. You can detect changes from within
1072:      * ParsePostData by calling $this->objForm->CheckableControlValue,
1073:      * or use the QHtmlTableCheckBoxColumn_ClickEvent to detect a change to a checkbox.
1074:      *
1075:      * You will need to detect whether
1076:      * the header check all box was clicked, or a regular box was clicked and respond accordingly. In response to a
1077:      * click, you could store the array of ids of the checkboxes clicked in a session variable, the database, or
1078:      * a cache variable. You would just give an id to each checkbox. This would cause internet traffic every time
1079:      * a box is clicked.
1080:      *
1081:      * @property bool $ShowCheckAll
1082:      *
1083:      */
1084:     class QHtmlTableCheckBoxColumn extends QAbstractHtmlTableDataColumn {
1085:         protected $blnHtmlEntities = false; // turn off html entities
1086:         protected $checkParamCallback = null;
1087:         protected $blnShowCheckAll = false;
1088: 
1089:         /**
1090:          * Returns a header cell with a checkbox. This could be used as a check all box. Override this and return
1091:          * an empty string to turn it off.
1092:          *
1093:          * @return string
1094:          */
1095:         public function FetchHeaderCellValue() {
1096:             if ($this->blnShowCheckAll) {
1097:                 $aParams = $this->GetCheckboxParams(null);
1098:                 $aParams['type'] = 'checkbox';
1099:                 return QHtml::RenderTag('input', $aParams, null, true);
1100:             } else {
1101:                 return $this->Name;
1102:             }
1103:         }
1104: 
1105:         public function FetchCellObject($item) {
1106:             $aParams = $this->GetCheckboxParams($item);
1107:             $aParams['type'] = 'checkbox';
1108:             return QHtml::RenderTag('input', $aParams, null, true);
1109:         }
1110: 
1111:         /**
1112:          * Returns an array of parameters to attach to the checkbox tag. Includes whether the
1113:          * checkbox should appear as checked. Will try the callback first, and if not present,
1114:          * will try overridden functions.
1115:          * 
1116:          * @param mixed|null $item  Null to indicate that we want the params for the header cell.
1117:          * @return array
1118:          */
1119:         public function GetCheckboxParams ($item) {
1120:             $aParams = array();
1121:             
1122:             if ($strId = $this->GetCheckboxId ($item)) {
1123:                 $aParams['id'] = $strId;
1124:             }
1125:             
1126:             if ($this->IsChecked ($item)) {
1127:                 $aParams['checked'] = 'checked';
1128:             }
1129: 
1130:             if ($strName = $this->GetCheckboxName ($item)) {
1131:                 $aParams['name'] = $strName; // name is not used by QCubed
1132:             }
1133: 
1134:             $aParams['value'] = $this->GetCheckboxValue ($item); // note that value is required for html checkboxes, but is not used by QCubed
1135: 
1136:             if ($this->checkParamCallback) {
1137:                 $a = call_user_func($this->checkParamCallback, $item);
1138:                 $aParams = array_merge ($aParams, $a);
1139:             }
1140:             
1141:             return $aParams;        
1142:         }
1143: 
1144:         /**
1145:          * Optional callback to control the appearance of the checkboxes. You can use a callback, or subclass to do this.
1146:          * If a callback, it should be of the form:
1147:          *  func($item)
1148:          *
1149:          *  $item is either the line item, or null to indicate the header
1150:          *
1151:          * This should return the following values in an array to indicate what should be put as attributes for the checkbox tag:
1152:          *  id
1153:          *  name
1154:          *  value
1155:          *  checked (only return a value here if you want it checked. Otherwise, do not include in the array)
1156:          *
1157:          *  See below for a description of what should be returned for each item.
1158:          *
1159:          * @param $callable
1160:          */
1161:         public function SetCheckParamCallback ($callable) {
1162:             $this->checkParamCallback = $callable;
1163:         }
1164:         
1165:         /**
1166:          * Returns the id for the checkbox itself. This is used together with the check action to send the item
1167:          * id to the action. Your id should look like:
1168:          *
1169:          *
1170:          *
1171:          * @param mixed|null $item  Null to get the id for the header checkbox
1172:          */
1173:         protected function GetCheckboxId ($item) {
1174:             return null;
1175:         }
1176: 
1177:         /**
1178:          * Return true if the checkbox should be drawn checked. Override this to provide the correct value.
1179:          * @param mixed|null $item  Null to get the id for the header checkbox
1180:          * @return bool
1181:          */
1182:         protected function IsChecked ($item) {
1183:             return false;
1184:         }
1185: 
1186:         /**
1187:          * Return the name attribute for the checkbox. If you return null, the checkbox will not get submitted to the form.
1188:          * If you return a name, then that will be the key for the value submitted by the form. If you return a name
1189:          * ending with brackets [], then this checkbox will be part of an array of values posted to that name.
1190:          *
1191:          * @param mixed|null $item  Null to get the id for the header checkbox
1192:          * @return null|string
1193:          */
1194:         protected function GetCheckboxName ($item) {
1195:             return null;
1196:         }
1197: 
1198:         /**
1199:          * Return the value attribute of the checkbox tag. Checkboxes are required to have a value in html.
1200:          * This value will be what is posted by form post.
1201:          *
1202:          * @param mixed|null $item  Null to get the id for the header checkbox
1203:          * @return string
1204:          */
1205:         protected function GetCheckboxValue ($item) {
1206:             return "1"; // Means that if the checkbox is checked, the POST value corresponding to the name of the checkbox will be 1.
1207:         }
1208: 
1209:         /**
1210:          * Fix up possible embedded reference to the form.
1211:          */
1212:         public function Sleep() {
1213:             $this->checkParamCallback = QControl::SleepHelper($this->checkParamCallback);
1214:             parent::Sleep();
1215:         }
1216: 
1217:         /**
1218:          * Restore embedded objects.
1219:          * 
1220:          * @param QForm $objForm
1221:          */
1222:         public function Wakeup(QForm $objForm) {
1223:             parent::Wakeup($objForm);
1224:             $this->checkParamCallback = QControl::WakeupHelper($objForm, $this->checkParamCallback);
1225:         }
1226: 
1227:         /**
1228:          * PHP magic method
1229:          *
1230:          * @param string $strName
1231:          *
1232:          * @return bool|int|mixed|QHtmlTableBase|string
1233:          * @throws Exception
1234:          * @throws QCallerException
1235:          */
1236:         public function __get($strName) {
1237:             switch ($strName) {
1238:                 case 'ShowCheckAll':
1239:                     return $this->blnShowCheckAll;
1240:                 default:
1241:                     try {
1242:                         return parent::__get($strName);
1243:                     } catch (QCallerException $objExc) {
1244:                         $objExc->IncrementOffset();
1245:                         throw $objExc;
1246:                     }
1247:             }
1248:         }
1249: 
1250:         /**
1251:          * PHP magic method
1252:          *
1253:          * @param string $strName
1254:          * @param string $mixValue
1255:          *
1256:          * @return mixed|void
1257:          * @throws Exception
1258:          * @throws QCallerException
1259:          * @throws QInvalidCastException
1260:          */
1261:         public function __set($strName, $mixValue) {
1262:             switch ($strName) {
1263:                 case "ShowCheckAll":
1264:                     try {
1265:                         $this->blnShowCheckAll = QType::Cast($mixValue, QType::Boolean);
1266:                         break;
1267:                     } catch (QInvalidCastException $objExc) {
1268:                         $objExc->IncrementOffset();
1269:                         throw $objExc;
1270:                     }
1271: 
1272:                 default:
1273:                     try {
1274:                         parent::__set($strName, $mixValue);
1275:                         break;
1276:                     } catch (QCallerException $objExc) {
1277:                         $objExc->IncrementOffset();
1278:                         throw $objExc;
1279:                     }
1280:             }
1281:         }
1282: 
1283: 
1284:     }
1285: 
1286: 
1287:     class QHtmlTableCheckBoxColumn_ClickEvent extends QClickEvent {
1288:         const JsReturnParam = '{"row": $j(this).closest("tr")[0].rowIndex, "col": $j(this).parent()[0].cellIndex, "checked":this.checked, "id":this.id}'; // returns the array of cell info, and the new state of the checkbox
1289: 
1290:         public function __construct($intDelay = 0, $strCondition = null) {
1291:             parent::__construct($intDelay, $strCondition, 'input[type="checkbox"]');
1292:         }
1293:     }
1294: 
1295:     /**
1296:      * Class QHtmlTableLinkColumn
1297:      *
1298:      * A multi-purpose link column. This column lets you specify a column whose purpose is to show an anchor tag
1299:      * with text, attributes and properties related to row item. It can handle row items that are objects or arrays,
1300:      * and specify parameters or methods of objects, as well as offsets in arrays.
1301:      *
1302:      * You can specify the text of the link, the destination address, the html get variables, and the attributes
1303:      * to the anchor tag in a variety of ways as follows:
1304:      * - as a static string
1305:      * - as a two member array callable, with the row item passed to the callable
1306:      * - as an object property or string of properties (i.e. $item->prop1->prop2) by starting the string with "->" and
1307:      *   separating each property with a "->". If the property ends with "()", then it will be a method call instead.
1308:      *   The same can be accomplished by passing an array, with each item being a step in the property chain. This
1309:      *   is provided the row item is an object.
1310:      * - as an index into an array, or a multi-index array (i.e. $item['index1']['index2']) by passing a string of the
1311:      *   form "[index1][index2]...". You can also pass an array that contains the indexes into the array. This is provided
1312:      *   the row item is an array.
1313:      *
1314:      * Other options:
1315:      * - Specify null for $mixDestination, and no link will be created, just text. This is helpful for turning off the
1316:      *   link mode without having to create a completely different kind of column.
1317:      * - Specify a QControlProxy for $mixDestination to draw it as a proxy control. In this case, $blnAsButton can be
1318:      *   used to draw the proxy as a button rather than a link.
1319:      *
1320:      * Examples:
1321:      *
1322:      *  Create a column to edit a person, with "Edit" in the header, the name of the person as the label of each link, and give each
1323:      *   anchor a class of "link".
1324:      *  $objColumn = new QHtmlTableLinkColumn ("Edit", "->Name", "person_edit.php", ["intId"=>"->Id"], ["class"=>"link"]);
1325:      *
1326:      *
1327:      *  Create a similar column, but use a proxy instead, with the person id as the action parameter to the proxy and
1328:      *   drawing the proxy as a button.
1329:      *  $objProxy = new QControlProxy($this);
1330:      *  $objColumn = new QHtmlTableLinkColumn ("Edit", "Edit", $objProxy, "->Id", null, true);
1331:      *
1332:      *  Create a "zoom" column for a table that uses an array of arrays as its source. Pass the 'id' index from the item
1333:      *   as the id to the destination link. Use the "title" index as the label for the link.
1334:      *  $objColumn = new QHtmlTableLinkColumn ("Zoom", "[title]", "zoom.php", ["intId"=>"[id]"]);
1335:      *
1336:      *  Create a simple link column that just specifies a data attribute, and uses event delegation attached to the table to trap a click on the link.
1337:      *   Return the id of the item clicked to the action as the action parameter.
1338:      *  $objTable = new QHtmlTable ($this);
1339:      *  $objTable->CreateLinkColumn("", "->Name", "#", null, ["data-id"=>"->Id"]);
1340:      *  $objTable->AddAction(new QClickEvent(0, null, "a"), new QAjaxAction("myActionScript", null, null, '$j(this).data("id")'));
1341:      *
1342:      * @property bool $AsButton Only used if this is drawing a QControlProxy. Will draw the proxy as a button.
1343:      * @property-write null|string|array $Text The text to display as the label of the anchor, a callable callback to get the text,
1344:      *   a string that represents a property chain or a multi-dimensional array, or an array that represents the same. Depends on
1345:      *   what time of row item is passed.
1346:      * @property-write null|string|array|QControlProxy $Destination The text representing the destination of the anchor, a callable callback to get the destination,
1347:      *   a string that represents a property chain or a multi-dimensional array, or an array that represents the same,
1348:      *   or a QControlProxy. Depends on what time of row item is passed.
1349:      * @property-write null|string|array $GetVars An array of key=>value pairs to use as the GET variables in the link URL,
1350:      *   or in the case of a QControlProxy, possibly a string to represent the action parameter. In either case, each item
1351:      *   can be a property chain, an array index list, or a callable callback as specified above.
1352:      * @property-write null|array $TagAttributes An array of key=>value pairs to use as additional attributes in the tag.
1353:      *   For example, could be used to add a class or an id to each tag.
1354:      */
1355:     class QHtmlTableLinkColumn extends QAbstractHtmlTableDataColumn {
1356:         /** @var bool  */
1357:         protected $blnHtmlEntities = false; // we are rendering a link so turn off entities
1358: 
1359:         /** @var  string|array */
1360:         protected $mixText;
1361:         /** @var  string|array|QControlProxy|null */
1362:         protected $mixDestination;
1363:         /** @var  array|string|null */
1364:         protected $getVars;
1365:         /** @var  array|null */
1366:         protected $tagAttributes;
1367:         /** @var bool  */
1368:         protected $blnAsButton;
1369: 
1370:         /**
1371:          * QHtmlTableLinkColumn constructor.
1372:          *
1373:          * @param string $strName Column name to be displayed in the table header.
1374:          * @param null|string|array|QQNode $mixText The text to display as the label of the anchor, a callable callback to get the text,
1375:          *   a string that represents a property chain or a multi-dimensional array, or an array that represents the same, or a QQNode representing the property.
1376:          *   Depends on what type of row item is passed.
1377:          * @param null|string|array|QControlProxy $mixDestination The text representing the destination of the anchor, a callable callback to get the destination,
1378:          *   a string that represents a property chain or a multi-dimensional array, or an array that represents the same,
1379:          *   or a QControlProxy. Depends on what type of row item is passed.
1380:          * @param null|string|array $getVars An array of key=>value pairs to use as the GET variables in the link URL,
1381:          *   or in the case of a QControlProxy, possibly a string to represent the action parameter. In either case, each item
1382:          *   can be a property chain, an array index list, a QQNode, or a callable callback as specified above. If the destination is a
1383:          *   QControlProxy, this would be what to use as the action parameter.
1384:          * @param null|array $tagAttributes An array of key=>value pairs to use as additional attributes in the tag.
1385:          *   For example, could be used to add a class or an id to each tag.
1386:          * @param bool $blnAsButton Only used if this is drawing a QControlProxy. Will draw the proxy as a button.
1387:          */
1388:         public function __construct($strName, $mixText, $mixDestination = null, $getVars = null, $tagAttributes = null, $blnAsButton = false) {
1389:             parent::__construct($strName);
1390:             $this->Text = $mixText;
1391:             $this->Destination = $mixDestination;
1392:             $this->GetVars = $getVars;
1393:             $this->TagAttributes = $tagAttributes;
1394:             $this->blnAsButton = $blnAsButton;
1395:         }
1396: 
1397:         /**
1398:          * Utility function to pre-process a value specifier. This will take a property list chain or an array index
1399:          * chain and split it into an array representing the parts.
1400:          *
1401:          * @param mixed $mixSpec
1402:          * @return mixed
1403:          */
1404:         protected static function SplitSpec ($mixSpec)
1405:         {
1406:             if (is_array($mixSpec)) {
1407:                 return $mixSpec; // already split
1408:             } elseif (is_string($mixSpec)) {
1409:                 if (strpos($mixSpec, '->') === 0) {
1410:                     // It is an object property list ($item->param1->param2)
1411:                     $parts = explode('->', substr($mixSpec, 2));
1412:                     return $parts;
1413:                 } elseif ($mixSpec[0] == '[' && substr($mixSpec, -1) == ']') {
1414:                     // It is a list of array dereferences
1415:                     $parts = explode('][', $mixSpec, substr(1, strlen($mixSpec) - 2));
1416:                     return $parts;
1417:                 }
1418:                 else {
1419:                     return $mixSpec;
1420:                 }
1421:             } else {
1422:                 return $mixSpec;
1423:             }
1424:         }
1425: 
1426: 
1427:         /**
1428:          * Utility function to post-process a value specifier. Will walk through an object property chain or an array
1429:          * index chain and return the final value.
1430:          *
1431:          * @param mixed $mixSpec
1432:          * @param mixed $item
1433:          * @return string
1434:          */
1435:         protected static function GetObjectValue ($mixSpec, $item) {
1436:             if (is_array($mixSpec)) {
1437:                 if (is_object($mixSpec[0]) && is_callable($mixSpec)) {
1438:                     // If its a callable array, then call it
1439:                     return call_user_func($mixSpec, $item);
1440:                 }
1441:                 elseif (is_object($item)) {
1442:                     // It is an object property list ($item->param1->param2 or $item->method()->method2()). Can mix these too.
1443:                     $value = $item;
1444:                     foreach ($mixSpec as $part) {
1445:                         // Evaluate as a function, or a param
1446:                         if (substr($part,-2) == '()') {
1447:                             // call as a method
1448:                             $value = $value->$part();
1449:                         } else {
1450:                             $value = $value->$part;
1451:                         }
1452:                     }
1453:                     return $value;
1454:                 }
1455:                 elseif (is_array($item)) {
1456:                     $value = $item;
1457:                     foreach ($mixSpec as $part) {
1458:                         $value = $value[$part];
1459:                     }
1460:                     return $value;
1461:                 }
1462:                 else {
1463:                     return $item; // We have no idea what this is, so return the item for possible further processing
1464:                 }
1465:             }
1466:             elseif ($mixSpec instanceof QQNode) {
1467:                 $properties = array($mixSpec->_PropertyName);
1468:                 $objNode = $mixSpec;
1469:                 while ($objNode = $objNode->_ParentNode) {
1470:                     if (!($objNode instanceof QQNode))
1471:                         throw new QCallerException('QQNode cannot go through any "To Many" association nodes.');
1472:                     if (($objNode instanceof QQReverseReferenceNode) && !$objNode->IsUnique())
1473:                         throw new QCallerException('QQNode cannot go through any "To Many" association nodes.');
1474:                     if ($strPropName = $objNode->_PropertyName) {
1475:                         $properties[] = $strPropName;
1476:                     }
1477:                 }
1478:                 $properties = array_reverse($properties);
1479:                 $value = $item;
1480:                 foreach ($properties as $prop) {
1481:                     $value = $value->$prop;
1482:                 }
1483:                 if (is_object($value)) {
1484:                     return $value->__toString();
1485:                 }
1486:                 else {
1487:                     return $value;
1488:                 }
1489:             }
1490:             return $mixSpec; // In this case, we return a static value
1491:         }
1492: 
1493:         /**
1494:          * Returns the initial text that will be the label of the link. This text can be further processed by using
1495:          * the inherited PostCallback function and similar properties.
1496:          *
1497:          * @param mixed $item
1498:          * @return string
1499:          */
1500:         public function FetchCellObject($item)
1501:         {
1502:             return static::GetObjectValue($this->mixText, $item);
1503:         }
1504: 
1505:         /**
1506:          * Returns the final string representing the content of the cell.
1507:          *
1508:          * @param mixed $item
1509:          * @return string
1510:          */
1511:         public function FetchCellValue($item) {
1512:             $strText = parent::FetchCellValue($item);   // allow post processing of cell label
1513: 
1514:             $getVars = null;
1515:             if ($this->getVars) {
1516:                 if (is_array($this->getVars)) {
1517:                     if (array_keys($this->getVars)[0] === 0) {
1518:                         // assume this is not associative array. Likely we are here to extract a property list.
1519:                         $getVars = static::GetObjectValue($this->getVars, $item);
1520:                     }
1521:                     else {
1522:                         // associative array, so likely these are Get variables to be assigned individually
1523:                         foreach ($this->getVars as $key => $val) {
1524:                             $getVars[$key] = static::GetObjectValue($val, $item);
1525:                         }
1526:                     }
1527:                 }
1528:                 elseif ($this->getVars instanceof QQNode) {
1529:                     $getVars = static::GetObjectValue($this->getVars, $item);
1530:                 }
1531:                 else {
1532:                     $getVars = $this->getVars; // could be a simple action parameter.
1533:                 }
1534:             }
1535: 
1536:             $tagAttributes = [];
1537:             if ($this->tagAttributes && is_array($this->tagAttributes)) {
1538:                 foreach ($this->tagAttributes as $key=>$val) {
1539:                     $tagAttributes[$key] = static::GetObjectValue($val, $item);
1540:                 }
1541:             }
1542: 
1543:             if ($this->mixDestination === null) {
1544:                 return QApplication::HtmlEntities($strText);
1545:             }
1546:             elseif ($this->mixDestination instanceof QControlProxy) {
1547:                 if ($this->blnAsButton) {
1548:                     return $this->mixDestination->RenderAsButton($strText, $getVars, $tagAttributes);
1549:                 } else {
1550:                     return $this->mixDestination->RenderAsLink($strText, $getVars, $tagAttributes);
1551:                 }
1552:             }
1553:             else {
1554:                 $strDestination = static::GetObjectValue($this->mixDestination, $item);
1555:                 return QHtml::RenderLink(QHtml::MakeUrl($strDestination, $getVars), $strText, $tagAttributes);
1556:             }
1557:         }
1558: 
1559:         /**
1560:          * Fix up possible embedded references to the form.
1561:          */
1562:         public function Sleep() {
1563:             $this->mixText = QControl::SleepHelper($this->mixText);
1564:             $this->mixDestination = QControl::SleepHelper($this->mixDestination);
1565:             $this->getVars = QControl::SleepHelper($this->getVars);
1566:             $this->tagAttributes = QControl::SleepHelper($this->tagAttributes);
1567:             parent::Sleep();
1568:         }
1569: 
1570:         /**
1571:          * Restore embedded objects.
1572:          *
1573:          * @param QForm $objForm
1574:          */
1575:         public function Wakeup(QForm $objForm) {
1576:             parent::Wakeup($objForm);
1577:             $this->mixText = QControl::WakeupHelper($objForm, $this->mixText);
1578:             $this->mixDestination = QControl::WakeupHelper($objForm, $this->mixDestination);
1579:             $this->getVars = QControl::WakeupHelper($objForm, $this->getVars);
1580:             $this->tagAttributes = QControl::WakeupHelper($objForm, $this->tagAttributes);
1581:         }
1582: 
1583: 
1584:         /**
1585:          * PHP magic method
1586:          *
1587:          * @param string $strName
1588:          *
1589:          * @return bool|int|mixed|QHtmlTableBase|string
1590:          * @throws Exception
1591:          * @throws QCallerException
1592:          */
1593:         public function __get($strName) {
1594:             switch ($strName) {
1595:                 case 'AsButton':
1596:                     return $this->blnAsButton;
1597:                 default:
1598:                     try {
1599:                         return parent::__get($strName);
1600:                     } catch (QCallerException $objExc) {
1601:                         $objExc->IncrementOffset();
1602:                         throw $objExc;
1603:                     }
1604:             }
1605:         }
1606: 
1607:         /**
1608:          * PHP magic method
1609:          *
1610:          * @param string $strName
1611:          * @param string $mixValue
1612:          *
1613:          * @return mixed|void
1614:          * @throws Exception
1615:          * @throws QCallerException
1616:          * @throws QInvalidCastException
1617:          */
1618:         public function __set($strName, $mixValue) {
1619:             switch ($strName) {
1620:                 case "AsButton":
1621:                     try {
1622:                         $this->blnAsButton = QType::Cast($mixValue, QType::Boolean);
1623:                         break;
1624:                     } catch (QInvalidCastException $objExc) {
1625:                         $objExc->IncrementOffset();
1626:                         throw $objExc;
1627:                     }
1628: 
1629:                 case "Text":
1630:                     $this->mixText = self::SplitSpec($mixValue);
1631:                     break;
1632: 
1633:                 case "Destination":
1634:                     if ($mixValue instanceof QControlProxy) {
1635:                         $this->mixDestination = $mixValue;
1636:                     } else {
1637:                         $this->mixDestination = self::SplitSpec($mixValue);
1638:                     }
1639:                     break;
1640: 
1641:                 case "GetVars":
1642:                     try {
1643:                         if (is_null($mixValue)) {
1644:                             $this->getVars = null;
1645:                         }
1646:                         elseif (is_string($mixValue)) {
1647:                             $this->getVars = self::SplitSpec($mixValue); // a simple action parameter for a control proxy
1648:                         }
1649:                         elseif (is_array($mixValue)) {
1650:                             $this->getVars = [];
1651:                             foreach ($mixValue as $key=>$val) {
1652:                                 $this->getVars[$key] = self::SplitSpec($val);
1653:                             }
1654:                         }
1655:                         elseif ($mixValue instanceof QQNode) {
1656:                             $this->getVars = $mixValue;
1657:                         }
1658:                         else {
1659:                             throw new Exception ("Invalid type");
1660:                         }
1661:                         break;
1662:                     } catch (QInvalidCastException $objExc) {
1663:                         $objExc->IncrementOffset();
1664:                         throw $objExc;
1665:                     }
1666: 
1667:                 case "TagAttributes":
1668:                     try {
1669:                         if (is_null($mixValue)) {
1670:                             $this->tagAttributes = null;
1671:                         }
1672:                         elseif (is_array($mixValue)) {
1673:                             $this->tagAttributes = [];
1674:                             foreach ($mixValue as $key=>$val) {
1675:                                 $this->tagAttributes[$key] = self::SplitSpec($val);
1676:                             }
1677:                         }
1678:                         else {
1679:                             throw new Exception ("Invalid type");
1680:                         }
1681:                         break;
1682:                     } catch (QInvalidCastException $objExc) {
1683:                         $objExc->IncrementOffset();
1684:                         throw $objExc;
1685:                     }
1686: 
1687:                 default:
1688:                     try {
1689:                         parent::__set($strName, $mixValue);
1690:                         break;
1691:                     } catch (QCallerException $objExc) {
1692:                         $objExc->IncrementOffset();
1693:                         throw $objExc;
1694:                     }
1695:             }
1696:         }
1697: 
1698: 
1699: 
1700:     }
1701: 
API documentation generated by ApiGen