示例#1
0
/**
 * function to get multilanguage strings.
 *
 * This is actually a wrapper for ATK's Tools::atktext() method, for
 * use in templates.
 *
 * @author Ivo Jansch <*****@*****.**>
 *
 * Example: {atktext id="users.userinfo.description"}
 *          {atktext id="userinfo.description" module="users"}
 *          {atktext id="description" module="users" node="userinfo"}
 */
function smarty_function_atktext($params, $smarty)
{
    if (!isset($params['id'])) {
        $params['id'] = $params[0];
    }
    switch (substr_count($params['id'], '.')) {
        case 1:
            list($module, $id) = explode('.', $params['id']);
            $str = Tools::atktext($id, $module, isset($params['node']) ? $params['node'] : '');
            break;
        case 2:
            list($module, $node, $id) = explode('.', $params['id']);
            $str = Tools::atktext($id, $module, $node);
            break;
        default:
            $str = Tools::atktext($params['id'], Tools::atkArrayNvl($params, 'module', ''), Tools::atkArrayNvl($params, 'node', ''), Tools::atkArrayNvl($params, 'lng', ''));
    }
    if (isset($params['filter'])) {
        $fn = $params['filter'];
        $str = $fn($str);
    }
    // parse the rest of the params in the string
    $parser = new StringParser($str);
    return $parser->parse($params);
}
示例#2
0
 /**
  * Parse the target string.
  *
  * @param string $string The string to parse
  * @param array $recordset The recordset to use for parsing the string
  *
  * @return string The parsed string
  */
 public function parseString($string, $recordset)
 {
     $parser = new StringParser($string);
     // for backwardscompatibility reasons, we also support the '[pk]' var.
     $recordset['pk'] = $this->getNode()->primaryKey($recordset);
     $output = $parser->parse($recordset, true);
     return $output;
 }
示例#3
0
 public function search($record, $extended = false, $fieldprefix = '', DataGrid $grid = null)
 {
     $this->createDestination();
     if ($this->m_destinationFilter != '') {
         $sp = new StringParser($this->m_destinationFilter);
         $this->m_destInstance->addFilter($sp->parse($record));
     }
     $recordset = $this->m_destInstance->select()->includes(Tools::atk_array_merge($this->m_destInstance->descriptorFields(), $this->m_destInstance->m_primaryKey))->getAllRows();
     $result = '<select class="form-control" name="atksearch[' . $this->fieldName() . ']">';
     $result .= '<option value="">' . Tools::atktext('search_all', 'atk');
     $result .= $this->createdd($recordset);
     $result .= '</select>';
     return $result;
 }
示例#4
0
 /**
  * Converts a database value to an internal value.
  *
  * For this attribute the value will be read from a file (if possible)
  *
  * @param array $record The database record that holds this attribute's value
  *
  * @return mixed The internal value
  */
 public function db2value($record)
 {
     // determine filename.
     $parser = new StringParser($this->m_filename);
     $filename = $parser->parse($record);
     if (!file_exists($filename)) {
         Tools::atkdebug('[' . $this->fieldName() . "] warning: {$filename} doesn't exist");
         return $record[$this->fieldName()];
     } else {
         if ($record[$this->fieldName()] == '') {
             // db is empty. if file contains stuff, use that.
             $contents = implode('', file($filename));
             Tools::atkdebug('[' . $this->fieldName() . "] succesfully read {$filename}");
             return $contents;
         } else {
             return $record[$this->fieldName()];
         }
     }
 }
示例#5
0
 /**
  * Renders the summary for the given data grid.
  *
  * @return string rendered HTML
  */
 public function render()
 {
     $grid = $this->getGrid();
     $limit = $grid->getLimit();
     $count = $grid->getCount();
     if ($count == 0) {
         return;
     }
     if ($limit == -1) {
         $limit = $count;
     }
     $start = $grid->getOffset();
     $end = min($start + $limit, $count);
     $page = floor($start / $limit + 1);
     $pages = ceil($count / $limit);
     $string = $grid->text('datagrid_summary');
     $params = array('start' => $start + 1, 'end' => $end, 'count' => $count, 'limit' => $limit, 'page' => $page, 'pages' => $pages);
     $parser = new StringParser($string);
     $result = $parser->parse($params);
     return '<div class="dgridsummary">' . $result . '</div>';
 }
示例#6
0
 /**
  * Parses a record.
  *
  * @param array $record Array with fields
  * @param string $mode
  *
  * @return string Parsed string
  */
 public function display($record, $mode)
 {
     $stringparser = new StringParser($this->m_text);
     return $stringparser->parse($record);
 }
示例#7
0
文件: DbAuth.php 项目: sintattica/atk
 /**
  * This function returns the list of users that may login. This can be
  * used to display a dropdown of users from which to choose.
  *
  * @return array List of users as an associative array with the following
  *               format: array of records, each record is an associative
  *               array with a userid and a username field.
  */
 public function getUserList()
 {
     $db = Db::getInstance(Config::getGlobal('auth_database'));
     $query = 'SELECT * FROM ' . Config::getGlobal('auth_usertable');
     $accountdisablefield = Config::getGlobal('auth_accountdisablefield');
     $accountenableexpression = Config::getGlobal('auth_accountenableexpression');
     if ($accountenableexpression != '') {
         $query .= " WHERE {$accountenableexpression}";
         if ($accountdisablefield != '') {
             $query .= " AND {$accountdisablefield} = 0";
         }
     } else {
         if ($accountdisablefield != '') {
             $query .= " WHERE {$accountdisablefield} = 0";
         }
     }
     $recs = $db->getRows($query);
     $userlist = [];
     $stringparser = new StringParser(Config::getGlobal('auth_userdescriptor'));
     for ($i = 0, $_i = count($recs); $i < $_i; ++$i) {
         $userlist[] = array('userid' => $recs[$i][Config::getGlobal('auth_userfield')], 'username' => $stringparser->parse($recs[$i]));
     }
     usort($userlist, array('auth_db', 'userListCompare'));
     return $userlist;
 }
示例#8
0
 /**
  * Get Concat filter.
  *
  * @param string $searchValue Search value
  * @param string $fieldaliasprefix Field alias prefix
  *
  * @return string|bool
  */
 public function getConcatFilter($searchValue, $fieldaliasprefix = '')
 {
     // If we have a descriptor with multiple fields, use CONCAT
     $attribs = $this->m_destInstance->descriptorFields();
     if (count($attribs) > 1) {
         $fields = [];
         foreach ($attribs as $attribname) {
             $post = '';
             if (strstr($attribname, '.')) {
                 if ($fieldaliasprefix != '') {
                     $table = $fieldaliasprefix . '_AE_';
                 } else {
                     $table = '';
                 }
                 $post = substr($attribname, strpos($attribname, '.'));
                 $attribname = substr($attribname, 0, strpos($attribname, '.'));
             } elseif ($fieldaliasprefix != '') {
                 $table = $fieldaliasprefix . '.';
             } else {
                 $table = $this->m_destInstance->m_table . '.';
             }
             /** @var Attribute $p_attrib */
             $p_attrib = $this->m_destInstance->m_attribList[$attribname];
             $fields[$p_attrib->fieldName()] = $table . $p_attrib->fieldName() . $post;
         }
         if (is_array($searchValue)) {
             // (fix warning trim function)
             $searchValue = $searchValue[0];
         }
         $value = $this->escapeSQL(trim($searchValue));
         $value = str_replace('  ', ' ', $value);
         if (!$value) {
             return false;
         } else {
             $function = $this->getConcatDescriptorFunction();
             if ($function != '' && method_exists($this->m_destInstance, $function)) {
                 $descriptordef = $this->m_destInstance->{$function}();
             } elseif ($this->m_destInstance->m_descTemplate != null) {
                 $descriptordef = $this->m_destInstance->m_descTemplate;
             } elseif (method_exists($this->m_destInstance, 'descriptor_def')) {
                 $descriptordef = $this->m_destInstance->descriptor_def();
             } else {
                 $descriptordef = $this->m_destInstance->descriptor(null);
             }
             $parser = new StringParser($descriptordef);
             $concatFields = $parser->getAllParsedFieldsAsArray($fields, true);
             $concatTags = $concatFields['tags'];
             $concatSeparators = $concatFields['separators'];
             $concatSeparators[] = ' ';
             //the query removes all spaces, so let's do the same here [Bjorn]
             // to search independent of characters between tags, like spaces and comma's,
             // we remove all these separators so we can search for just the concatenated tags in concat_ws [Jeroen]
             foreach ($concatSeparators as $separator) {
                 $value = str_replace($separator, '', $value);
             }
             $db = $this->getDb();
             $searchcondition = 'UPPER(' . $db->func_concat_ws($concatTags, '', true) . ") LIKE UPPER('%" . $value . "%')";
         }
         return $searchcondition;
     }
     return false;
 }
 /**
  * Render the multiselect list control.
  *
  * @param string $name The name of the list control
  * @param array $recordset The list of records to render in the control
  * @param string $opposite The name of the list control connected to this list control for shuttle actions
  * @param string $prefix The prefix which is needed for determining the correct JS name
  * @param bool $isSelected Whether or not this is the selectbox with the selectedItems (needed for onchangecode)
  *
  * @return string piece of html code
  */
 protected function _renderSelect($name, $recordset, $opposite, $prefix, $isSelected)
 {
     if ($isSelected) {
         $onchangecode = $this->getHtmlId($prefix) . '_onChange(\'selected\');';
         $action = 'del';
     } else {
         $onchangecode = $this->getHtmlId($prefix) . '_onChange(\'available\');';
         $action = 'add';
     }
     $valName = $this->getHtmlId($prefix) . '[selected][][' . $this->getRemoteKey() . ']';
     $result = '<select class="shuttle_select" id="' . $name . '" name="' . $name . '" multiple size="10" onDblClick="shuttle_move(\'' . $name . '\', \'' . $opposite . '\',\'' . $action . '\',\'' . $valName . '\');' . $onchangecode . '">';
     $parser = null;
     // Only import the stringparser once.
     if (isset($this->m_descriptor_tooltip_template)) {
         $parser = new StringParser($this->m_descriptor_tooltip_template);
     }
     for ($i = 0, $_i = count($recordset); $i < $_i; ++$i) {
         $title = $this->m_destInstance->descriptor($recordset[$i]);
         $ttip = isset($this->m_descriptor_tooltip_template) ? $parser->parse($recordset[$i]) : $title;
         $ttip = str_replace('\\r\\n', ' ', strip_tags($ttip));
         $result .= '<option value="' . $recordset[$i][$this->m_destInstance->primaryKeyField()] . '" title="' . $ttip . '">' . htmlentities($title) . '</option>';
     }
     $result .= '</select>';
     return $result;
 }
示例#10
0
 /**
  * The load method performs the calculation.
  *
  * @param Db $db
  * @param array $record
  * @param string $mode
  *
  * @return string result of the calculation
  */
 public function load($db, $record, $mode)
 {
     $parser = new StringParser($this->m_calculation);
     $result = 0;
     eval('$result = ' . $parser->parse($record) . ';');
     return $result;
 }
示例#11
0
文件: Node.php 项目: sintattica/atk
 /**
  * Determine a descriptor of a record.
  *
  * The descriptor is a string that describes a record for the user. For
  * person records, this may be the firstname and the lastname, for
  * companies it may be the company name plus the city etc.
  * The descriptor is used when displaying records in a dropdown for
  * example, or in the title of editpages, delete confirmations etc.
  *
  * The descriptor method calls a method named descriptor_def() on the node
  * to retrieve a template for the descriptor (string with attributenames
  * between blockquotes, for example "[lastname], [firstname]".
  *
  * If the node has no descriptor_def() method, the first attribute of the
  * node is used as descriptor.
  *
  * Derived classes may override this method to implement custom descriptor
  * logic.
  *
  * @param array $record The record for which the descriptor is returned.
  *
  * @return string The descriptor for the record.
  */
 public function descriptor($record)
 {
     // Descriptor handler is set?
     if ($this->m_descHandler != null) {
         return $this->m_descHandler->descriptor($record, $this);
     }
     // Descriptor template is set?
     if ($this->m_descTemplate != null) {
         $parser = new StringParser($this->m_descTemplate);
         return $parser->parse($record);
     } else {
         if (method_exists($this, 'descriptor_def')) {
             $parser = new StringParser($this->descriptor_def());
             return $parser->parse($record);
         } else {
             // default descriptor.. (default is first attribute of a node)
             $keys = array_keys($this->m_attribList);
             return $record[$keys[0]];
         }
     }
 }
示例#12
0
 /**
  * Determine the real filename of a file (based on m_filenameTpl).
  *
  * @param array $rec The record
  * @param string $default The default filename
  *
  * @return string The real filename based on the filename template
  */
 public function filenameMangle($rec, $default)
 {
     if ($this->m_filenameTpl == '') {
         $filename = $default;
     } else {
         $parser = new StringParser($this->m_filenameTpl);
         $includes = $parser->getAttributes();
         $record = $this->m_ownerInstance->updateRecord($rec, $includes, array($this->fieldName()));
         $record[$this->fieldName()] = substr($default, 0, strrpos($default, '.'));
         $ext = $this->getFileExtension($default);
         $filename = $parser->parse($record) . ($ext != '' ? '.' . $ext : '');
     }
     return str_replace(' ', '_', $filename);
 }
示例#13
0
 /**
  * Function outputs an array with all information necessary to output a recordlist.
  *
  * @param array $recordset List of records that need to be displayed
  * @param string $prefix Prefix for each column name (used for subcalls)
  * @param array $actions List of default actions for each record
  * @param array $suppress An array of fields that you want to hide
  *
  * The result array contains the following information:
  *  "name"     => the name of the recordlist
  *  "heading"  => for each visible column an array containing: "title" {, "url"}
  *  "search"   => for each visible column HTML input field(s) for searching
  *  "rows"     => list of rows, per row: "data", "actions", "mra", "record"
  *  "totalraw" => for each totalisable column the sum value field(s) (raw)
  *  "total"    => for each totalisable column the sum value (display)
  *  "mra"      => list of all multi-record actions
  *
  * @return array see above
  */
 private function listArray(&$recordset, $prefix = '', $actions = [], $suppress = array())
 {
     $grid = $this->getGrid();
     $flags = $this->convertDataGridFlags();
     if (!is_array($suppress)) {
         $suppress = [];
     }
     $result = array('name' => $grid->getName(), 'heading' => [], 'search' => [], 'rows' => [], 'totalraw' => [], 'total' => [], 'mra' => []);
     $columnConfig = $grid->getNode()->getColumnConfig($grid->getName());
     if (!Tools::hasFlag($flags, RecordList::RL_NO_SEARCH) || $grid->isEditing()) {
         $grid->getNode()->setAttribSizes();
     }
     $this->_addListArrayHeader($result, $prefix, $suppress, $flags, $columnConfig);
     /* actions array can contain multi-record-actions */
     if (count($actions) == 2 && count(array_diff(array_keys($actions), array('actions', 'mra'))) == 0) {
         $mra = $actions['mra'];
         $actions = $actions['actions'];
     } else {
         $mra = $grid->getNode()->hasFlag(Node::NF_NO_DELETE) ? [] : array('delete');
     }
     /* get the rows */
     for ($i = 0, $_i = count($recordset); $i < $_i; ++$i) {
         $result['rows'][$i] = array('columns' => [], 'actions' => $actions, 'mra' => $mra, 'record' => &$recordset[$i], 'data' => []);
         $result['rows'][$i]['selector'] = $grid->getNode()->primaryKey($recordset[$i]);
         $result['rows'][$i]['type'] = 'data';
         $row =& $result['rows'][$i];
         /* actions / mra */
         $grid->getNode()->collectRecordActions($row['record'], $row['actions'], $row['mra']);
         // filter actions we are allowed to execute
         foreach ($row['actions'] as $name => $url) {
             if (!empty($url) && $grid->getNode()->allowed($name, $row['record'])) {
                 /* dirty hack */
                 $atkencoded = strpos($url, '_15B') > 0;
                 $url = str_replace('%5B', '[', $url);
                 $url = str_replace('%5D', ']', $url);
                 $url = str_replace('_1' . '5B', '[', $url);
                 $url = str_replace('_1' . '5D', ']', $url);
                 if ($atkencoded) {
                     $url = str_replace('[pk]', Tools::atkurlencode(rawurlencode($row['selector']), false), $url);
                 } else {
                     $url = str_replace('[pk]', rawurlencode($row['selector']), $url);
                 }
                 $parser = new StringParser($url);
                 $url = $parser->parse($row['record'], true, false);
                 $row['actions'][$name] = $url;
             } else {
                 unset($row['actions'][$name]);
             }
         }
         // filter multi-record-actions we are allowed to execute
         foreach ($row['mra'] as $j => $name) {
             if (!$grid->getNode()->allowed($name, $row['record'])) {
                 unset($row['mra'][$j]);
             }
         }
         $row['mra'] = array_values($row['mra']);
         $result['mra'] = array_merge($result['mra'], $row['mra']);
         /* columns */
         $editAllowed = $grid->getPostvar('atkgridedit', false) && $grid->getNode()->allowed('edit', $result['rows'][$i]['record']);
         $result['rows'][$i]['edit'] = $editAllowed;
         $this->_addListArrayRow($result, $prefix, $suppress, $flags, $i, $editAllowed);
     }
     // override totals
     if (is_array($result['total']) && count($result['total']) > 0) {
         $selector = $grid->getNode()->select()->ignoreDefaultFilters();
         foreach ($grid->getFilters() as $filter) {
             $selector->where($filter['filter'], $filter['params']);
         }
         $result['totalraw'] = $selector->getTotals(array_keys($result['total']));
         foreach ($result['totalraw'] as $attrName => $value) {
             $result['total'][$attrName] = $grid->getNode()->getAttribute($attrName)->getView('list', $result['totalraw']);
         }
     }
     if (Tools::hasFlag($flags, RecordList::RL_EXT_SORT) && $columnConfig->hasSubTotals()) {
         $totalizer = new Totalizer($grid->getNode(), $columnConfig);
         $result['rows'] = $totalizer->totalize($result['rows']);
     }
     if (Tools::hasFlag($flags, RecordList::RL_MRA)) {
         $result['mra'] = array_values(array_unique($result['mra']));
     }
     return $result;
 }
示例#14
0
 public function getSearchCondition(Query $query, $table, $value, $searchmode, $fieldname = '')
 {
     $searchconditions = [];
     // Get search condition for all searchFields
     foreach ($this->m_searchfields as $field) {
         $p_attrib = $this->m_ownerInstance->getAttribute($field);
         if (is_object($p_attrib)) {
             $condition = $p_attrib->getSearchCondition($query, $table, $value, $searchmode);
             if (!empty($condition)) {
                 $searchconditions[] = $condition;
             }
         }
     }
     // When searchmode is substring also search the value in a concat of all searchfields
     if ($searchmode == 'substring') {
         $value = $this->escapeSQL(trim($value));
         $data = [];
         foreach ($this->m_searchfields as $field) {
             if (strpos($field, '.') == false) {
                 $data[$field] = $table . '.' . $field;
             } else {
                 $data[$field] = $field;
             }
         }
         $parser = new StringParser($this->m_template);
         $concatFields = $parser->getAllParsedFieldsAsArray($data, true);
         $concatTags = $concatFields['tags'];
         $concatSeparators = $concatFields['separators'];
         // to search independent of characters between tags, like spaces and comma's,
         // we remove all these separators (defined in the node with new atkAggregatedColumn)
         // so we can search for just the concatenated tags in concat_ws [Jeroen]
         foreach ($concatSeparators as $separator) {
             $value = str_replace($separator, '', $value);
         }
         $db = $this->getDb();
         $condition = 'UPPER(' . $db->func_concat_ws($concatTags, '', true) . ") LIKE UPPER('%" . $value . "%')";
         $searchconditions[] = $condition;
     }
     if (count($searchconditions)) {
         return '(' . implode(' OR ', $searchconditions) . ')';
     }
     return '';
 }
示例#15
0
 /**
  * If the auto-select flag is set and only one record exists we immediately
  * return with the selected record.
  *
  * @param DataGrid $grid data grid
  *
  * @return bool auto-select active?
  */
 protected function autoSelectRecord($grid)
 {
     $node = $this->getNode();
     if (!$node->hasFlag(Node::NF_AUTOSELECT)) {
         return false;
     }
     $grid->loadRecords();
     if ($grid->getCount() != 1) {
         return false;
     }
     $sm = SessionManager::getInstance();
     if ($sm->atkLevel() > 0 && $grid->getPostvar('atkprevlevel', 0) > $sm->atkLevel()) {
         $backUrl = $sm->sessionUrl(Config::getGlobal('dispatcher') . '?atklevel=' . $sm->newLevel(SessionManager::SESSION_BACK));
         $node->redirect($backUrl);
     } else {
         $records = $grid->getRecords();
         // There's only one record and the autoselect flag is set, so we
         // automatically go to the target.
         $parser = new StringParser(rawurldecode(Tools::atkurldecode($grid->getPostvar('atktarget'))));
         // For backwardscompatibility reasons, we also support the '[pk]' var.
         $records[0]['pk'] = $node->primaryKey($records[0]);
         $target = $parser->parse($records[0], true);
         $node->redirect($sm->sessionUrl($target, SessionManager::SESSION_NESTED));
     }
     return true;
 }
示例#16
0
 /**
  * Parses the destination filter.
  *
  * @param string $destFilter filter to parse
  * @param array $record the current record
  *
  * @return string $filter
  */
 public function parseFilter($destFilter, $record)
 {
     if ($destFilter != '') {
         $parser = new StringParser($destFilter);
         return $parser->parse($record);
     }
     return '';
 }
示例#17
0
 /**
  * Initialize when we create the datagrid for the first time.
  */
 protected function initOnCreate()
 {
     $this->setFlags($this->convertNodeFlags($this->getNode()->getFlags()));
     $this->setBaseUrl(Tools::partial_url($this->getNode()->atkNodeUri(), $this->getNode()->m_action, 'datagrid'));
     $this->setDefaultLimit(Config::getGlobal('recordsperpage'));
     $this->setDefaultActions($this->getNode()->defaultActions('admin'));
     $this->setDefaultOrderBy($this->getNode()->getOrder());
     $this->setTemplate('datagrid.tpl');
     $this->setActionSessionStatus(SessionManager::SESSION_NESTED);
     $this->setMode('admin');
     $this->setMRASelectionMode($this->getNode()->getMRASelectionMode());
     if (!$this->getNode()->hasFlag(Node::NF_NO_FILTER)) {
         foreach ($this->getNode()->m_filters as $key => $value) {
             $this->addFilter($key . "='" . $value . "'");
         }
         foreach ($this->getNode()->m_fuzzyFilters as $filter) {
             $parser = new StringParser($filter);
             $filter = $parser->parse(array('table' => $this->getNode()->getTable()));
             $this->addFilter($filter);
         }
     }
     $this->addComponent('list', __NAMESPACE__ . '\\DataGridList');
     $this->addComponent('summary', __NAMESPACE__ . '\\DataGridSummary');
     $this->addComponent('limit', __NAMESPACE__ . '\\DataGridLimit', array('showAll' => Config::getGlobal('enable_showall')));
     $this->addComponent('norecordsfound', __NAMESPACE__ . '\\DataGridNoRecordsFound');
     $this->addComponent('paginator', __NAMESPACE__ . '\\DataGridPaginator');
     if (!empty($this->getNode()->m_index)) {
         $this->addComponent('index', 'atk.datagrid.atkdgindex');
     }
     if (count($this->getNode()->m_editableListAttributes) > 0) {
         $this->addComponent('editcontrol', __NAMESPACE__ . '\\DataGridEditControl');
     }
 }
示例#18
0
 /**
  * Apply node filters to query.
  *
  * @param Query $query query
  */
 protected function _applyFiltersToQuery(Query $query)
 {
     if ($this->m_ignoreDefaultFilters) {
         return;
     }
     // key/value filters
     foreach ($this->_getNode()->m_filters as $key => $value) {
         $query->addCondition($key . "='" . $this->_getDb()->escapeSQL($value) . "'");
     }
     // fuzzy filters
     foreach ($this->_getNode()->m_fuzzyFilters as $filter) {
         $parser = new StringParser($filter);
         $filter = $parser->parse(array('table' => $this->_getNode()->getTable()));
         $query->addCondition($filter);
     }
 }
示例#19
0
 /**
  * Recursive funtion which fills an array with all the items of the tree.
  *
  * @param bool $showactions Show actions?
  * @param bool $expandAll Expand all leafs?
  * @param bool $foldable Is this tree foldable?
  *
  * @return string
  */
 public function GraphTreeRender($showactions = true, $expandAll = false, $foldable = true)
 {
     global $g_maxlevel, $exp_index;
     // Return
     if (count($this->m_tree) == 1) {
         return '';
     }
     $img_expand = $this->getIcon('expand');
     $img_collapse = $this->getIcon('collapse');
     $img_line = $this->getIcon('vertline');
     $img_split = $this->getIcon('split');
     $img_plus = $this->getIcon('split_plus');
     $img_minus = $this->getIcon('split_minus');
     $img_end = $this->getIcon('end');
     $img_end_plus = $this->getIcon('end_plus');
     $img_end_minus = $this->getIcon('end_minus');
     $img_leaf = $this->getIcon('leaf');
     $img_leaflink = $this->getIcon('leaf_link');
     $img_spc = $this->getIcon('space');
     $img_extfile = $this->getIcon('extfile');
     $res = '';
     $lastlevel = 0;
     //echo $this->m_tree[0]["expand"]."--".$this->m_tree[0]["colapse"];
     $explevels = [];
     if ($this->m_tree[0]['expand'] != 1 && $this->m_tree[0]['colapse'] != 1) {
         // normal operation
         for ($i = 0; $i < count($this->m_tree); ++$i) {
             if ($this->m_tree[$i]['level'] < 2) {
                 if ($this->m_tree[$i]['isleaf'] == 1 && $this->m_tree[$i]['level'] < 1) {
                     $expand[$i] = 1;
                     $visible[$i] = 1;
                 } else {
                     $expand[$i] = 0;
                     $visible[$i] = 1;
                 }
             } else {
                 $expand[$i] = 0;
                 $visible[$i] = 0;
             }
             $levels[$i] = 0;
         }
         if ($this->m_postvars['atktree'] != '') {
             $explevels = explode('|', $this->m_postvars['atktree']);
         }
     } elseif ($this->m_tree[0]['expand'] == 1) {
         // expand all mode!
         for ($i = 0; $i < count($this->m_tree); ++$i) {
             $expand[$i] = 1;
             $visible[$i] = 1;
             $levels[$i] = 0;
         }
         $this->m_tree[0]['expand'] = 0;
         // next time we are back in normal view mode!
     } elseif ($this->m_tree[0]['colapse'] == 1) {
         //  colapse all mode!
         for ($i = 0; $i < count($this->m_tree); ++$i) {
             if ($this->m_tree[$i]['level'] < 2) {
                 if ($this->m_tree[$i]['isleaf'] == 1 && $this->m_tree[$i]['level'] < 1) {
                     $expand[$i] = 1;
                     $visible[$i] = 1;
                 } else {
                     $expand[$i] = 0;
                     $visible[$i] = 1;
                 }
             }
             $levels[$i] = 0;
         }
         $this->m_tree[0]['colapse'] = 0;
         // next time we are back in normal view mode!
     }
     /*         * ****************************************** */
     /*  Get Node numbers to expand               */
     /*         * ****************************************** */
     $i = 0;
     while ($i < count($explevels)) {
         //$expand[$explevels[$i]]=1;
         $expand[$exp_index[$explevels[$i]]] = 1;
         ++$i;
     }
     /*         * ****************************************** */
     /*  Find last nodes of subtrees              */
     /*         * ****************************************** */
     $lastlevel = $g_maxlevel;
     for ($i = count($this->m_tree) - 1; $i >= 0; --$i) {
         if ($this->m_tree[$i]['level'] < $lastlevel) {
             for ($j = $this->m_tree[$i]['level'] + 1; $j <= $g_maxlevel; ++$j) {
                 $levels[$j] = 0;
             }
         }
         if ($levels[$this->m_tree[$i]['level']] == 0) {
             $levels[$this->m_tree[$i]['level']] = 1;
             $this->m_tree[$i]['isleaf'] = 1;
         } else {
             $this->m_tree[$i]['isleaf'] = 0;
         }
         $lastlevel = $this->m_tree[$i]['level'];
     }
     /*         * ****************************************** */
     /*  Determine visible nodes                  */
     /*         * ****************************************** */
     $visible[0] = 1;
     // root is always visible
     for ($i = 0; $i < count($explevels); ++$i) {
         $n = $exp_index[$explevels[$i]];
         if ($visible[$n] == 1 && $expand[$n] == 1) {
             $j = $n + 1;
             while ($this->m_tree[$j]['level'] > $this->m_tree[$n]['level']) {
                 if ($this->m_tree[$j]['level'] == $this->m_tree[$n]['level'] + 1) {
                     $visible[$j] = 1;
                 }
                 ++$j;
             }
         }
     }
     for ($i = 0; $i < $g_maxlevel; ++$i) {
         $levels[$i] = 1;
     }
     $res .= '<tr>';
     // Make cols for max level
     for ($i = 0; $i < $g_maxlevel; ++$i) {
         $res .= "<td width=16>&nbsp;</td>\n";
     }
     // Make the last text column
     $res .= '<td width=300>&nbsp;</td>';
     // Column for the functions
     if ($showactions) {
         $res .= '<td width=300>&nbsp;</td>';
     }
     $res .= "</tr>\n";
     $cnt = 0;
     while ($cnt < count($this->m_tree)) {
         if ($visible[$cnt]) {
             $currentlevel = isset($this->m_tree[$cnt]['level']) ? $this->m_tree[$cnt]['level'] : 0;
             $nextlevel = isset($this->m_tree[$cnt + 1]['level']) ? $this->m_tree[$cnt + 1]['level'] : 0;
             /****************************************/
             /* start new row                        */
             /****************************************/
             $res .= '<tr>';
             /****************************************/
             /* vertical lines from higher levels    */
             /****************************************/
             $i = 0;
             while ($i < $this->m_tree[$cnt]['level'] - 1) {
                 if ($levels[$i] == 1) {
                     $res .= '<td><img src="' . $img_line . "\" border=0></td>\n";
                 } else {
                     $res .= '<td><img src="' . $img_spc . "\" border=0></td>\n";
                 }
                 ++$i;
             }
             /***************************************/
             /* corner at end of subtree or t-split */
             /***************************************/
             if ($this->m_tree[$cnt]['isleaf'] == 1 && $nextlevel < $currentlevel) {
                 if ($cnt != 0) {
                     $res .= '<td><img src="' . $img_end . "\" border=0></td>\n";
                 }
                 $levels[$this->m_tree[$cnt]['level'] - 1] = 0;
             } else {
                 if ($expand[$cnt] == 0) {
                     if ($nextlevel > $currentlevel) {
                         /*                             * ************************************* */
                         /* Create expand/collapse parameters    */
                         /*                             * ************************************* */
                         $i = 0;
                         $params = 'atktree=';
                         while ($i < count($expand)) {
                             if ($expand[$i] == 1 && $cnt != $i || $expand[$i] == 0 && $cnt == $i) {
                                 $params = $params . $this->m_tree[$i]['id'];
                                 $params = $params . '|';
                             }
                             ++$i;
                         }
                         if ($this->extraparams) {
                             $params = $params . $this->extraparams;
                         }
                         if ($this->m_tree[$cnt]['isleaf'] == 1) {
                             if ($cnt != 0) {
                                 $res .= '<td>' . Tools::href(Config::getGlobal('dispatcher') . '?atknodeuri=' . $this->atkNodeUri() . '&atkaction=' . $this->m_action . '&' . $params, '<img src="' . $img_end_plus . '" border=0>') . "</td>\n";
                             }
                         } else {
                             if ($cnt != 0) {
                                 $res .= '<td>' . Tools::href(Config::getGlobal('dispatcher') . '?atknodeuri=' . $this->atkNodeUri() . '&atkaction=' . $this->m_action . '&' . $params, '<img src="' . $img_plus . '" border=0>') . "</td>\n";
                             }
                         }
                     } else {
                         $res .= '<td><img src="' . $img_split . "\" border=0></td>\n";
                     }
                 } else {
                     if ($nextlevel > $currentlevel) {
                         /*                             * ************************************* */
                         /* Create expand/collapse parameters    */
                         /*                             * ************************************* */
                         $i = 0;
                         $params = 'atktree=';
                         while ($i < count($expand)) {
                             if ($expand[$i] == 1 && $cnt != $i || $expand[$i] == 0 && $cnt == $i) {
                                 $params = $params . $this->m_tree[$i]['id'];
                                 $params = $params . '|';
                             }
                             ++$i;
                         }
                         if (isset($this->extraparams)) {
                             $params = $params . $this->extraparams;
                         }
                         if ($this->m_tree[$cnt]['isleaf'] == 1) {
                             if ($cnt != 0) {
                                 if ($foldable) {
                                     $res .= '<td>' . Tools::href(Config::getGlobal('dispatcher') . '?atknodeuri=' . $this->atkNodeUri() . '&atkaction=' . $this->m_action . '&' . $params, '<img src="' . $img_end_minus . '" border=0>') . "</td>\n";
                                 } else {
                                     $res .= '<td><img src="' . $img_end . "\" border=0></td>\n";
                                 }
                             }
                         } else {
                             if ($cnt != 0) {
                                 if ($foldable) {
                                     $res .= '<td>' . Tools::href(Config::getGlobal('dispatcher') . '?atknodeuri=' . $this->atkNodeUri() . '&atkaction=' . $this->m_action . '&' . $params, '<img src="' . $img_minus . '" border=0>') . "</td>\n";
                                 } else {
                                     $res .= '<td><img src="' . $img_split . "\" border=0></td>\n";
                                 }
                             }
                         }
                     } else {
                         $res .= '<td><img src="' . $img_split . "\" border=0></td>\n";
                     }
                 }
                 if ($this->m_tree[$cnt]['isleaf'] == 1) {
                     $levels[$this->m_tree[$cnt]['level'] - 1] = 0;
                 } else {
                     $levels[$this->m_tree[$cnt]['level'] - 1] = 1;
                 }
             }
             /*                 * ***************************************** */
             /* Node (with subtree) or Leaf (no subtree) */
             /*                 * ***************************************** */
             if ($nextlevel > $currentlevel) {
                 /*                     * ************************************* */
                 /* Create expand/collapse parameters    */
                 /*                     * ************************************* */
                 if ($foldable) {
                     $i = 0;
                     $params = 'atktree=';
                     while ($i < count($expand)) {
                         if ($expand[$i] == 1 && $cnt != $i || $expand[$i] == 0 && $cnt == $i) {
                             $params = $params . $this->m_tree[$i]['id'];
                             $params = $params . '|';
                         }
                         ++$i;
                     }
                     if (isset($this->extraparams)) {
                         $params = $params . $this->extraparams;
                     }
                     if ($expand[$cnt] == 0) {
                         $res .= '<td>' . Tools::href(Config::getGlobal('dispatcher') . '?' . $params, '<img src="' . $img_expand . '" border=0>') . "</td>\n";
                     } else {
                         $res .= '<td>' . Tools::href(Config::getGlobal('dispatcher') . '?' . $params, '<img src="' . $img_collapse . '" border=0>') . "</td>\n";
                     }
                 } else {
                     $res .= '<td><img src="' . $img_collapse . "\" border=0></td>\n";
                 }
             } else {
                 /*                     * ********************** */
                 /* Tree Leaf             */
                 /*                     * ********************** */
                 $img = $img_leaf;
                 // the image is a leaf image by default, but it can be overridden
                 // by putting img to something else
                 if ($this->m_tree[$cnt]['img'] != '') {
                     $imgname = $this->m_tree[$cnt]['img'];
                     $img = ${$imgname};
                 }
                 $res .= '<td><img src="' . $img . "\"></td>\n";
             }
             /*                 * ************************************* */
             /* output item text                     */
             /*                 * ************************************* */
             // If there's an array inside the 'label' thingee, we have an entire record.
             // Else, it's probably just a textual label.
             if (is_array($this->m_tree[$cnt]['label'])) {
                 $label = $this->descriptor($this->m_tree[$cnt]['label']);
             } else {
                 $label = $this->m_tree[$cnt]['label'];
             }
             $res .= '<td colspan=' . ($g_maxlevel - $this->m_tree[$cnt]['level']) . ' nowrap><font size=2>' . $label . "</font></td>\n";
             /*                 * ************************************* */
             /* end row   with the functions                      */
             /*                 * ************************************* */
             if ($showactions) {
                 $res .= '<td nowrap> ';
                 $actions = [];
                 if (!$this->hasFlag(self::NF_NO_ADD) && !($this->hasFlag(self::NF_TREE_NO_ROOT_ADD) && $this->m_tree[$cnt]['level'] == 0)) {
                     $actions['add'] = Config::getGlobal('dispatcher') . '?atknodeuri=' . $this->atkNodeUri() . '&atkaction=add&atkfilter=' . $this->m_parent . '.' . $this->m_primaryKey[0] . rawurlencode("='" . $this->m_tree[$cnt]['id'] . "'");
                 }
                 if ($cnt > 0) {
                     if (!$this->hasFlag(self::NF_NO_EDIT)) {
                         $actions['edit'] = Config::getGlobal('dispatcher') . '?atknodeuri=' . $this->atkNodeUri() . '&atkaction=edit&atkselector=' . $this->m_table . '.' . $this->m_primaryKey[0] . '=' . $this->m_tree[$cnt]['id'];
                     }
                     if ($this->hasFlag(self::NF_COPY) && $this->allowed('add') && !$this->hasFlag(self::NF_TREE_NO_ROOT_COPY) || $this->m_tree[$cnt]['level'] != 1 && $this->hasFlag(self::NF_COPY) && $this->allowed('add')) {
                         $actions['copy'] = Config::getGlobal('dispatcher') . '?atknodeuri=' . $this->atkNodeUri() . '&atkaction=copy&atkselector=' . $this->m_table . '.' . $this->m_primaryKey[0] . '=' . $this->m_tree[$cnt]['id'];
                     }
                     if ($this->hasFlag(self::NF_NO_DELETE) || $this->hasFlag(self::NF_TREE_NO_ROOT_DELETE) && $this->m_tree[$cnt]['level'] == 1) {
                         // Do nothing
                     } else {
                         $actions['delete'] = Config::getGlobal('dispatcher') . '?atknodeuri=' . $this->atkNodeUri() . '&atkaction=delete&atkselector=' . $this->m_table . '.' . $this->m_primaryKey[0] . '=' . $this->m_tree[$cnt]['id'];
                     }
                 }
                 // Look for custom record actions.
                 $recordactions = $actions;
                 $this->collectRecordActions($this->m_tree[$cnt]['label'], $recordactions, $dummy);
                 foreach ($recordactions as $name => $url) {
                     if (!empty($url)) {
                         /* dirty hack */
                         $atkencoded = strpos($url, '_1') > 0;
                         $url = str_replace('%5B', '[', $url);
                         $url = str_replace('%5D', ']', $url);
                         $url = str_replace('_1' . '5B', '[', $url);
                         $url = str_replace('_1' . '5D', ']', $url);
                         if ($atkencoded) {
                             $url = str_replace('[pk]', Tools::atkurlencode(rawurlencode($this->primaryKey($this->m_tree[$cnt]['label'])), false), $url);
                         } else {
                             $url = str_replace('[pk]', rawurlencode($this->primaryKey($this->m_tree[$cnt]['label'])), $url);
                         }
                         $stringparser = new StringParser($url);
                         $url = $stringparser->parse($this->m_tree[$cnt]['label'], true);
                         $res .= Tools::href($url, Tools::atktext($name), SessionManager::SESSION_NESTED) . '&nbsp;';
                     }
                 }
                 $res .= '</td>';
             }
             $res .= "</tr>\n";
         }
         ++$cnt;
     }
     return $res;
 }