/**
    * Generate the widget and return it as string
    * @return string
    */
   public function generate()
   {
       $arrSet = array();
       $arrValues = array();
       $blnHasOrder = $this->strOrderField != '' && is_array($this->{$this->strOrderField});
       if (!empty($this->varValue)) {
           $objItems = $this->Database->execute("SELECT * FROM " . $this->foreignTable . " WHERE id IN (" . implode(',', array_map('intval', (array) $this->varValue)) . ") ORDER BY sorting");
           if ($objItems !== null) {
               while ($objItems->next()) {
                   $arrSet[] = $objItems->id;
                   $arrValues[$objItems->id] = TreePickerHelper::generateItemLabel($objItems, $this->foreignTable, $this->objDca, null, $this->pickerCallback);
               }
           }
           // Apply a custom sort order
           if ($blnHasOrder) {
               $arrNew = array();
               foreach ($this->{$this->strOrderField} as $i) {
                   if (isset($arrValues[$i])) {
                       $arrNew[$i] = $arrValues[$i];
                       unset($arrValues[$i]);
                   }
               }
               if (!empty($arrValues)) {
                   foreach ($arrValues as $k => $v) {
                       $arrNew[$k] = $v;
                   }
               }
               $arrValues = $arrNew;
               unset($arrNew);
           }
           $orderCallback = $this->orderCallback;
           // Use callback to order things
           if (is_array($orderCallback)) {
               $strClass = $orderCallback[0];
               $strMethod = $orderCallback[1];
               $arrValues = \System::importStatic($strClass)->{$strMethod}($arrValues);
           } elseif (is_callable($orderCallback)) {
               $arrValues = $orderCallback($arrValues);
           }
       }
       // Load the fonts for the drag hint
       $GLOBALS['TL_CONFIG']['loadGoogleFonts'] = true;
       $return = '<input type="hidden" name="' . $this->strName . '" id="ctrl_' . $this->strId . '" value="' . implode(',', $arrSet) . '">' . ($blnHasOrder ? '
 <input type="hidden" name="' . $this->strOrderName . '" id="ctrl_' . $this->strOrderId . '" value="' . $this->{$this->strOrderField} . '">' : '') . '
 <div class="selector_container">' . ($blnHasOrder && count($arrValues) ? '
   <p class="sort_hint">' . $GLOBALS['TL_LANG']['MSC']['dragItemsHint'] . '</p>' : '') . '
   <ul id="sort_' . $this->strId . '" class="' . ($blnHasOrder ? 'sortable' : '') . '">';
       foreach ($arrValues as $k => $v) {
           $return .= '<li data-id="' . $k . '">' . $v . '</li>';
       }
       $return .= '</ul>
   <p><a href="system/modules/widget_tree_picker/public/treepicker.php?do=' . \Input::get('do') . '&amp;table=' . $this->strTable . '&amp;field=' . $this->strField . '&amp;act=show&amp;id=' . $this->activeRecord->id . '&amp;value=' . implode(',', $arrSet) . '&amp;rt=' . REQUEST_TOKEN . '" class="tl_submit" onclick="Backend.getScrollOffset();TreePicker.openModal({\'width\':765,\'title\':\'' . specialchars($GLOBALS['TL_LANG']['MSC']['treepicker']) . '\',\'url\':this.href,\'id\':\'' . $this->strId . '\'});return false">' . $GLOBALS['TL_LANG']['MSC']['changeSelection'] . '</a></p>' . ($blnHasOrder ? '
   <script>Backend.makeMultiSrcSortable("sort_' . $this->strId . '", "ctrl_' . $this->strOrderId . '")</script>' : '') . '
   <script>
       var script = document.createElement("script");
       script.src = "system/modules/widget_tree_picker/assets/treepicker.min.js";
       document.getElementsByTagName("head")[0].appendChild(script);
   </script>
 </div>';
       if (!\Environment::get('isAjaxRequest')) {
           $return = '<div>' . $return . '</div>';
       }
       return $return;
   }
 /**
  * Recursively render the itemtree
  * @param integer
  * @param integer
  * @param boolean
  * @param boolean
  * @return string
  */
 protected function renderItemTree($id, $intMargin, $blnNoRecursion = false)
 {
     static $session;
     $session = $this->Session->getData();
     $flag = substr($this->strField, 0, 2);
     $node = 'tree_' . $this->strTable . '_' . $this->strField;
     $xtnode = 'tree_' . $this->strTable . '_' . $this->strName;
     // Get the session data and toggle the nodes
     if (\Input::get($flag . 'tg')) {
         $session[$node][\Input::get($flag . 'tg')] = isset($session[$node][\Input::get($flag . 'tg')]) && $session[$node][\Input::get($flag . 'tg')] == 1 ? 0 : 1;
         $this->Session->setData($session);
         $this->redirect(preg_replace('/(&(amp;)?|\\?)' . $flag . 'tg=[^& ]*/i', '', \Environment::get('request')));
     }
     $objItem = $this->Database->prepare("SELECT * FROM " . $this->foreignTable . " WHERE id=?")->limit(1)->execute($id);
     // Return if there is no result
     if ($objItem->numRows < 1) {
         return '';
     }
     $return = '';
     $intSpacing = 20;
     $childs = array();
     // Check whether there are child records
     if (!$blnNoRecursion) {
         $objNodes = $this->Database->prepare("SELECT id FROM " . $this->foreignTable . " WHERE pid=? ORDER BY sorting")->execute($id);
         if ($objNodes->numRows) {
             $childs = $objNodes->fetchEach('id');
         }
     }
     $return .= "\n    " . '<li class="tl_file toggle_select" onmouseover="Theme.hoverDiv(this, 1)" onmouseout="Theme.hoverDiv(this, 0)"><div class="tl_left" style="padding-left:' . ($intMargin + $intSpacing) . 'px">';
     $session[$node][$id] = is_numeric($session[$node][$id]) ? $session[$node][$id] : 0;
     $level = $intMargin / $intSpacing + 1;
     $blnIsOpen = $session[$node][$id] == 1 || in_array($id, $this->arrNodes);
     if (!empty($childs)) {
         $img = $blnIsOpen ? 'folMinus.gif' : 'folPlus.gif';
         $alt = $blnIsOpen ? $GLOBALS['TL_LANG']['MSC']['collapseNode'] : $GLOBALS['TL_LANG']['MSC']['expandNode'];
         $return .= '<a href="' . $this->addToUrl($flag . 'tg=' . $id) . '" title="' . specialchars($alt) . '" onclick="return TreePicker.toggle(this,\'' . $xtnode . '_' . $id . '\',\'' . $this->strField . '\',\'' . $this->strName . '\',' . $level . ')">' . \Image::getHtml($img, '', 'style="margin-right:2px"') . '</a>';
     }
     $label = TreePickerHelper::generateItemLabel($objItem, $this->foreignTable, $this->objDca);
     // Add the current item
     if (!empty($childs)) {
         $return .= '<a href="' . $this->addToUrl('node=' . $objItem->id) . '" title="' . specialchars(strip_tags($label)) . '">' . $label . '</a></div> <div class="tl_right">';
     } else {
         $return .= '<span style="margin-left:' . $intSpacing . 'px;"></span>' . $label . '</div> <div class="tl_right">';
     }
     $showInput = true;
     // HOOK: toggle input visibility
     if (isset($GLOBALS['TL_HOOKS']['widgetTreePickerToggleInput']) && is_array($GLOBALS['TL_HOOKS']['widgetTreePickerToggleInput'])) {
         foreach ($GLOBALS['TL_HOOKS']['widgetTreePickerToggleInput'] as $callback) {
             $this->import($callback[0]);
             $showInput = $this->{$callback[0]}->{$callback[1]}($objItem, $this);
         }
     }
     if ($showInput) {
         // Add checkbox or radio button
         switch ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['eval']['fieldType']) {
             case 'checkbox':
                 $input = '<input type="checkbox" name="' . $this->strName . '[]" id="' . $this->strName . '_' . $id . '" class="tl_tree_checkbox" value="' . specialchars($id) . '" onfocus="Backend.getScrollOffset()"' . ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$this->strField]['eval']['selectParents'] ? ' onclick="TreePicker.selectParents(this)"' : '') . static::optionChecked($id, $this->varValue) . '>';
                 break;
             default:
             case 'radio':
                 $input = '<input type="radio" name="' . $this->strName . '" id="' . $this->strName . '_' . $id . '" class="tl_tree_radio" value="' . specialchars($id) . '" onfocus="Backend.getScrollOffset()"' . static::optionChecked($id, $this->varValue) . '>';
                 break;
         }
         // HOOK: modify input markup
         if (isset($GLOBALS['TL_HOOKS']['widgetTreePickerModifyInput']) && is_array($GLOBALS['TL_HOOKS']['widgetTreePickerModifyInput'])) {
             foreach ($GLOBALS['TL_HOOKS']['widgetTreePickerModifyInput'] as $callback) {
                 $this->import($callback[0]);
                 $input = $this->{$callback[0]}->{$callback[1]}($input, $objItem, $this);
             }
         }
         $return .= $input;
     }
     $return .= '</div><div style="clear:both"></div></li>';
     // Begin a new submenu
     if (!empty($childs) && ($blnIsOpen || $this->Session->get($this->getSearchSessionKey()) != '')) {
         $return .= '<li class="parent" id="' . $node . '_' . $id . '"><ul class="level_' . $level . '">';
         for ($k = 0, $c = count($childs); $k < $c; $k++) {
             $return .= $this->renderItemTree($childs[$k], $intMargin + $intSpacing);
         }
         $return .= '</ul></li>';
     }
     return $return;
 }