From 7cc46886fa8ce53bc2eb0f5ef867ca491e2e1229 Mon Sep 17 00:00:00 2001
From: Moritz Strohm <strohm@data-quest.de>
Date: Mon, 2 Sep 2024 09:41:30 +0000
Subject: TIC 4392, closes #4392

Closes #4392

Merge request studip/studip!3207
---
 app/views/course/details/index.php                 |   19 +-
 app/views/shared/modul/overview.php                |    5 +-
 app/views/study_area/tree.php                      |   12 +-
 .../JsonApi/Routes/RangeTree/RangeTreeIndex.php    |    0
 .../JsonApi/Routes/StudyAreas/StudyAreasIndex.php  |   18 +-
 lib/classes/RangeTreeObject.php                    |  294 -----
 lib/classes/RangeTreeObjectFak.php                 |   56 -
 lib/classes/RangeTreeObjectInst.php                |   71 --
 lib/classes/SemBrowse.php                          | 1257 --------------------
 lib/classes/Seminar.php                            |    0
 lib/classes/StudipRangeTree.php                    |  222 ----
 lib/classes/StudipRangeTreeView.php                |  101 --
 lib/classes/StudipRangeTreeViewAdmin.php           |  837 -------------
 lib/classes/StudipSemRangeTreeViewSimple.php       |  247 ----
 lib/classes/StudipSemSearch.php                    |  191 ---
 lib/classes/StudipSemSearchHelper.php              |   39 +-
 lib/classes/StudipSemTree.php                      |  312 -----
 lib/classes/StudipSemTreeSearch.php                |  241 ----
 lib/classes/StudipSemTreeView.php                  |  215 ----
 lib/classes/StudipSemTreeViewAdmin.php             |  825 -------------
 lib/classes/StudipSemTreeViewSimple.php            |  244 ----
 lib/classes/TreeAbstract.php                       |  431 -------
 lib/classes/TreeView.php                           |  444 -------
 lib/extern/ExternPageCourseDetails.php             |   11 +-
 lib/functions.php                                  |   22 -
 lib/meine_seminare_func.inc.php                    |   17 +-
 lib/models/StudipStudyArea.php                     |   19 +
 lib/modules/CoreOverview.php                       |   17 +-
 lib/navigation/SearchNavigation.php                |  199 +++-
 public/show_bereich.php                            |  147 ---
 templates/sembrowse/quick-search.php               |   65 -
 tests/unit/lib/classes/MarkupClassTest.php         |    1 -
 32 files changed, 292 insertions(+), 6287 deletions(-)
 create mode 100644 lib/classes/JsonApi/Routes/RangeTree/RangeTreeIndex.php
 delete mode 100644 lib/classes/RangeTreeObject.php
 delete mode 100644 lib/classes/RangeTreeObjectFak.php
 delete mode 100644 lib/classes/RangeTreeObjectInst.php
 delete mode 100644 lib/classes/SemBrowse.php
 create mode 100644 lib/classes/Seminar.php
 delete mode 100644 lib/classes/StudipRangeTree.php
 delete mode 100644 lib/classes/StudipRangeTreeView.php
 delete mode 100644 lib/classes/StudipRangeTreeViewAdmin.php
 delete mode 100644 lib/classes/StudipSemRangeTreeViewSimple.php
 delete mode 100644 lib/classes/StudipSemSearch.php
 delete mode 100644 lib/classes/StudipSemTree.php
 delete mode 100644 lib/classes/StudipSemTreeSearch.php
 delete mode 100644 lib/classes/StudipSemTreeView.php
 delete mode 100644 lib/classes/StudipSemTreeViewSimple.php
 delete mode 100644 lib/classes/TreeAbstract.php
 delete mode 100644 lib/classes/TreeView.php
 delete mode 100644 public/show_bereich.php
 delete mode 100644 templates/sembrowse/quick-search.php

diff --git a/app/views/course/details/index.php b/app/views/course/details/index.php
index 29db9bd..569a266 100644
--- a/app/views/course/details/index.php
+++ b/app/views/course/details/index.php
@@ -6,6 +6,7 @@
  * @var Course_DetailsController $controller
  * @var string $prelim_discussion
  * @var stdClass $id_sfx
+ * @var StudipStudyArea[] $study_areas
  */
 ?>
 <style>
@@ -351,6 +352,12 @@
 <? endif ?>
 
 <? if (isset($studyAreaTree) && $studyAreaTree->required_children) : ?>
+    <?
+    $semester_id = '';
+    if ($course->end_semester && $course->end_semester !== Semester::findCurrent()) {
+        $semester_id = $course->end_semester->id;
+    }
+    ?>
     <article class="studip">
         <header>
             <h1><?= _('Studienbereiche') ?></h1>
@@ -361,6 +368,7 @@
                     'study_area/tree.php',
                     [
                         'node' => $studyAreaTree,
+                        'semester_id' => $semester_id,
                         'open' => true,
                         'dont_open' => Config::get()->COURSE_SEM_TREE_CLOSED_LEVELS
                     ]
@@ -377,9 +385,18 @@
         </header>
         <section>
             <ul class="list-unstyled">
+                <?
+                $url_params = [];
+                if ($course->end_semester && $course->end_semester !== Semester::findCurrent()) {
+                    $url_params['semester'] = $course->end_semester->id;
+                }
+                ?>
                 <? foreach ($study_areas as $area) : ?>
+                    <?
+                    $url_params['node_id'] = 'StudipStudyArea_' . $area->id;
+                    ?>
                     <li>
-                        <a href="<?=URLHelper::getScriptLink('show_bereich.php?level=sbb&id=' . $area->id)?>">
+                        <a href="<?= URLHelper::getLink('dispatch.php/search/courses', $url_params, true) ?>">
                             <?= htmlReady($area->getPath(' > ')) ?>
                         </a>
                     </li>
diff --git a/app/views/shared/modul/overview.php b/app/views/shared/modul/overview.php
index 0f20791..4bfd71e 100644
--- a/app/views/shared/modul/overview.php
+++ b/app/views/shared/modul/overview.php
@@ -134,7 +134,10 @@
                                 <em><?= _('[versteckt]') ?></em>
                                 <? endif; ?>
                                 <? if (Config::get()->COURSE_SEARCH_SHOW_ADMISSION_STATE) : ?>
-                                    <? switch (SemBrowse::getStatusCourseAdmission($course->id, $course->admission_prelim)) :
+                                    <?
+                                    $admission_status = GlobalSearchCourses::getStatusCourseAdmission($course->id, $course->admission_prelim);
+                                    ?>
+                                    <? switch ($admission_status) :
                                         case 1:
                                             echo Icon::create('span-2quarter', Icon::ROLE_STATUS_YELLOW, [
                                                 'alt'   => _('Eingeschränkter Zugang'),
diff --git a/app/views/study_area/tree.php b/app/views/study_area/tree.php
index d3ec538..b23450f 100644
--- a/app/views/study_area/tree.php
+++ b/app/views/study_area/tree.php
@@ -1,6 +1,7 @@
 <?php
 /**
  * @var StudipStudyArea $node
+ * @var string $semester_id An optional semester_id.
  * @var string $open
  * @var int $layer
  * @var array $dont_open
@@ -15,7 +16,13 @@ $layer = 0;
     <label for='<?= htmlReady($node->id) ?>'></label>
 
 <? if ($node->id !== 'root'): ?>
-    <a href="<?= URLHelper::getLink('show_bereich.php?level=sbb&id=' . $node->id) ?>">
+    <?
+    $url_params = ['node_id' => 'StudipStudyArea_' . $node->id];
+    if ($semester_id) {
+        $url_params['semester'] = $semester_id;
+    }
+    ?>
+    <a href="<?= URLHelper::getLink('dispatch.php/search/courses', $url_params, true) ?>">
         <?= htmlReady($node->name) ?>
     </a>
 <? else: ?>
@@ -25,7 +32,8 @@ $layer = 0;
 <? if ($node->required_children): ?>
     <ul>
     <? foreach ($node->required_children as $child): ?>
-        <?= $this->render_partial('study_area/tree.php', ['node' => $child, 'open' => $open, 'layer' => ((int)$layer + 1)]) ?>
+        <?= $this->render_partial(
+            'study_area/tree.php', ['node' => $child, 'open' => $open, 'layer' => $layer + 1, 'semester_id' => $semester_id]) ?>
     <? endforeach; ?>
     </ul>
 <? endif; ?>
diff --git a/lib/classes/JsonApi/Routes/RangeTree/RangeTreeIndex.php b/lib/classes/JsonApi/Routes/RangeTree/RangeTreeIndex.php
new file mode 100644
index 0000000..e69de29
diff --git a/lib/classes/JsonApi/Routes/StudyAreas/StudyAreasIndex.php b/lib/classes/JsonApi/Routes/StudyAreas/StudyAreasIndex.php
index ddb7eb8..786e160 100644
--- a/lib/classes/JsonApi/Routes/StudyAreas/StudyAreasIndex.php
+++ b/lib/classes/JsonApi/Routes/StudyAreas/StudyAreasIndex.php
@@ -24,8 +24,9 @@ class StudyAreasIndex extends JsonApiController
      */
     public function __invoke(Request $request, Response $response, $args)
     {
-        $tree = \TreeAbstract::getInstance('StudipSemTree', ['visible_only' => 1]);
-        $studyAreas =  self::mapTree('root', $tree);
+        $root = \StudipStudyArea::getRootArea();
+        $studyAreas =  $this->mapTree($root);
+
         list($offset, $limit) = $this->getOffsetAndLimit();
 
         return $this->getPaginatedContentResponse(
@@ -34,17 +35,14 @@ class StudyAreasIndex extends JsonApiController
         );
     }
 
-    private function mapTree($parentId, &$tree)
+    private function mapTree(\StudipStudyArea $node)
     {
         $level = [];
-        $kids = $tree->getKids($parentId);
-        if (is_array($kids) && count($kids) > 0) {
-            foreach ($kids as $kid) {
-                $level[] = \StudipStudyArea::find($kid);
-                $level = array_merge($level, self::mapTree($kid, $tree));
-            }
+        $child_nodes = $node->getChildNodes();
+        foreach ($child_nodes as $child_node) {
+            $level[] = $child_node;
+            $level = array_merge($level, $this->mapTree($child_node));
         }
-
         return $level;
     }
 }
diff --git a/lib/classes/RangeTreeObject.php b/lib/classes/RangeTreeObject.php
deleted file mode 100644
index 06f84bf..0000000
--- a/lib/classes/RangeTreeObject.php
+++ /dev/null
@@ -1,294 +0,0 @@
-<?php
-# Lifter002: TODO
-# Lifter007: TODO
-# Lifter003: TODO
-# Lifter010: TODO
-// +---------------------------------------------------------------------------+
-// This file is part of Stud.IP
-// RangeTreeObject.php
-// Class to handle items in the "range tree"
-//
-// Copyright (c) 2002 André Noack <noack@data-quest.de>
-// Suchi & Berg GmbH <info@data-quest.de>
-// +---------------------------------------------------------------------------+
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or any later version.
-// +---------------------------------------------------------------------------+
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-// +---------------------------------------------------------------------------+
-
-/**
-* base class for items in the "range tree"
-*
-* This class is used for items
-*
-* @access   public
-* @author   André Noack <noack@data-quest.de>
-* @package
-*/
-class RangeTreeObject {
-
-    /**
-    * item_id in range_tree
-    *
-    *
-    * @access   public
-    * @var      string $tree_item_id
-    */
-    var $tree_item_id;
-    /**
-    * References the tree object
-    *
-    *
-    * @access   private
-    * @var      object StudipRangeTree $tree
-    */
-    var $tree;
-    /**
-    * associative array with data from database fields
-    *
-    *
-    * @access   public
-    * @var      array $item_data
-    */
-    var $item_data = null;
-
-    /**
-    * associative array with mapping for database fields
-    *
-    *
-    * @access   public
-    * @var      array $item_data_mapping
-    */
-    var $item_data_mapping = null;
-
-    /**
-    * Factory method
-    *
-    *
-    * @access public
-    * @static
-    * @param    string  $item_id
-    * @return   object RangeTreeObject
-    */
-    public static function GetInstance($item_id){
-        $tree = TreeAbstract::GetInstance("StudipRangeTree", false);
-        $class_name = "RangeTreeObject" . ucfirst($tree->tree_data[$item_id]['studip_object']);
-        return new $class_name($item_id);
-    }
-
-    /**
-    * Constructor
-    *
-    * Do not use directly, call factory method instead
-    * @access private
-    * @param    string  $item_id
-    */
-    function __construct($item_id) {
-        $this->tree = TreeAbstract::GetInstance("StudipRangeTree", false);
-        $this->tree_item_id = $item_id;
-        $this->item_data = $this->tree->tree_data[$item_id] ?? null;
-    }
-
-    /**
-    * Returns all tree items which are kids of this object
-    *
-    *
-    * @access public
-    * @param    boolean $as_value_list
-    * @return   mixed   returns numeric array if param is false, else comma separated string
-    */
-    function getAllItemKids($as_value_list = false){
-        return ($as_value_list) ? $this->getValueList($this->tree->getKidsKids($this->tree_item_id)) : $this->tree->getKidsKids($this->tree_item_id);
-    }
-
-    /**
-    * Returns all tree items which are kids of this object and are "real" Stud.IP objects
-    *
-    *
-    * @access public
-    * @param    boolean $as_value_list
-    * @return   mixed   returns numeric array if param is false, else comma separated string
-    */
-    function getAllObjectKids($as_value_list = false){
-        $all_object_kids = array_merge((array)$this->getInstKids(), (array)$this->getFakKids());
-        return ($as_value_list) ? $this->getValueList($all_object_kids) : $all_object_kids;
-    }
-
-    /**
-    * Returns all tree items which are kids of this object and are Stud.IP "Einrichtungen"
-    *
-    *
-    * @access public
-    * @param    boolean $as_value_list
-    * @return   mixed   returns numeric array if param is false, else comma separated string
-    */
-    function getInstKids($as_value_list = false){
-        $all_kids = $this->tree->getKidsKids($this->tree_item_id);
-        $inst_kids = [];
-        for ($i = 0; $i < count($all_kids); ++$i){
-            if ($this->tree->tree_data[$all_kids[$i]]['studip_object'] == 'inst'){
-                $inst_kids[] = $this->tree->tree_data[$all_kids[$i]]['studip_object_id'];
-            }
-        }
-        return ($as_value_list) ? $this->getValueList($inst_kids) : $inst_kids;
-    }
-
-    /**
-    * Returns all tree items which are kids of this object and are Stud.IP "Fakultaeten"
-    *
-    *
-    * @access public
-    * @param    boolean $as_value_list
-    * @return   mixed   returns numeric array if param is false, else comma separated string
-    */
-    function getFakKids($as_value_list = false){
-        $all_kids = $this->tree->getKidsKids($this->tree_item_id);
-        $fak_kids = [];
-        for ($i = 0; $i < count($all_kids); ++$i){
-            if ($this->tree->tree_data[$all_kids[$i]]['studip_object'] == 'fak'){
-                $inst_kids[] = $this->tree->tree_data[$all_kids[$i]]['studip_object_id'];
-            }
-        }
-        return ($as_value_list) ? $this->getValueList($fak_kids) : $fak_kids;
-    }
-
-    /**
-    * Returns array of Stud.IP range_ids of "real" objects
-    *
-    * This function is a wrapper for the according function in StudipRangeTree
-    * @see StudipRangeTree::getAdminRange()
-    * @access   public
-    * @return   array   of primary keys from table "institute"
-    */
-    function getAdminRange(){
-        return $this->tree->getAdminRange($this->tree_item_id);
-    }
-
-    /**
-    * Only useful in RangeTreeObjectInst ,all other items are always in the correct branch
-    *
-    * @access   public
-    * @return   bool
-    */
-    function isInCorrectBranch(){
-        return true;
-    }
-
-    /**
-    * Returns tree path of the current object
-    *
-    * This function is a wrapper for the according function in StudipRangeTree
-    * @see StudipRangeTree::getItemPath()
-    * @access public
-    * @return   string
-    */
-    function getItemPath(){
-        return $this->tree->getItemPath($this->tree_item_id);
-    }
-
-    /**
-    * extends the $item_data array
-    *
-    * This function fills the $item_data array with fields from the according database table (is of no use in the base class)
-    * @abstract
-    * @access private
-    */
-    function initItemDetail(){
-        if ($type = $this->item_data['studip_object']){
-            $view = DbView::getView('range_tree');
-            $view->params = [$this->tree->studip_objects[$type]['table'],
-                                $this->tree->studip_objects[$type]['pk'],
-                                $this->item_data['studip_object_id']];
-            $snap = new DbSnapshot($view->get_query("view:TREE_OBJECT_DETAIL"));
-            if ($snap->numRows){
-                $fields = $snap->getFieldList();
-                $snap->nextRow();
-                for ($i = 0; $i < count($fields); ++$i){
-                    $this->item_data[$fields[$i]] = $snap->getField($fields[$i]);
-                }
-            }
-        return true;
-        }
-    return false;
-    }
-
-    /**
-    * fetch categories of this object from database
-    *
-    * the categories are appended to the $item_data array, key 'categories', value is object of type DbSnapshot
-    * @access private
-    * @return   boolean true if categories were found
-    */
-    function fetchCategories(){
-        $view = DbView::getView('range_tree');
-        $view->params[] = $this->tree_item_id;
-        $rs = $view->get_query("view:TREE_OBJECT_CAT");
-        if (is_object($rs)){
-            $this->item_data['categories'] = new DbSnapshot($rs);
-            return true;
-        }
-    return false;
-    }
-
-    /**
-    * getter method for categories of this object
-    *
-    *
-    * @access public
-    * @return   object DbSnapshot
-    */
-    function &getCategories(){
-        if (empty($this->item_data['categories']) || !is_object($this->item_data['categories'])){
-            $this->fetchCategories();
-        }
-        return $this->item_data['categories'];
-    }
-
-    function fetchNumStaff(){
-        $view = DbView::getView('range_tree');
-        if (!($view->params[0] = $this->item_data['studip_object_id']))
-            $view->params[0] = $this->tree_item_id;
-        $rs = $view->get_query("view:STATUS_COUNT");
-        if ($rs->next_record()){
-            $this->item_data['num_staff'] = $rs->f(0);
-            return true;
-        }
-        return false;
-    }
-
-    function getNumStaff(){
-        if(!isset($this->item_data['num_staff'])){
-            $this->fetchNumStaff();
-        }
-        return $this->item_data['num_staff'];
-    }
-
-
-    /**
-    * transform numerical array into a comma separated string
-    *
-    * the result could be used in a SQL query
-    * @access private
-    * @param    array   $list
-    * @return   string
-    */
-
-    function getValueList($list){
-        $value_list = false;
-        if (count($list) == 1)
-            $value_list = "'$list[0]'";
-        else
-            $value_list = "'".join("','",$list)."'";
-        return $value_list;
-    }
-
-}
diff --git a/lib/classes/RangeTreeObjectFak.php b/lib/classes/RangeTreeObjectFak.php
deleted file mode 100644
index 9e980ca..0000000
--- a/lib/classes/RangeTreeObjectFak.php
+++ /dev/null
@@ -1,56 +0,0 @@
-<?php
-# Lifter002: TODO
-# Lifter007: TODO
-# Lifter003: TODO
-# Lifter010: TODO
-// +---------------------------------------------------------------------------+
-// This file is part of Stud.IP
-// RangeTreeObjectFak.php
-// Class to handle items in the "range tree"
-// 
-// Copyright (c) 2002 André Noack <noack@data-quest.de> 
-// Suchi & Berg GmbH <info@data-quest.de>
-// +---------------------------------------------------------------------------+
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or any later version.
-// +---------------------------------------------------------------------------+
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-// +---------------------------------------------------------------------------+
-
-/**
-* class for items in the "range tree"
-*
-* This class is used for items in the tree which are "Fakultäten"
-*
-* @access   public
-* @author   André Noack <noack@data-quest.de>
-* @package  
-*/
-class RangeTreeObjectFak extends RangeTreeObject {
-    
-    /**
-    * Constructor
-    *
-    * Do not use directly, call factory method in base class instead
-    * @access private
-    * @param    string  $item_id
-    */
-    function __construct($item_id) {
-        parent::__construct($item_id); //calling the baseclass constructor
-        $this->initItemDetail();
-        $this->item_data_mapping = ['Strasse' => _("Straße"), 'Plz' => _("Ort"), 'telefon' => _("Tel."), 'fax' => _("Fax"),
-                                        'url' => _("Homepage"), 'email' => _("Kontakt")];
-        $this->item_data['type_num'] = $this->item_data['type'];
-        $this->item_data['type'] = ($this->item_data['type']) ? $GLOBALS['INST_TYPE'][$this->item_data['type']]['name'] : $GLOBALS['INST_TYPE'][1]['name'];
-    
-    }
-}
-?>
diff --git a/lib/classes/RangeTreeObjectInst.php b/lib/classes/RangeTreeObjectInst.php
deleted file mode 100644
index d41b03d..0000000
--- a/lib/classes/RangeTreeObjectInst.php
+++ /dev/null
@@ -1,71 +0,0 @@
-<?php
-# Lifter002: TODO
-# Lifter007: TODO
-# Lifter003: TODO
-# Lifter010: TODO
-// +---------------------------------------------------------------------------+
-// This file is part of Stud.IP
-// RangeTreeObjectInst.php
-// Class to handle items in the "range tree"
-//
-// Copyright (c) 2002 André Noack <noack@data-quest.de>
-// Suchi & Berg GmbH <info@data-quest.de>
-// +---------------------------------------------------------------------------+
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or any later version.
-// +---------------------------------------------------------------------------+
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-// +---------------------------------------------------------------------------+
-/**
-* class for items in the "range tree"
-*
-* This class is used for items which are "Einrichtungen"
-*
-* @access   public
-* @author   André Noack <noack@data-quest.de>
-* @package
-*/
-class RangeTreeObjectInst extends RangeTreeObject {
-
-    /**
-    * Constructor
-    *
-    * Do not use directly, call factory method in base class instead
-    * @access private
-    * @param    string  $item_id
-    */
-    function __construct($item_id) {
-        parent::__construct($item_id); //calling the baseclass constructor
-        $this->initItemDetail();
-        $this->item_data_mapping = ['Strasse' => _("Straße"), 'Plz' => _("Ort"), 'telefon' => _("Tel."), 'fax' => _("Fax"),
-                                        'url' => _("Homepage"), 'email' => _("Kontakt")];
-        $this->item_data['type_num'] = $this->item_data['type'];
-        $this->item_data['type'] = ($this->item_data['type']) ? $GLOBALS['INST_TYPE'][$this->item_data['type']]['name'] : $GLOBALS['INST_TYPE'][1]['name'];
-
-    }
-
-    /**
-    * Returns true, if fakultaets_id of the item is found in its parents
-    *
-    * @access   public
-    * @return   bool
-    */
-    function isInCorrectBranch(){
-        $parents = $this->tree->getParents($this->tree_item_id);
-        if (is_array($parents) && in_array($this->item_data['fakultaets_id'],$parents)){
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-}
-?>
diff --git a/lib/classes/SemBrowse.php b/lib/classes/SemBrowse.php
deleted file mode 100644
index 19e6f6c..0000000
--- a/lib/classes/SemBrowse.php
+++ /dev/null
@@ -1,1257 +0,0 @@
-<?php
-# Lifter002: TODO
-# Lifter005: TODO
-# Lifter007: TODO
-# Lifter003: TODO
-# Lifter010: TODO
-
-require_once 'lib/dates.inc.php';
-
-class SemBrowse {
-
-    public $sem_browse_data;
-    public $persistent_fields = [
-        'level', 'cmd', 'start_item_id', 'show_class', 'group_by',
-        'search_result', 'default_sem', 'sem_status', 'show_entries', 'sset'
-    ];
-    public $search_obj;
-    public $sem_tree;
-    public $range_tree;
-    public $show_result;
-    public $sem_number;
-    public $group_by_fields = [];
-    public $target_url;
-    public $target_id;
-    public $classes_show_module;
-    public $classes_show_class;
-
-    public function __construct($sem_browse_data_init = [])
-    {
-
-        $this->group_by_fields =
-                [
-                    [
-                        'name'        => _('Semester'),
-                        'group_field' => 'sem_number'
-                    ],
-                    [
-                        'name'        => _('Bereich'),
-                        'group_field' => 'bereich'
-                    ],
-                    [
-                        'name'         => _('Lehrende'),
-                        'group_field'  => 'fullname',
-                        'unique_field' => 'username'
-                    ],
-                    [
-                        'name'        => _('Typ'),
-                        'group_field' => 'status'
-                    ],
-                    [
-                        'name'         => _('Einrichtung'),
-                        'group_field'  => 'Institut',
-                        'unique_field' => 'Institut_id'
-                    ]
-                ];
-
-        if (empty($_SESSION['sem_browse_data'])) {
-            $_SESSION['sem_browse_data'] = $sem_browse_data_init;
-        }
-        $this->sem_browse_data =& $_SESSION['sem_browse_data'];
-
-        $level_change = Request::option('start_item_id') || Request::submitted('search_sem_sem_change');
-
-        for ($i = 0; $i < count($this->persistent_fields); ++$i){
-            $persistend_field = $this->persistent_fields[$i];
-            if (Request::get($persistend_field) != null) {
-                $this->sem_browse_data[$persistend_field] = Request::option($persistend_field);
-            }
-        }
-        $this->search_obj = new StudipSemSearch(
-            'search_sem',
-            false,
-            !(is_object($GLOBALS['perm']) && $GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM)),
-            $this->sem_browse_data['show_class'] ?? null
-        );
-
-
-        if (Request::get($this->search_obj->form_name . '_scope_choose')) {
-            $this->sem_browse_data['start_item_id'] =
-                    Request::option($this->search_obj->form_name . '_scope_choose');
-        }
-        if (Request::get($this->search_obj->form_name . '_range_choose')) {
-            $this->sem_browse_data['start_item_id'] =
-                    Request::option($this->search_obj->form_name . '_range_choose');
-        }
-        if (Request::get($this->search_obj->form_name . '_sem')) {
-            $this->sem_browse_data['default_sem'] =
-                    Request::option($this->search_obj->form_name . '_sem');
-        }
-
-        if (
-            Request::get('keep_result_set')
-            || !empty($this->sem_browse_data['sset'])
-            || (!empty($this->sem_browse_data['search_result']) && !empty($this->sem_browse_data['show_entries']))
-        ) {
-            $this->show_result = true;
-        }
-
-        if (isset($this->sem_browse_data['cmd']) && $this->sem_browse_data['cmd'] === 'xts') {
-            if ($this->search_obj->new_search_button_clicked) {
-                $this->show_result = false;
-                $this->sem_browse_data['sset'] = false;
-                $this->sem_browse_data['search_result'] = [];
-            }
-        }
-
-        if (!isset($this->sem_browse_data['default_sem'])) {
-            $this->sem_number[0] = 0;
-        } elseif ($this->sem_browse_data['default_sem'] != 'all') {
-            $this->sem_number[0] = intval($this->sem_browse_data['default_sem']);
-        } else {
-            $this->sem_number = false;
-        }
-
-        $sem_status = (!empty($this->sem_browse_data['sem_status']) && is_array($this->sem_browse_data['sem_status'])) ? $this->sem_browse_data['sem_status'] : false;
-
-        if ($this->sem_browse_data['level'] == 'vv') {
-            if (empty($this->sem_browse_data['start_item_id'])) {
-                $this->sem_browse_data['start_item_id'] = 'root';
-            }
-            $this->sem_tree = new StudipSemTreeViewSimple(
-                    $this->sem_browse_data['start_item_id'],
-                    $this->sem_number, $sem_status,
-                    !(is_object($GLOBALS['perm'])
-                            && $GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM)));
-            if (Request::option('cmd') != 'show_sem_range'
-                    && $level_change
-                    && !$this->search_obj->search_button_clicked ) {
-                $this->get_sem_range($this->sem_browse_data['start_item_id'], false);
-                $this->show_result = true;
-                $this->sem_browse_data['show_entries'] = 'level';
-                $this->sem_browse_data['sset'] = false;
-            }
-            if ($this->search_obj->sem_change_button_clicked) {
-                $this->get_sem_range($this->sem_browse_data['start_item_id'],
-                        ($this->sem_browse_data['show_entries'] == 'sublevels'));
-                $this->show_result = true;
-            }
-        }
-
-        if ($this->sem_browse_data['level'] == 'ev'){
-            if (!$this->sem_browse_data['start_item_id']) {
-                $this->sem_browse_data['start_item_id'] = 'root';
-            }
-            $this->range_tree = new StudipSemRangeTreeViewSimple(
-                    $this->sem_browse_data['start_item_id'],
-                    $this->sem_number,
-                    $sem_status,
-                    !(is_object($GLOBALS['perm'])
-                            && $GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM)));
-            if (Request::option('cmd') != 'show_sem_range_tree'
-                    && $level_change
-                    && !$this->search_obj->search_button_clicked ) {
-                $this->get_sem_range_tree($this->sem_browse_data['start_item_id'], false);
-                $this->show_result = true;
-                $this->sem_browse_data['show_entries'] = 'level';
-                $this->sem_browse_data['sset'] = false;
-            }
-            if ($this->search_obj->sem_change_button_clicked) {
-                $this->get_sem_range_tree($this->sem_browse_data['start_item_id'],
-                        ($this->sem_browse_data['show_entries'] == 'sublevels'));
-                $this->show_result = true;
-            }
-        }
-
-        if ($this->search_obj->search_button_clicked
-                && !$this->search_obj->new_search_button_clicked) {
-            $this->search_obj->override_sem = $this->sem_number;
-            $this->search_obj->doSearch();
-            if ($this->search_obj->found_rows) {
-                $this->sem_browse_data['search_result'] = array_flip($this->search_obj->search_result->getRows('seminar_id'));
-            } else {
-                $this->sem_browse_data['search_result'] = [];
-            }
-            $this->show_result = true;
-            $this->sem_browse_data['show_entries'] = false;
-            $this->sem_browse_data['sset'] = Request::get($this->search_obj->form_name . "_quick_search_parameter");
-        }
-
-
-        if (Request::option('cmd') == 'show_sem_range') {
-            $tmp = explode('_', Request::option('item_id'));
-            $this->get_sem_range($tmp[0], isset($tmp[1]));
-            $this->show_result = true;
-            $this->sem_browse_data['show_entries'] = (isset($tmp[1])) ? 'sublevels' : 'level';
-            $this->sem_browse_data['sset'] = false;
-        }
-
-        if (Request::option('cmd') == 'show_sem_range_tree') {
-            $tmp = explode('_', Request::option('item_id'));
-            $this->get_sem_range_tree($tmp[0],isset($tmp[1]));
-            $this->show_result = true;
-            $this->sem_browse_data['show_entries'] = (isset($tmp[1])) ? 'sublevels' : 'level';
-            $this->sem_browse_data['sset'] = false;
-        }
-
-        if (Request::option('do_show_class')
-                && count($this->sem_browse_data['sem_status'])) {
-            $this->get_sem_class();
-        }
-
-    }
-
-    /**
-     * Returns whether the search for modules has to be displayed.
-     *
-     * @return boolean True if search for modules has to be displayed.
-     */
-    private function showModules()
-    {
-        if ($this->sem_browse_data['show_class'] == 'all') {
-            return true;
-        }
-        if (!is_array($this->classes_show_module)) {
-            $this->classes_show_class = [];
-            foreach ($GLOBALS['SEM_CLASS'] as $sem_class_key => $sem_class){
-                if ($sem_class['module']) {
-                    $this->classes_show_module[] = $sem_class_key;
-                }
-            }
-        }
-        return in_array($this->sem_browse_data['show_class'], $this->classes_show_class);
-    }
-
-    public function show_class()
-    {
-        if ($this->sem_browse_data['show_class'] == 'all') {
-            return true;
-        }
-        if (!is_array($this->classes_show_class)) {
-            $this->classes_show_class = [];
-            foreach ($GLOBALS['SEM_CLASS'] as $sem_class_key => $sem_class) {
-                if ($sem_class['bereiche']) {
-                    $this->classes_show_class[] = $sem_class_key;
-                }
-            }
-        }
-        return in_array($this->sem_browse_data['show_class'], $this->classes_show_class);
-    }
-
-    public function get_sem_class()
-    {
-        $query = "SELECT `Seminar_id`
-                  FROM `seminare`
-                  WHERE `status` IN (?)";
-
-        $show_all = is_object($GLOBALS['perm'])
-                 && $GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM);
-        if (!$show_all) {
-            $query .= ' AND visible = 1';
-        }
-
-        $sem_ids = DBManager::get()->fetchFirst($query);
-        if (is_array($sem_ids)) {
-            $this->sem_browse_data['search_result'] = array_flip($sem_ids);
-        }
-        $this->sem_browse_data['sset'] = true;
-        $this->show_result = true;
-    }
-
-    public function get_sem_range($item_id, $with_kids)
-    {
-        if (!is_object($this->sem_tree)) {
-            $sem_status = (is_array($this->sem_browse_data['sem_status'])) ? $this->sem_browse_data['sem_status'] : false;
-            $this->sem_tree = new StudipSemTreeViewSimple(
-                    $this->sem_browse_data['start_item_id'],
-                    $this->sem_number,
-                    $sem_status,
-                    !(is_object($GLOBALS['perm'])
-                            && $GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM)));
-        }
-        $sem_ids = $this->sem_tree->tree->getSemIds($item_id,$with_kids);
-        if (is_array($sem_ids)) {
-            $this->sem_browse_data['search_result'] = array_flip($sem_ids);
-        } else {
-            $this->sem_browse_data['search_result'] = [];
-        }
-    }
-
-    public function get_sem_range_tree($item_id, $with_kids)
-    {
-        $range_object = RangeTreeObject::GetInstance($item_id);
-        if ($with_kids) {
-            $inst_ids = $range_object->getAllObjectKids();
-        }
-        $inst_ids[] = $range_object->item_data['studip_object_id'];
-        $db_view = DbView::getView('sem_tree');
-        $db_view->params[0] = $inst_ids;
-        $db_view->params[1] = (is_object($GLOBALS['perm']) && $GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM)) ? '' : ' AND c.visible=1';
-        $db_view->params[1] .= !empty($this->sem_browse_data['sem_status']) && is_array($this->sem_browse_data['sem_status'])
-                ? " AND c.status IN('" . join("','", $this->sem_browse_data['sem_status']) ."')"
-                : '';
-        $db_view->params[2] = is_array($this->sem_number)
-                ? ' HAVING sem_number IN ('
-                    . join(',', $this->sem_number)
-                    . ') OR (sem_number <= '
-                    . $this->sem_number[count($this->sem_number) - 1]
-                    . '  AND (sem_number_end >= '
-                    . $this->sem_number[count($this->sem_number) - 1]
-                    . ' OR sem_number_end = -1)) '
-                : '';
-        $db_snap = new DbSnapshot($db_view->get_query('view:SEM_INST_GET_SEM'));
-        if ($db_snap->numRows) {
-            $sem_ids = $db_snap->getRows('Seminar_id');
-            $this->sem_browse_data['search_result'] = array_flip($sem_ids);
-        } else {
-            $this->sem_browse_data['search_result'] = [];
-        }
-    }
-
-    /**
-     * Prints the quicksearch form.
-     */
-    private function printQuickSearch()
-    {
-        if ($this->sem_browse_data['level'] === 'vv') {
-            $this->search_obj->sem_tree =& $this->sem_tree->tree;
-            if ($this->sem_tree->start_item_id !== 'root') {
-                $this->search_obj->search_scopes[] = $this->sem_tree->start_item_id;
-            }
-        } elseif ($this->sem_browse_data['level'] === 'ev') {
-            $this->search_obj->range_tree =& $this->range_tree->tree;
-            if ($this->range_tree->start_item_id !== 'root'){
-                $this->search_obj->search_ranges[] = $this->range_tree->start_item_id;
-            }
-        }
-
-        $template = $GLOBALS['template_factory']->open('sembrowse/quick-search.php');
-        $template->search_obj      = $this->search_obj;
-        $template->sem_browse_data = $this->sem_browse_data;
-        $template->sem_tree        = $this->sem_tree;
-        $template->range_tree      = $this->range_tree;
-        $template->quicksearch     = $this->getQuicksearch();
-
-        echo $template->render();
-    }
-
-    private function getQuicksearch()
-    {
-        $quicksearch = QuickSearch::get(
-            $this->search_obj->form_name . '_quick_search',
-            new SeminarSearch()
-        );
-
-        $quicksearch->setAttributes([
-            'aria-label' => _('Suchbegriff'),
-            'autofocus'  => '',
-        ]);
-        $quicksearch->fireJSFunctionOnSelect('selectSem');
-        $quicksearch->noSelectbox();
-        $quicksearch->defaultValue(
-            $this->sem_browse_data['sset'] ?: '',
-            $this->sem_browse_data['sset'] ?: ''
-        );
-
-        return $quicksearch;
-    }
-
-    private function printExtendedSearch()
-    {
-        $template = $GLOBALS['template_factory']->open('sembrowse/extended-search.php');
-        $template->search_obj      = $this->search_obj;
-        $template->sem_browse_data = $this->sem_browse_data;
-        $template->show_class      = $this->show_class();
-        echo $template->render();
-    }
-
-    public function do_output()
-    {
-        if ($this->sem_browse_data['cmd'] == 'xts') {
-            $this->printExtendedSearch();
-        }
-        $path_id = Request::option('path_id');
-        URLHelper::addLinkParam('path_id', $path_id);
-        $this->print_level($path_id);
-    }
-
-    public function print_level($start_id = null)
-    {
-        ob_start();
-
-        echo "\n" . '<table id="sem_search_level" class="course-search" style="width: 100%">' . "\n";
-        if ($this->sem_browse_data['level'] == 'vv') {
-            echo "\n" . '<caption class="legend">'._('Studienbereiche').'<caption>';
-            echo "\n" . '<tr><td style="text-align: center">';
-            $this->sem_tree->show_entries = $this->sem_browse_data['show_entries'] ?? false;
-            $this->sem_tree->showSemTree($start_id);
-        }
-        if ($this->sem_browse_data['level'] == 'ev') {
-            echo "\n" . '<caption class="legend">'._('Einrichtungen').'<caption>';
-            echo "\n" . '<tr><td style="text-align: center">';
-            $this->range_tree->show_entries = $this->sem_browse_data['show_entries'] ?? false;
-            $this->range_tree->showSemRangeTree($start_id);
-        }
-
-        if ($this->show_result) {
-            $this->print_result();
-        }
-
-        echo '</td></tr></table>';
-        ob_end_flush();
-    }
-
-    public function print_result()
-    {
-        ob_start();
-        global $SEM_TYPE, $SEM_CLASS;
-
-        if (is_array($this->sem_browse_data['search_result'])
-                && count($this->sem_browse_data['search_result'])) {
-            if (!is_object($this->sem_tree)) {
-                $this->sem_tree = new StudipSemTreeViewSimple(
-                        $this->sem_browse_data['start_item_id'] ?? null,
-                        $this->sem_number,
-                        !empty($this->sem_browse_data['sem_status']) && is_array($this->sem_browse_data['sem_status'])
-                            ? $this->sem_browse_data['sem_status'] : false,
-                        !(is_object($GLOBALS['perm']) && $GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM))
-                );
-            }
-            $the_tree = $this->sem_tree->tree;
-
-            list($group_by_data, $sem_data) = $this->get_result();
-
-            $visibles = $sem_data;
-            if (!$GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM)) {
-                $visibles = array_filter($visibles, function ($c) {
-                    return key($c['visible']) == 1;
-                });
-            }
-
-            echo '<table class="default" id="sem_search_result" style="width: calc(100% - 21px);" >';
-            foreach ($group_by_data as $group_field => $sem_ids) {
-                if (Config::get()->COURSE_SEARCH_SHOW_ADMISSION_STATE) {
-                    echo '<tr><th colspan="6">';
-                } else {
-                    echo '<tr><th colspan="5">';
-                }
-                switch ($this->sem_browse_data['group_by'] ?? null) {
-                    case 0:
-                        echo htmlReady($this->search_obj->sem_dates[$group_field]['name'] ?? '');
-                        break;
-                    case 1:
-                        if ($the_tree->tree_data[$group_field]) {
-                            echo htmlReady($the_tree->getShortPath($group_field));
-                            if (is_object($this->sem_tree)){
-                                echo $this->sem_tree->getInfoIcon($group_field);
-                            }
-                        } else {
-                            echo _('keine Studienbereiche eingetragen');
-                        }
-                        break;
-                    case 3:
-                        echo htmlReady($SEM_TYPE[$group_field]['name']
-                                . ' ('
-                                . $SEM_CLASS[$SEM_TYPE[$group_field]['class']]['name']
-                                . ')');
-                        break;
-                    default:
-                        echo htmlReady($group_field);
-                }
-                echo '</th></tr>';
-                ob_end_flush();
-                ob_start();
-                if (is_array($sem_ids['Seminar_id'])) {
-                    foreach(array_keys($sem_ids['Seminar_id']) as $seminar_id){
-                        echo $this->printCourseRow($seminar_id, $sem_data);
-                    }
-                }
-            }
-            echo '</table>';
-        } elseif ($this->search_obj->search_button_clicked
-                && !$this->search_obj->new_search_button_clicked) {
-            $details = [];
-            if ($this->search_obj->found_rows === false) {
-                $details = [_('Der Suchbegriff fehlt oder ist zu kurz')];
-            }
-            if ($details) {
-                PageLayout::postError(_('Ihre Suche ergab keine Treffer'), $details);
-            } else {
-                PageLayout::postInfo(_('Ihre Suche ergab keine Treffer'));
-            }
-            $this->sem_browse_data['sset'] = 0;
-        }
-        ob_end_flush();
-    }
-
-    public function get_result()
-    {
-        global $_fullname_sql, $user;
-        if ($this->sem_browse_data['group_by'] == 1) {
-            if (!is_object($this->sem_tree)) {
-                $the_tree = TreeAbstract::GetInstance('StudipSemTree', false);
-            } else {
-                $the_tree = $this->sem_tree->tree;
-            }
-            $sem_tree_query = '';
-            if ($this->sem_browse_data['start_item_id'] != 'root'
-                    && ($this->sem_browse_data['level'] == 'vv'
-                    || $this->sem_browse_data['level'] == 'sbb')) {
-                $allowed_ranges = $the_tree->getKidsKids($this->sem_browse_data['start_item_id']);
-                $allowed_ranges[] = $this->sem_browse_data['start_item_id'];
-                $sem_tree_query = " AND sem_tree_id IN('" . join("','", $allowed_ranges) . "') ";
-            }
-            $add_fields = 'seminar_sem_tree.sem_tree_id AS bereich,';
-            $add_query = "LEFT JOIN seminar_sem_tree ON (seminare.Seminar_id = seminar_sem_tree.seminar_id $sem_tree_query)";
-        } else if ($this->sem_browse_data['group_by'] == 4){
-            $add_fields = 'Institute.Name AS Institut,Institute.Institut_id,';
-            $add_query = 'LEFT JOIN seminar_inst
-                            ON (seminare.Seminar_id = seminar_inst.Seminar_id)
-                          LEFT JOIN Institute
-                            ON (Institute.Institut_id = seminar_inst.institut_id)';
-        } else {
-            $add_fields = '';
-            $add_query = '';
-        }
-
-        $dbv = DbView::getView('sem_tree');
-
-        $query = "
-            SELECT seminare.Seminar_id, VeranstaltungsNummer, seminare.status,
-                IF(seminare.visible = 0, CONCAT(seminare.Name, ' " . _('(versteckt)')
-                    . "'), seminare.Name) AS Name,"
-                . $add_fields
-                . $_fullname_sql['full'] . " AS fullname,
-                    auth_user_md5.username,"
-                . $dbv->sem_number_sql . ' AS sem_number, '
-                . $dbv->sem_number_end_sql . ' AS sem_number_end,
-                seminar_user.position AS position, seminare.parent_course, seminare.visible
-            FROM seminare
-                LEFT JOIN seminar_user
-                    ON (seminare.Seminar_id=seminar_user.Seminar_id AND seminar_user.status = ' . "'dozent'" . ')
-                LEFT JOIN auth_user_md5
-                    USING (user_id)
-                LEFT JOIN user_info
-                    USING (user_id) '
-                . $add_query . "
-            WHERE (seminare.Seminar_id IN('" . join("','", array_keys($this->sem_browse_data['search_result'])) . "')
-                OR seminare.parent_course IN ('" . join("','", array_keys($this->sem_browse_data['search_result'])) . "'))";
-
-        // don't show Studiengruppen if user not logged in
-        if (!$GLOBALS['user'] || $GLOBALS['user']->id == 'nobody') {
-            $studygroup_types = DBManager::get()->quote(studygroup_sem_types());
-            $query .= " AND seminare.status NOT IN ({$studygroup_types})";
-        }
-
-        $db = new DB_Seminar($query);
-        $snap = new DbSnapshot($db);
-        $group_field = $this->group_by_fields[$this->sem_browse_data['group_by']]['group_field'];
-        $data_fields[0] = 'Seminar_id';
-        if (!empty($this->group_by_fields[$this->sem_browse_data['group_by']]['unique_field'])) {
-            $data_fields[1] = $this->group_by_fields[$this->sem_browse_data['group_by']]['unique_field'];
-        }
-        if($user->id == 'nobody' && $snap->numRows == 0){
-            $group_by_data = $sem_data = [];
-        }else{
-            $group_by_data = $snap->getGroupedResult($group_field, $data_fields);
-            $sem_data = $snap->getGroupedResult('Seminar_id');
-        }
-
-        if ($this->sem_browse_data['group_by'] == 0) {
-            if($user->id == 'nobody' && $snap->numRows == 0){
-                $group_by_duration = [];
-            }else{
-                $group_by_duration = $snap->getGroupedResult('sem_number_end', ['sem_number', 'Seminar_id']);
-            }
-            foreach ($group_by_duration as $sem_number_end => $detail) {
-                if ($sem_number_end != -1
-                        && ($detail['sem_number'][$sem_number_end]
-                                && count($detail['sem_number']) == 1)) {
-                    continue;
-                }
-
-                $current_semester_index = Semester::getIndexById(Semester::findCurrent()->semester_id, true, true);
-                foreach (array_keys($detail['Seminar_id']) as $seminar_id) {
-                    $start_sem = key($sem_data[$seminar_id]['sem_number']);
-                    if ($sem_number_end == -1) {
-                        if ($this->sem_number === false) {
-                            $sem_number_end = $current_semester_index && isset($this->search_obj->sem_dates[$current_semester_index + 1]) ? $current_semester_index + 1 : count($this->search_obj->sem_dates) -1;
-                        } else {
-                            $sem_number_end = $this->sem_number[0];
-                        }
-                    }
-                    for ($i = $start_sem; $i <= $sem_number_end; ++$i) {
-                        if ($this->sem_number === false
-                                || is_array($this->sem_number)
-                                && in_array($i, $this->sem_number)) {
-                            if (!empty($group_by_data[$i]) && empty($tmp_group_by_data[$i])) {
-                                foreach (array_keys($group_by_data[$i]['Seminar_id']) as $id) {
-                                    $tmp_group_by_data[$i]['Seminar_id'][$id] = true;
-                                }
-                            }
-                            $tmp_group_by_data[$i]['Seminar_id'][$seminar_id] = true;
-                        }
-                    }
-                }
-            }
-            if (!empty($tmp_group_by_data) && is_array($tmp_group_by_data)) {
-                if ($this->sem_number !== false) {
-                    unset($group_by_data);
-                }
-                foreach ($tmp_group_by_data as $start_sem => $detail) {
-                    $group_by_data[$start_sem] = $detail;
-                }
-            }
-        }
-
-        //release memory
-        unset($snap);
-        unset($tmp_group_by_data);
-
-        foreach ($group_by_data as $group_field => $sem_ids) {
-            foreach ($sem_ids['Seminar_id'] as $seminar_id => $foo) {
-                $name = mb_strtolower(key($sem_data[$seminar_id]['Name']));
-                $name = str_replace(['ä', 'ö', 'ü'], ['ae', 'oe', 'ue'], $name);
-                if (Config::get()->IMPORTANT_SEMNUMBER && key($sem_data[$seminar_id]['VeranstaltungsNummer'])) {
-                    $name = key($sem_data[$seminar_id]['VeranstaltungsNummer']) . ' ' . $name;
-                }
-                $group_by_data[$group_field]['Seminar_id'][$seminar_id] = $name;
-            }
-            uasort($group_by_data[$group_field]['Seminar_id'], 'strnatcmp');
-        }
-
-        switch ($this->sem_browse_data['group_by']) {
-            case 0:
-                krsort($group_by_data, SORT_NUMERIC);
-                break;
-            case 1:
-                uksort($group_by_data, function($a,$b) {
-                    $the_tree = TreeAbstract::GetInstance('StudipSemTree', false);
-                    $the_tree->buildIndex();
-                    return $the_tree->tree_data[$a]['index'] - $the_tree->tree_data[$b]['index'];
-                });
-                break;
-            case 3:
-                uksort($group_by_data, function ($a,$b) {
-                    global $SEM_CLASS,$SEM_TYPE;
-                    return strnatcasecmp($SEM_TYPE[$a]['name'], $SEM_TYPE[$b]['name'])
-                        ?: strnatcasecmp(
-                               $SEM_CLASS[$SEM_TYPE[$a]['class']]['name'],
-                               $SEM_CLASS[$SEM_TYPE[$b]["class"]]['name']
-                           );
-                });
-                break;
-            default:
-                uksort($group_by_data, 'strnatcasecmp');
-        }
-
-        return [$group_by_data, $sem_data];
-    }
-
-    /**
-     * Creates HTML code for a single course row. This has been extracted
-     * into a separate function as that makes handling and outputting
-     * course children easier.
-     *
-     * @param string $seminar_id a single course id to output
-     * @param mixed $sem_data collected data for all found courses
-     * @param bool $child call in "child mode" -> force output because here children are listed
-     * @return string A HTML table row.
-     */
-    private function printCourseRow($seminar_id, &$sem_data, $child = false)
-    {
-        global $SEM_TYPE;
-
-        $row = '';
-
-        /*
-         * As we include child courses now, we need an extra check for visibility.
-         * Child courses are not shown extra, but summarized under their parent if
-         * the parent is part of the search result.
-         */
-        if (($GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM)
-                || key($sem_data[$seminar_id]['visible']) == 1)
-                && (empty($sem_data[key($sem_data[$seminar_id]['parent_course'])])
-                        || $child)) {
-            // create instance of seminar-object
-            $course = Course::find($seminar_id);
-
-            $sem_name = $course->getFullName('type-name');
-            $seminar_number = $course->veranstaltungsnummer;
-
-            $visibleChildren = [];
-
-            $row .= '<tr';
-            // Set necessary classes if we are displaying subcourses.
-            if ($child) {
-                $row .= ' class="hidden-js subcourses subcourses-' . key($sem_data[$seminar_id]['parent_course']) . '"' ;
-            }
-            $row .= '>';
-
-            if ($course->isStudygroup()) {
-                $sem_name .= ' (' . _('Studiengruppe');
-                if ($course->admission_prelim) {
-                    $sem_name .= ', ' . _('Zutritt auf Anfrage');
-                }
-                $sem_name .= ')';
-                $row .= '<td width="1%" class="hidden-tiny-down">';
-                $row .= StudygroupAvatar::getAvatar($seminar_id)->getImageTag(Avatar::SMALL, ['title' => $course->name]);
-                $row .= '</td>';
-            } else {
-                $sem_number_start = key($sem_data[$seminar_id]['sem_number']);
-                $sem_number_end = key($sem_data[$seminar_id]['sem_number_end']);
-                if ($sem_number_start != $sem_number_end) {
-                    $sem_name .= ' (' . $this->search_obj->sem_dates[$sem_number_start]['name'] . ' - ';
-                    $sem_name .= (($sem_number_end == -1)
-                            ? _('unbegrenzt')
-                            : $this->search_obj->sem_dates[$sem_number_end]['name']) . ')';
-                } elseif ($this->sem_browse_data['group_by']) {
-                    $sem_name .= " (" . $this->search_obj->sem_dates[$sem_number_start]['name'] . ')';
-                }
-                $row .= '<td width="1%" class="hidden-tiny-down">';
-                $row .= CourseAvatar::getAvatar($seminar_id)->getImageTag(Avatar::SMALL, ['title' => $course->name]);
-                $row .= '</td>';
-
-            }
-            $send_from_search = URLHelper::getUrl(basename($_SERVER['PHP_SELF']), ['keep_result_set' => 1, 'cid' => null]);
-            $send_from_search_link = URLHelper::getLink($this->target_url,
-                    [
-                        $this->target_id => $seminar_id,
-                        'cid' => null,
-                        'send_from_search' => 1,
-                        'send_from_search_page' => $send_from_search
-                    ]);
-            $row .= '<td style="width: 66%" colspan="2">';
-
-            // Show the "more" icon only if there are visible children.
-            if (count($course->children) > 0) {
-
-                // If you are not root, perhaps not all available subcourses are visible.
-                $visibleChildren = $course->children;
-                if (!$GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM)) {
-                    $visibleChildren = $visibleChildren->filter(function($c) {
-                        return $c->visible;
-                    });
-                }
-                if (count($visibleChildren) > 0) {
-                    $row .= Icon::create('add', Icon::ROLE_CLICKABLE ,[
-                            'id' => 'show-subcourses-' . $seminar_id,
-                            'title' => sprintf(_('%u Unterveranstaltungen anzeigen'), count($visibleChildren)),
-                            'onclick' => "jQuery('tr.subcourses-" . $seminar_id . "').removeClass('hidden-js');jQuery(this).closest('tr').addClass('has-subcourses');jQuery(this).hide();jQuery('#hide-subcourses-" . $seminar_id . "').show();"
-                        ])->asImg(12) . ' ';
-                    $row .= Icon::create('remove', Icon::ROLE_CLICKABLE ,[
-                            'id' => 'hide-subcourses-' . $seminar_id,
-                            'style' => 'display:none',
-                            'title' => sprintf(_('%u Unterveranstaltungen ausblenden'), count($visibleChildren)),
-                            'onclick' => "jQuery('tr.subcourses-" . $seminar_id . "').addClass('hidden-js'); jQuery(this).closest('tr').removeClass('has-subcourses');jQuery(this).hide();jQuery('#show-subcourses-" . $seminar_id . "').show();"
-                        ])->asImg(12) . ' ';
-                }
-            }
-
-            $row .= '<a href="' . $send_from_search_link . '">';
-            if (Config::get()->IMPORTANT_SEMNUMBER && $seminar_number) {
-                $row .= htmlReady($seminar_number) . " ";
-            }
-            $row .= htmlReady($sem_name) . '</a><br>';
-            //create Turnus field
-            if ($course->isStudygroup()) {
-                $row .= '<div style="font-size:smaller">'
-                        . htmlReady(mb_substr($course->description, 0, 100))
-                        . '</div>';
-            } else {
-                $temp_turnus_string = implode(" ", $course->getAllDatesInSemester()->toStringArray());
-                //Shorten, if string too long (add link for details.php)
-                if (mb_strlen($temp_turnus_string) > 70) {
-                    $temp_turnus_string = htmlReady(mb_substr($temp_turnus_string, 0, mb_strpos(mb_substr($temp_turnus_string, 70, mb_strlen($temp_turnus_string)), ',') + 71));
-                    $temp_turnus_string .= ' ... <a href="' . $send_from_search_link . '">(' . _('mehr') . ')</a>';
-                } else {
-                    $temp_turnus_string = htmlReady($temp_turnus_string);
-                }
-                if (!Config::get()->IMPORTANT_SEMNUMBER) {
-                    $row .= '<div style="margin-left:5px;font-size:smaller">' . htmlReady($seminar_number) . '</div>';
-                }
-                $row .= '<div style="margin-left:5px;font-size:smaller">' . $temp_turnus_string . '</div>';
-                if (count($course->children) > 0 && count($visibleChildren) > 0) {
-                    $row .= '<div style="margin-left:5px;font-size:smaller">';
-                    $row .= sprintf(_('%u Unterveranstaltungen'), count($visibleChildren));
-                    $row .= '</div>';
-                }
-            }
-            $row .= '</td>';
-            $row .= '<td style="text-align: right">(';
-            $doz_name = [];
-            $c = 0;
-            reset($sem_data[$seminar_id]['fullname']);
-            foreach ($sem_data[$seminar_id]['username'] as $anzahl1) {
-                if ($c == 0) {
-                    $d_name = key($sem_data[$seminar_id]['fullname']);
-                    $anzahl2 = current($sem_data[$seminar_id]['fullname']);
-                    next($sem_data[$seminar_id]['fullname']);
-                    $c = $anzahl2 / $anzahl1;
-                    $doz_name = array_merge($doz_name, array_fill(0, $c, $d_name));
-                }
-                --$c;
-            }
-            $doz_uname = array_keys($sem_data[$seminar_id]['username']);
-            $doz_position = array_keys($sem_data[$seminar_id]['position']);
-            if (count($doz_name)) {
-                if (count($doz_position) != count($doz_uname)) {
-                    $doz_position = range(1, count($doz_uname));
-                }
-                array_multisort($doz_position, $doz_name, $doz_uname);
-                $i = 0;
-                foreach ($doz_name as $index => $value) {
-                    if ($value) {  // hide dozenten with empty username
-                        if ($i == 4) {
-                            $row .= '... <a href="' . $send_from_search_link . '">(' . _('mehr') . ')</a>';
-                            break;
-                        }
-                        $row .= '<a href="' . URLHelper::getLink('dispatch.php/profile', ['username' => $doz_uname[$index]]) . '">' . htmlReady($value) . '</a>';
-                        if ($i != count($doz_name) - 1) {
-                            $row .= ', ';
-                        }
-                    }
-                    ++$i;
-                }
-                $row .= ')</td>';
-                if (Config::get()->COURSE_SEARCH_SHOW_ADMISSION_STATE) {
-                    $row .= '<td>';
-                    switch (self::getStatusCourseAdmission($seminar_id, $course->admission_prelim)) {
-                        case 1:
-                            $row .= Icon::create(
-                                'info-circle',
-                                Icon::ROLE_STATUS_YELLOW,
-                                tooltip2(_('Eingeschränkter Zugang'))
-                            );
-                            break;
-                        case 2:
-                            $row .= Icon::create(
-                                'decline-circle',
-                                Icon::ROLE_STATUS_RED,
-                                tooltip2(_('Kein Zugang'))
-                            );
-                            break;
-                        default:
-                            $row .= Icon::create(
-                                'check-circle',
-                                Icon::ROLE_STATUS_GREEN,
-                                tooltip2(_('Uneingeschränkter Zugang'))
-                            );
-                    }
-                    $row .= '</td>';
-                }
-                $row .= '</tr>';
-            }
-
-            // Process children.
-            foreach ($course->children as $child) {
-                $row .= $this->printCourseRow($child->id, $sem_data, true);
-            }
-
-        }
-
-        return $row;
-    }
-
-
-    /**
-     * Returns a new navigation object corresponding to the given target and
-     * name of the option. The target has two possibel values "sidebar" and
-     * "course" and indicates the place where the navigation is shown.
-     * The option name is the key of an entry in the array with the navigation
-     * options.
-     *
-     * The navigation options are configured in the global configuration as an
-     * array. For further details see documentation of entry
-     * COURSE_SEARCH_NAVIGATION_OPTIONS in global configuration.
-     *
-     * This is an example with all possible options:
-     *
-     * {
-     *     // "courses", "semtree" and "rangetree" are the "old" search options.
-     *     // The link text is fixed.
-     *     "courses":{
-     *         "visible":true,
-     *         // The target indicates where the link to this search option is
-     *         // placed. Possible values are "sidebar" for a link in the sidebar
-     *         // or "courses" to show a link (maybe with picture) below the
-     *         // "course search".
-     *         "target":"sidebar"
-     *     },
-     *     "semtree":{
-     *         "visible":true,
-     *         "target":"sidebar"
-     *     },
-     *     "rangetree":{
-     *         "visible":false,
-     *         "target":"sidebar"
-     *     },
-     *     // New option to acivate the search for modules and the systematic
-     *     // search in studycourses, field of study and degrees.
-     *     "module":{
-     *         "visible":true,
-     *         "target":"sidebar"
-     *     },
-     *     // This option shows a direct link in the sidebar to an entry (level)
-     *     // in the range tree. The link text is the name of the level.
-     *     "fb3_hist":{
-     *         "visible":true,
-     *         "target":"sidebar",
-     *         "range_tree_id":"d1a07cf0c8057c664279214cc070b580"
-     *     },
-     *     // The same for an entry in the sem tree.
-     *     "grundstudium":{
-     *         "visible":true,
-     *         "target":"sidebar",
-     *         "sem_tree_id":"e1a07cf0c8057c664279214cc070b580"
-     *     },
-     *     // This shows a link in the sidebar to the course search. The text is
-     *     // availlable in two languages.
-     *     "vvz":{
-     *         "visible":true,
-     *         "target":"sidebar",
-     *         "url":"dispatch.php/search/courses?level=f&option=vav",
-     *         "title":{
-     *             "de_DE":"Veranstaltungsverzeichnis",
-     *             "en_GB":"Course Catalogue"
-     *         }
-     *     },
-     *     // This option uses an url with search option and shows a link in the
-     *     // sidebar to an entry in the range tree with all courses.
-     *     "test":{
-     *         "visible":true,
-     *         "target":"sidebar",
-     *         "url":"dispatch.php/search/courses?start_item_id=d1a07cf0c8057c664279214cc070b580&cmd=show_sem_range_tree&item_id=d1a07cf0c8057c664279214cc070b580_withkids&level=ev",
-     *         "title":{
-     *             "de_DE":"Historisches Institut",
-     *             "en_GB":"Historical Institute"
-     *         }
-     *     },
-     *     // This option shows a link to the sem tree with picture below the
-     *     // course search (target: courses).
-     *     // This is the behaviour of Stud.IP < 4.2.
-     *     "csemtree":{
-     *         "visible":true,
-     *         "target":"courses",
-     *         "url":"dispatch.php/search/courses?level=vv",
-     *         "img":{
-     *             "filename":"directory-search.png",
-     *             "attributes":{
-     *                 "size":"260@100"
-     *             }
-     *         },
-     *         "title":{
-     *             "de_DE":"Suche im Vorlesungsverzeichnis",
-     *             "en_GB":"Search course directory"
-     *         }
-     *     },
-     *     // This option shows a link to the range tree with picture below the
-     *     // course search (target: courses).
-     *     // This is the behaviour of Stud.IP < 4.2.
-     *     "crangetree":{
-     *         "visible":true,
-     *         "target":"courses",
-     *         "url":"dispatch.php/search/courses?level=ev",
-     *         "img":{
-     *             "filename":"institute-search.png",
-     *             "attributes":{
-     *                 "size":"260@100"
-     *             }
-     *         },
-     *         "title":{
-     *             "de_DE":"Suche in Einrichtungen",
-     *             "en_GB":"Search institutes"
-     *         }
-     *     }
-     * }
-     *
-     *
-     * @param string $target
-     * @param string $option_name
-     * @return Navigation|null
-     */
-    public static function getSearchOptionNavigation($target, $option_name = null): ?Navigation
-    {
-        // return first visible search option
-        if (is_null($option_name)) {
-            $options = Config::get()->COURSE_SEARCH_NAVIGATION_OPTIONS;
-            foreach ($options as $name => $option) {
-                if ($option['visible'] && $option['target'] === $target) {
-                    return self::getSearchOptionNavigation($target, $name);
-                }
-            }
-            return null;
-        }
-
-        $installed_languages = array_keys(Config::get()->INSTALLED_LANGUAGES);
-        $language = $_SESSION['_language'] ?? reset($installed_languages);
-        $option = Config::get()->COURSE_SEARCH_NAVIGATION_OPTIONS[$option_name];
-        if (!$option['visible'] || $option['target'] !== $target) {
-            return null;
-        }
-        if (empty($option['url'])) {
-            switch ($option_name) {
-                case 'courses':
-                case 'semtree':
-                    return new Navigation(_('Vorlesungsverzeichnis'),
-                            URLHelper::getURL('dispatch.php/search/courses',
-                                    [
-                                        'type' => 'semtree'
-                                    ], true));
-                case 'rangetree':
-                    return new Navigation(_('Einrichtungsverzeichnis'),
-                            URLHelper::getURL('dispatch.php/search/courses',
-                                    [
-                                        'type' => 'rangetree'
-                                    ], true));
-                case 'module':
-                    return new MVVSearchNavigation(_('Modulverzeichnis'),
-                            URLHelper::getURL('dispatch.php/search/module'),null, true);
-            }
-        } else {
-            return new Navigation($option['title'][$language],
-                    URLHelper::getURL($option['url'], ['option' => $option_name], true));
-        }
-        if (!empty($option['sem_tree_id'])) {
-            $study_area = StudipStudyArea::find($option['sem_tree_id']);
-            return new Navigation($study_area->name,
-                    URLHelper::getURL('dispatch.php/search/courses',
-                        [
-                            'start_item_id' => $option['sem_tree_id'],
-                            'path_id'       => $option['sem_tree_id'],
-                            'cmd'           => 'show_sem_range',
-                            'item_id'       => $option['sem_tree_id'] . '_withkids',
-                            'level'         => 'vv',
-                            'option'        => $option_name
-                        ], true));
-        }
-        if (!empty($option['range_tree_id'])) {
-            $item_name = DBManager::get()->fetchColumn('
-                    SELECT `name`
-                    FROM `range_tree`
-                    WHERE item_id = ?',
-                    [$option['range_tree_id']]);
-            return new Navigation($item_name,
-                    URLHelper::getURL('dispatch.php/search/courses',
-                        [
-                            'start_item_id' => $option['range_tree_id'],
-                            'path_id'       => $option['range_tree_id'],
-                            'cmd'           => 'show_sem_range_tree',
-                            'item_id'       => $option['range_tree_id'] . '_withkids',
-                            'level'         => 'ev',
-                            'option'        => $option_name
-                        ], true));
-        }
-
-        return null;
-    }
-
-    /**
-     * The class SemBrowse uses a vast number of variables stored in the
-     * session. This function sets the default values or transfers some
-     * of them to url parameters if a filter in the sidebar has been changed.
-     *
-     * @see SemBrowse::setClassesSelector()
-     * @see SemBrowse::setSemesterSelector()
-     */
-    public static function transferSessionData()
-    {
-        if (empty($_SESSION['sem_browse_data']) || Request::option('reset_all')) {
-            $_SESSION['sem_browse_data'] = [];
-        }
-
-        $_SESSION['sem_browse_data']['qs_choose'] = Request::get('search_sem_qs_choose',
-                $_SESSION['sem_browse_data']['qs_choose'] ?? null);
-
-        // simulate button clicked if semester was changed
-        $old_default_sem = $_SESSION['sem_browse_data']['default_sem'] ?? null;
-        if (Request::option('search_sem_sem', $old_default_sem) != $old_default_sem) {
-            $_SESSION['sem_browse_data']['default_sem'] = Request::option('search_sem_sem');
-            if ($_SESSION['sem_browse_data']['sset']) {
-                Request::set('search_sem_quick_search_parameter', $_SESSION['sem_browse_data']['sset']);
-                Request::set('search_sem_quick_search', $_SESSION['sem_browse_data']['sset']);
-                Request::set('search_sem_qs_choose', $_SESSION['sem_browse_data']['qs_choose']);
-                Request::set('search_sem_category', $_SESSION['sem_browse_data']['show_class']);
-                Request::set('search_sem_do_search', '1');
-                Request::set('search_sem_' . md5('is_sended'), '1');
-            } else {
-                Request::set('search_sem_category', $_SESSION['sem_browse_data']['show_class']);
-                Request::set('search_sem_sem_change', '1');
-                Request::set('search_sem_sem_select', '1');
-            }
-        }
-
-        // simulate button clicked if class was changed
-        $old_show_class = $_SESSION['sem_browse_data']['show_class'] ?? null;
-        if (Request::option('show_class', $old_show_class) != $old_show_class) {
-            $_SESSION['sem_browse_data']['show_class'] = Request::option('show_class');
-
-            if ($_SESSION['sem_browse_data']['show_class']
-                    && $_SESSION['sem_browse_data']['show_class'] != 'all') {
-                $class = $GLOBALS['SEM_CLASS'][$_SESSION['sem_browse_data']['show_class']];
-                $_SESSION['sem_browse_data']['sem_status'] = array_keys($class->getSemTypes());
-            } else {
-                $_SESSION['sem_browse_data']['sem_status'] = false;
-            }
-
-            if ($_SESSION['sem_browse_data']['sset']) {
-                Request::set('search_sem_quick_search_parameter', $_SESSION['sem_browse_data']['sset']);
-                Request::set('search_sem_quick_search', $_SESSION['sem_browse_data']['sset']);
-                Request::set('search_sem_qs_choose', $_SESSION['sem_browse_data']['qs_choose']);
-                Request::set('search_sem_category', $_SESSION['sem_browse_data']['show_class']);
-                Request::set('search_sem_do_search', '1');
-                Request::set('search_sem_' . md5('is_sended'), '1');
-            } else {
-                Request::set('search_sem_category', $_SESSION['sem_browse_data']['show_class']);
-                Request::set('search_sem_sem_change', '1');
-                Request::set('search_sem_sem_select', '1');
-            }
-        }
-
-        // set default values
-        if (empty($_SESSION['sem_browse_data']['default_sem'])) {
-            $_SESSION['sem_browse_data']['default_sem'] =
-                Semester::getIndexById(self::getDefaultSemester(), true, true)
-                        ?: 'all';
-        }
-        $_SESSION['sem_browse_data']['show_class'] =
-                $_SESSION['sem_browse_data']['show_class'] ?? 'all';
-        $_SESSION['sem_browse_data']['group_by'] =
-                $_SESSION['sem_browse_data']['group_by'] ?? '0';
-    }
-
-    /**
-     * Retrieves the default semester from session or calculate it considering
-     * the value from SEMESTER_TIME_SWITCH.
-     *
-     * @return Semester The semester object of the default semester.
-     */
-    public static function getDefaultSemester()
-    {
-        $default_sem = $_SESSION['_default_sem'];
-        if (!$default_sem) {
-            $current_sem = Semester::findDefault();
-            $default_sem = $current_sem->id;
-        }
-
-        return $default_sem;
-    }
-
-    /**
-     * Adds a widget to the sidebar to select a course class. The result set is
-     * filtered by this class.
-     *
-     * @param string $submit_url The submit url.
-     */
-    public static function setClassesSelector($submit_url)
-    {
-        $classes_filter = new SelectWidget(_('Veranstaltungsklassen'),
-                $submit_url, 'show_class');
-        $classes_filter->addElement(new SelectElement('all', _('Alle'),
-                ($_SESSION['sem_browse_data']['show_class'] ?: 'all') === 'all'));
-        foreach ($GLOBALS['SEM_CLASS'] as $key => $val) {
-            $classes_filter->addElement(new SelectElement($key, $val['name'],
-                    ($_SESSION['sem_browse_data']['show_class'] == $key)));
-        }
-        Sidebar::Get()->addWidget($classes_filter);
-    }
-
-    /**
-     * Adds a widget to the sidebar to select a semester. The result set is
-     * filtered by this semester.
-     *
-     * @param string $submit_url The submit url.
-     */
-    public static function setSemesterSelector($submit_url)
-    {
-        $semesters = Semester::findAllVisible();
-        $sidebar = Sidebar::Get();
-        $list = new SelectWidget(_('Semester'),
-                $submit_url, 'search_sem_sem');
-        $list->addElement(new SelectElement('all', _('Alle'),
-                ($_SESSION['sem_browse_data']['default_sem']) === 'all'));
-        foreach(array_reverse($semesters, true) as $i => $semester_data) {
-            $list->addElement(new SelectElement(
-                $i,
-                $semester_data['name'],
-                ($_SESSION['sem_browse_data']['default_sem'] !== 'all'
-                    && intval($_SESSION['sem_browse_data']['default_sem']) === $i)
-            ));
-        }
-        $sidebar->addWidget($list, 'filter_semester');
-    }
-
-    /**
-     * Returns the admission status for a course.
-     *
-     * @param string $seminar_id Id of the course
-     * @param bool   $prelim     State of preliminary setting
-     * @return int
-     */
-    public static function getStatusCourseAdmission($seminar_id, $prelim)
-    {
-        $sql = "SELECT COUNT(`type`) AS `types`,
-                       SUM(IF(`type` = 'LockedAdmission', 1, 0)) AS `type_locked`
-                FROM `seminar_courseset`
-	            INNER JOIN `courseset_rule` USING (`set_id`)
-	            WHERE `seminar_id` = ?
-                GROUP BY `set_id`";
-
-	    $stmt = DBManager::get()->prepare($sql);
-	    $stmt->execute([$seminar_id]);
-	    $result = $stmt->fetch();
-
-        if (!empty($result['types'])) {
-            if ($result['type_locked']) {
-                return 2;
-            }
-            return 1;
-        }
-
-        if ($prelim) {
-            return 1;
-        }
-        return 0;
-    }
-
-    /**
-     * Returns a Quick Search form to put inside a WidgetElement.
-     *
-     * @param string   $level     The Level of search , expected ('f', 'vv', 'ev')
-     * @return string $search_form_content Contains a form element with a quick search input, predefined (hidden) inputs and search button
-     */
-    public function getQuickSearchForm()
-    {
-        if ($this->sem_browse_data['level'] === 'vv') {
-            $this->search_obj->sem_tree =& $this->sem_tree->tree;
-            if ($this->sem_tree->start_item_id !== 'root') {
-                $this->search_obj->search_scopes[] = $this->sem_tree->start_item_id;
-            }
-        } elseif ($this->sem_browse_data['level'] === 'ev') {
-            $this->search_obj->range_tree =& $this->range_tree->tree;
-            if ($this->range_tree->start_item_id !== 'root'){
-                $this->search_obj->search_ranges[] = $this->range_tree->start_item_id;
-            }
-        }
-
-        $search_form_content = $this->search_obj->getFormStart(URLHelper::getLink(), ['class' => '']);
-        $quicksearch = $this->getQuicksearch();
-        $quicksearch->setInputStyle('height:22px;width: 100%;');
-        $quicksearch->withButton(['search_button_name'=> 'course_search_button']);
-        $quicksearch->disableAutocomplete();
-        $search_form_content .= $quicksearch->render();
-        $search_form_content .= $this->search_obj->getHiddenField('qs_choose','title_lecturer_number');
-
-        if($this->sem_browse_data['level'] == 'vv')
-            $search_form_content .= $this->search_obj->getHiddenField('scope_choose', $this->sem_tree->start_item_id);
-
-        if($this->sem_browse_data['level'] == 'ev')
-            $search_form_content .= $this->search_obj->getHiddenField('range_choose', $this->range_tree->start_item_id);
-
-        $search_form_content .= $this->search_obj->getHiddenField('level', $this->sem_browse_data['level']);
-        $search_form_content .= $this->search_obj->getHiddenField('sem', htmlReady($_SESSION['sem_browse_data']['default_sem']));
-
-        $search_form_content .= $this->search_obj->getFormEnd();
-        return $search_form_content;
-    }
-}
diff --git a/lib/classes/Seminar.php b/lib/classes/Seminar.php
new file mode 100644
index 0000000..e69de29
diff --git a/lib/classes/StudipRangeTree.php b/lib/classes/StudipRangeTree.php
deleted file mode 100644
index 5e1aefe..0000000
--- a/lib/classes/StudipRangeTree.php
+++ /dev/null
@@ -1,222 +0,0 @@
-<?
-# Lifter002: TODO
-# Lifter007: TODO
-# Lifter003: TODO
-# Lifter010: TODO
-// +---------------------------------------------------------------------------+
-// This file is part of Stud.IP
-// StudipRangeTree.php
-// Class to handle structure of the "range tree"
-//
-// Copyright (c) 2002 André Noack <noack@data-quest.de>
-// Suchi & Berg GmbH <info@data-quest.de>
-// +---------------------------------------------------------------------------+
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or any later version.
-// +---------------------------------------------------------------------------+
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-// +---------------------------------------------------------------------------+
-
-/**
-* class to handle the "range tree"
-*
-* This class provides an interface to the structure of the "range tree"
-*
-* @access   public
-* @author   André Noack <noack@data-quest.de>
-* @package
-*/
-class StudipRangeTree extends TreeAbstract
-{
-    var $sem_number;
-    var $sem_status;
-    var $sem_dates;
-    var $studip_objects = [];
-    var $visible_only;
-    var $entries_init_done = false;
-
-    /**
-    * constructor
-    *
-    * do not use directly, call TreeAbstract::GetInstance("StudipRangeTree")
-    * @access private
-    */
-    function __construct($args) {
-        DbView::addView('range_tree');
-
-        $this->root_name = Config::get()->UNI_NAME_CLEAN;
-        $this->studip_objects['inst'] = ['pk' => 'Institut_id', 'table' => 'Institute'];
-        $this->studip_objects['fak'] = ['pk' => 'Institut_id', 'table' => 'Institute'];
-        if (isset($args['sem_number']) ){
-            $this->sem_number = array_map('intval', $args['sem_number']);
-        }
-        if (isset($args['sem_status']) ){
-            $this->sem_status = array_map('intval', $args['sem_status']);
-        }
-        $this->visible_only = (int)($args['visible_only'] ?? 0);
-        parent::__construct(); //calling the baseclass constructor
-        $this->sem_dates = Semester::findAllVisible();
-    }
-
-    /**
-    * initializes the tree
-    *
-    * stores all rows from table range_tree in array $tree_data
-    * @access public
-    */
-    function init(){
-        parent::init();
-        $this->tree_data['root']['studip_object_id'] = 'root';
-        $db = $this->view->get_query("view:TREE_GET_DATA");
-        while ($db->next_record()){
-            $item_name = $db->f("name");
-            if ($db->f("studip_object")){
-                $item_name = $db->f("studip_object_name");
-            }
-            $this->tree_data[$db->f("item_id")] = ["studip_object" => $db->f("studip_object"),
-                                                    "studip_object_id" => $db->f("studip_object_id"),
-                                                    "fakultaets_id" => $db->f("fakultaets_id"),"entries" => 0];
-            $this->storeItem($db->f("item_id"), $db->f("parent_id"), $item_name, $db->f("priority"));
-        }
-    }
-
-    function initEntries(){
-        $this->view->params[0] = (isset($this->sem_status)) ? " AND d.status IN('" . join("','", $this->sem_status) . "')" : " ";
-        $this->view->params[0] .= $this->visible_only ? " AND visible=1 " : "";
-        $this->view->params[1] = (isset($this->sem_number)) ? " WHERE ((" . $this->view->sem_number_sql
-                                . ") IN (" . join(",",$this->sem_number) .") OR ((" . $this->view->sem_number_sql
-                                .") <= " . $this->sem_number[count($this->sem_number)-1]
-                                . "  AND ((" . $this->view->sem_number_end_sql . ") >= " . $this->sem_number[count($this->sem_number)-1]
-                                . " OR (" . $this->view->sem_number_end_sql  . ") = -1))) " : "";
-
-        $db = $this->view->get_query("view:TREE_GET_SEM_ENTRIES");
-        while ($db->next_record()){
-            $this->tree_data[$db->f("item_id")]['entries'] = $db->f('entries');
-        }
-        $this->entries_init_done = true;
-    }
-
-    /**
-    * Returns Stud.IP range_id of the next "real" object
-    *
-    * This function finds the next item wich is a real Stud.IP Object, either an "Einrichtung" or a "Fakultaet"<br>
-    * useful for the user rights management
-    * @access   public
-    * @param    string  $item_id
-    * @return  bool|array   of primary keys from table "institute"
-    */
-    function getAdminRange($item_id) {
-        if (empty($this->tree_data[$item_id])) {
-            return false;
-        }
-
-        $found = false;
-        $ret = false;
-        $next_link = $item_id;
-
-        while(($next_link = $this->getNextLink($next_link)) != 'root') {
-            if ($this->tree_data[$next_link]['studip_object'] == 'inst') {
-                $found[] = $next_link;
-            }
-
-            if ($this->tree_data[$next_link]['studip_object'] == 'fak') {
-                if (is_array($found) && count($found)) {
-                    foreach($found as $f) {
-                        if ($this->tree_data[$f]['fakultaets_id'] == $this->tree_data[$next_link]['studip_object_id']) {
-                            $ret[] = $this->tree_data[$f]['studip_object_id'];
-                        }
-                    }
-
-                    $ret[] = $this->tree_data[$next_link]['studip_object_id'];
-                } else {
-                    $ret[] = $this->tree_data[$next_link]['studip_object_id'];
-                }
-                break;
-            }
-            $next_link = $this->tree_data[$next_link]['parent_id'];
-        }
-
-        if (!$ret){
-            $ret[] = $next_link;
-        }
-
-        return $ret;
-    }
-    /**
-    * returns the next item_id upwards the tree which is a Stud.IP object
-    *
-    * help function for getAdminRange()
-    *
-    * @access   private
-    * @param    string  $item_id
-    * @return   string
-    */
-
-    function getNextLink($item_id){
-    if (!$this->tree_data[$item_id])
-            return false;
-        $ret_id = $item_id;
-        while (!$this->tree_data[$ret_id]['studip_object_id']){
-            $ret_id = $this->tree_data[$ret_id]['parent_id'];
-        }
-        return $ret_id;
-    }
-
-    function getSemIds($item_id,$ids_from_kids = false){
-        if (!$this->tree_data[$item_id])
-            return false;
-        if ($ids_from_kids){
-            $this->view->params[0] = $this->getKidsKids($item_id);
-        }
-        $this->view->params[0][] = $item_id;
-        $this->view->params[1] = (isset($this->sem_number)) ? " HAVING sem_number IN (" . join(",",$this->sem_number) .") OR (sem_number <= " . $this->sem_number[count($this->sem_number)-1] . "  AND (sem_number_end >= " . $this->sem_number[count($this->sem_number)-1] . " OR sem_number_end = -1)) " : " ";
-        $ret = false;
-        $rs = $this->view->get_query("view:RANGE_TREE_GET_SEMIDS");
-        while($rs->next_record()){
-            $ret[] = $rs->f(0);
-        }
-        return $ret;
-    }
-
-    function getNumEntries($item_id, $num_entries_from_kids = false){
-        if (!$this->tree_data[$item_id])
-            return false;
-        if (!$this->entries_init_done) $this->initEntries();
-
-        return parent::getNumEntries($item_id, $num_entries_from_kids);
-    }
-
-    function InsertItem($item_id, $parent_id, $item_name, $priority,$studip_object,$studip_object_id){
-        $view = new DbView();
-        $view->params = [$item_id,$parent_id,$item_name,$priority,$studip_object,$studip_object_id];
-        $rs = $view->get_query("view:TREE_INS_ITEM");
-        return $rs->affected_rows();
-    }
-
-    function UpdateItem($item_name,$studip_object,$studip_object_id,$item_id){
-        $view = new DbView();
-        $view->params = [$item_name,$studip_object,$studip_object_id,$item_id];
-        $rs = $view->get_query("view:TREE_UPD_ITEM");
-        return $rs->affected_rows();
-    }
-
-    function DeleteItems($items_to_delete){
-        $view = new DbView();
-        $view->params[0] = (is_array($items_to_delete)) ? $items_to_delete : [$items_to_delete];
-        $view->auto_free_params = false;
-        $rs = $view->get_query("view:TREE_DEL_ITEM");
-        $deleted['items'] = $rs->affected_rows();
-        $rs = $view->get_query("view:CAT_DEL_RANGE");
-        $deleted['categories'] = $rs->affected_rows();
-        return $deleted;
-    }
-}
-?>
diff --git a/lib/classes/StudipRangeTreeView.php b/lib/classes/StudipRangeTreeView.php
deleted file mode 100644
index 7b23089..0000000
--- a/lib/classes/StudipRangeTreeView.php
+++ /dev/null
@@ -1,101 +0,0 @@
-<?php
-# Lifter001: TEST
-# Lifter002: TODO
-# Lifter007: TODO
-# Lifter003: TODO
-# Lifter010: TODO
-// +---------------------------------------------------------------------------+
-// This file is part of Stud.IP
-// StudipRangeTreeView.php
-// Class to print out the "range tree"
-//
-// Copyright (c) 2002 André Noack <noack@data-quest.de>
-// Suchi & Berg GmbH <info@data-quest.de>
-// +---------------------------------------------------------------------------+
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or any later version.
-// +---------------------------------------------------------------------------+
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-// +---------------------------------------------------------------------------+
-
-/**
-* class to print out the "range tree"
-*
-* This class prints out a html representation of the whole or part of the tree
-*
-* @access   public
-* @author   André Noack <noack@data-quest.de>
-* @package
-*/
-class StudipRangeTreeView extends TreeView{
-
-    /**
-    * constructor
-    *
-    * @access public
-    */
-    function __construct(){
-        $this->root_content = $GLOBALS['UNI_INFO'];
-        parent::__construct("StudipRangeTree"); //calling the baseclass constructor
-    }
-
-    function getItemContent($item_id){
-        $content = "\n<table width=\"100%\" cellpadding=\"2\" cellspacing=\"2\" align=\"center\" style=\"font-size:10pt\">";
-        if ($item_id == "root"){
-            $content .= "\n<tr><td class=\"table_header_bold\" align=\"left\">" . htmlReady($this->tree->root_name) ." </td></tr>";
-            $content .= "\n<tr><td class=\"blank\" align=\"left\">" . htmlReady($this->root_content) ." </td></tr>";
-            $content .= "\n</table>";
-            return $content;
-        }
-        $range_object = RangeTreeObject::GetInstance($item_id);
-        $name = ($range_object->item_data['type']) ? $range_object->item_data['type'] . ": " : "";
-        $name .= $range_object->item_data['name'];
-        $content .= "\n<tr><td class=\"table_header_bold\" align=\"left\">" . htmlReady($name) ." </td></tr>";
-        if (is_array($range_object->item_data_mapping)){
-            $content .= "\n<tr><td class=\"blank\" align=\"left\">";
-            foreach ($range_object->item_data_mapping as $key => $value){
-                if ($range_object->item_data[$key]){
-                    $content .= "<b>" . htmlReady($value) . ":</b>&nbsp;";
-                    $content .= formatLinks($range_object->item_data[$key]) . "&nbsp; ";
-                }
-            }
-            $content .= "</td></tr><tr><td class=\"blank\" align=\"left\">" .
-                    "<a href=\"".URLHelper::getLink("dispatch.php/institute/overview?auswahl=".$range_object->item_data['studip_object_id'])."\"" .
-                    tooltip(_("Seite dieser Einrichtung in Stud.IP aufrufen")) . ">" .
-                    htmlReady($range_object->item_data['name']) . "</a>&nbsp;" ._("in Stud.IP") ."</td></tr>";
-
-        } elseif (!$range_object->item_data['studip_object']){
-            $content .= "\n<tr><td class=\"blank\" align=\"left\">" .
-                        _("Dieses Element ist keine Stud.IP-Einrichtung, es hat daher keine Grunddaten.") . "</td></tr>";
-        } else {
-            $content .= "\n<tr><td class=\"blank\" align=\"left\">" . _("Keine Grunddaten vorhanden!") . "</td></tr>";
-        }
-        $content .= "\n<tr><td>&nbsp;</td></tr>";
-        $kategorien =& $range_object->getCategories();
-        if ($kategorien->numRows){
-            while($kategorien->nextRow()){
-                $content .= "\n<tr><td class=\"table_header_bold\">" . htmlReady($kategorien->getField("name")) . "</td></tr>";
-                $content .= "\n<tr><td class=\"blank\">" . formatReady($kategorien->getField("content")) . "</td></tr>";
-            }
-        } else {
-            $content .= "\n<tr><td class=\"blank\">" . _("Keine weiteren Daten vorhanden!") . "</td></tr>";
-        }
-        $content .= "</table>";
-        return $content;
-    }
-}
-//test
-//page_open(array("sess" => "Seminar_Session", "auth" => "Seminar_Default_Auth", "perm" => "Seminar_Perm", "user" => "Seminar_User"));
-//include 'lib/include/html_head.inc.php';
-//$test = new StudipRangeTreeView();
-//$test->showTree();
-//echo "</table>";
-//page_close();
diff --git a/lib/classes/StudipRangeTreeViewAdmin.php b/lib/classes/StudipRangeTreeViewAdmin.php
deleted file mode 100644
index 1c5e5a1..0000000
--- a/lib/classes/StudipRangeTreeViewAdmin.php
+++ /dev/null
@@ -1,837 +0,0 @@
-<?php
-# Lifter001: TEST
-# Lifter002: TODO
-# Lifter007: TODO
-# Lifter003: TODO
-# Lifter010: TODO
-// +---------------------------------------------------------------------------+
-// This file is part of Stud.IP
-// StudipRangeTreeViewAdmin.php
-// Class to print out the "range tree"
-//
-// Copyright (c) 2002 André Noack <noack@data-quest.de>
-// Suchi & Berg GmbH <info@data-quest.de>
-// +---------------------------------------------------------------------------+
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or any later version.
-// +---------------------------------------------------------------------------+
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-// +---------------------------------------------------------------------------+
-
-use Studip\Button, Studip\LinkButton;
-
-/**
-* class to print out the admin view of the "range tree"
-*
-* This class prints out a html representation of the whole or part of the tree, <br>
-* it also contains all functions for administrative tasks on the tree
-*
-* @access   public
-* @author   André Noack <noack@data-quest.de>
-* @package
-*/
-class StudipRangeTreeViewAdmin extends TreeView{
-
-
-    var $tree_status;
-
-    var $mode;
-
-    var $edit_item_id;
-
-    var $move_item_id;
-
-    var $search_result;
-
-    var $msg;
-
-    var $marked_item;
-
-    var $edit_cat_snap;
-
-    var $edit_cat_item_id;
-
-    /**
-    * constructor
-    *
-    * calls the base class constructor, registers a session variable, calls the init function and the command parser
-    * @access public
-    */
-    function __construct(){
-
-        $this->root_content = $GLOBALS['UNI_INFO'];
-        parent::__construct("StudipRangeTree"); //calling the baseclass constructor
-        $this->marked_item =& $_SESSION['_marked_item'];
-
-        $this->initTreeStatus();
-        $this->parseCommand();
-    }
-
-    function initTreeStatus()
-    {
-        $view = DbView::getView('range_tree');
-        $user_id = $GLOBALS['auth']->auth['uid'];
-        $user_perm = $GLOBALS['auth']->auth['perm'];
-        $studip_object_status = null;
-
-        if (is_array($this->open_items)){
-            foreach ($this->open_items as $key => $value) {
-                if ($key != 'root') {
-                    $tmp = $this->tree->getAdminRange($key);
-
-                    if(!empty($tmp)) {
-                        foreach($tmp as $i) {
-                            if($i) {
-                                $studip_object_status[$i] = ($user_perm == "root") ? 1 : -1;
-                            }
-                        }
-
-                    }
-                }
-            }
-        }
-
-        if (is_array($this->open_ranges)){
-            foreach ($this->open_ranges as $key => $value) {
-                if ($key != 'root'){
-                    $tmp = $this->tree->getAdminRange($key);
-
-                    if(!empty($tmp)) {
-                        foreach($tmp as $i) {
-                            if($i) {
-                                $studip_object_status[$i] = ($user_perm == "root") ? 1 : -1;
-                            }
-                        }
-                    }
-
-                    if (isset($this->tree->tree_data[$key])) {
-                        $tmp = $this->tree->getAdminRange($this->tree->tree_data[$key]['parent_id']);
-                    } else {
-                        $tmp = [];
-                    }
-
-                    if(!empty($tmp)) {
-                        foreach($tmp as $i) {
-                            if ($i) {
-                                $studip_object_status[$i] = ($user_perm == "root") ? 1 : -1;
-                            }
-                        }
-                    }
-
-                }
-            }
-        }
-        if (is_array($studip_object_status) && $user_perm != 'root'){
-            $view->params = [array_keys($studip_object_status), $user_id];
-            $rs = $view->get_query("view:TREE_INST_STATUS");
-            while ($rs->next_record()){
-                $studip_object_status[$rs->f("Institut_id")] = 1;
-            }
-            $view->params = [array_keys($studip_object_status), $user_id];
-            $rs = $view->get_query("view:TREE_FAK_STATUS");
-            while ($rs->next_record()){
-                $studip_object_status[$rs->f("Fakultaets_id")] = 1;
-                if ($rs->f("Institut_id") && isset($studip_object_status[$rs->f("Institut_id")])){
-                    $studip_object_status[$rs->f("Institut_id")] = 1;
-                }
-            }
-        }
-        $studip_object_status['root'] = ($user_perm == "root") ? 1 : -1;
-    $this->tree_status = $studip_object_status;
-    }
-
-    function parseCommand(){
-        if (Request::quoted('mode'))
-            $this->mode = Request::quoted('mode');
-        if (Request::option('cmd')){
-            $exec_func = "execCommand" . Request::option('cmd');
-            if (method_exists($this,$exec_func)){
-                if ($this->$exec_func()){
-                    $this->tree->init();
-                    $this->initTreeStatus();
-                }
-            }
-        }
-        if ($this->mode == "MoveItem")
-            $this->move_item_id = $this->marked_item;
-    }
-
-    function execCommandOrderItem(){
-        $direction = Request::quoted('direction');
-        $item_id = Request::option('item_id');
-        $items_to_order = $this->tree->getKids($this->tree->tree_data[$item_id]['parent_id']);
-        if (!$this->isParentAdmin($item_id) || !$items_to_order)
-            return false;
-        for ($i = 0; $i < count($items_to_order); ++$i){
-            if ($item_id == $items_to_order[$i])
-                break;
-        }
-        if ($direction == "up" && isset($items_to_order[$i-1])){
-            $items_to_order[$i] = $items_to_order[$i-1];
-            $items_to_order[$i-1] = $item_id;
-        } elseif (isset($items_to_order[$i+1])){
-            $items_to_order[$i] = $items_to_order[$i+1];
-            $items_to_order[$i+1] = $item_id;
-        }
-        $view = DbView::getView('range_tree');
-        for ($i = 0; $i < count($items_to_order); ++$i){
-            $view->params = [$i, $items_to_order[$i]];
-            $rs = $view->get_query("view:TREE_UPD_PRIO");
-        }
-        $this->mode = "";
-        $this->msg[$item_id] = "msg§" . (($direction == "up") ? _("Element wurde um eine Position nach oben verschoben.") : _("Element wurde um eine Position nach unten verschoben."));
-        return true;
-    }
-
-    function execCommandNewItem(){
-        $item_id = Request::option('item_id');
-        if ($this->isItemAdmin($item_id)){
-            $new_item_id = DbView::get_uniqid();
-            $this->tree->storeItem($new_item_id,$item_id,_("Neues Element"), $this->tree->getNumKids($item_id) +1);
-            $this->anchor = $new_item_id;
-            $this->edit_item_id = $new_item_id;
-            $this->open_ranges[$item_id] = true;
-            $this->open_items[$new_item_id] = true;
-            if ($this->mode != "NewItem")
-                $this->msg[$new_item_id] = "info§" . _("Wählen Sie einen Namen für dieses Element, oder verlinken Sie es mit einer Einrichtung in Stud.IP");
-            $this->mode = "NewItem";
-        }
-        return false;
-    }
-
-    function execCommandSearchStudip(){
-        $item_id = Request::option('item_id');
-        $parent_id = Request::quoted('parent_id');
-        $search_str = Request::quoted('edit_search');
-        $view = DbView::getView('range_tree');
-        if(mb_strlen($search_str) > 1){
-            $view->params[0] = $search_str;
-            $rs = $view->get_query("view:TREE_SEARCH_INST");
-            while ($rs->next_record()){
-                $this->search_result[$rs->f("Institut_id")]['name'] = $rs->f("Name");
-                $this->search_result[$rs->f("Institut_id")]['studip_object'] = "inst";
-            }
-            if ($parent_id == "root"){
-                $view->params[0] = $search_str;
-                $rs = $view->get_query("view:TREE_SEARCH_FAK");
-                while ($rs->next_record()){
-                    $this->search_result[$rs->f("Fakultaets_id")]['name'] = $rs->f("Name");
-                    $this->search_result[$rs->f("Fakultaets_id")]['studip_object'] = "fak";
-                }
-            }
-        $search_msg = "info§" . sprintf(_("Ihre Suche ergab %s Treffer."),count($this->search_result));
-        } else {
-            $search_msg = "error§" . _("Sie haben keinen Suchbegriff eingegeben.");
-        }
-        if ($this->mode == "NewItem"){
-            Request::set('item_id', $parent_id);
-            $this->execCommandNewItem();
-        } else {
-            $this->anchor = $item_id;
-            $this->edit_item_id = $item_id;
-        }
-        $this->msg[$this->edit_item_id] = $search_msg;
-        return false;
-    }
-
-    function execCommandEditItem(){
-        $item_id = Request::option('item_id');
-        if ($this->isItemAdmin($item_id) || $this->isParentAdmin($item_id)){
-            $this->mode = "EditItem";
-            $this->anchor = $item_id;
-            $this->edit_item_id = $item_id;
-            $this->msg[$item_id] = "info§" . _("Wählen Sie einen Namen für dieses Element, oder verlinken Sie es mit einer Einrichtung in Stud.IP");
-        }
-        return false;
-    }
-
-    function execCommandInsertItem(){
-        $item_id = Request::option('item_id');
-        $parent_id = Request::option('parent_id');
-        $item_name = Request::quoted('edit_name');
-        $tmp = explode(":",Request::quoted('edit_studip_object'));
-        if ($tmp[1] == "fak" || $tmp[1] == "inst"){
-            $studip_object = $tmp[1];
-            $studip_object_id = $tmp[0];
-        } else {
-            $studip_object = "";
-            $studip_object_id = "";
-        }
-        if ($this->mode == "NewItem" && $item_id){
-            if ($this->isItemAdmin($parent_id)){
-                $priority = count($this->tree->getKids($parent_id));
-                $affected_rows = $this->tree->InsertItem($item_id,$parent_id,$item_name,$priority,$studip_object,$studip_object_id);
-                if ($affected_rows){
-                    $this->mode = "";
-                    $this->anchor = $item_id;
-                    $this->open_items[$item_id] = true;
-                    $this->msg[$item_id] = "msg§" . _("Dieses Element wurde neu eingefügt.");
-                }
-            }
-        }
-        if ($this->mode == "EditItem"){
-            if ($this->isParentAdmin($item_id)){
-                $affected_rows = $this->tree->UpdateItem($item_name,$studip_object,$studip_object_id,$item_id);
-                if ($affected_rows){
-                    $this->msg[$item_id] = "msg§" . _("Element wurde geändert.");
-                } else {
-                    $this->msg[$item_id] = "info§" . _("Keine Veränderungen vorgenommen.");
-                }
-                $this->mode = "";
-                $this->anchor = $item_id;
-                $this->open_items[$item_id] = true;
-            }
-        }
-        return true;
-    }
-
-    function execCommandInsertFak(){
-        $studip_object_id = Request::quoted('insert_fak');
-        $parent_id = 'root';
-        if ($this->isItemAdmin($parent_id)){
-            $item_id = DbView::get_uniqid();
-            $priority = count($this->tree->getKids($parent_id));
-            $affected_rows = $this->tree->InsertItem($item_id,$parent_id,'',$priority,'fak',$studip_object_id);
-            if($affected_rows){
-                $view = DbView::getView('range_tree');
-                $priority = 0;
-                $rs = $view->get_query("SELECT * FROM Institute WHERE fakultaets_id <> Institut_id AND fakultaets_id = '$studip_object_id' ORDER BY Name");
-                while($rs->next_record()){
-                    $affected_rows += $this->tree->InsertItem(DbView::get_uniqid(),$item_id,addslashes($rs->f('name')),$priority++,'inst',$rs->f('Institut_id'));
-                }
-                $this->msg[$item_id] = "msg§" . sprintf(_("%s Elemente wurden eingefügt."), $affected_rows);
-                $this->mode = "";
-                $this->anchor = $item_id;
-                $this->open_items[$item_id] = true;
-                $this->open_ranges[$item_id] = true;
-            }
-        }
-        return true;
-    }
-
-    function execCommandAssertDeleteItem(){
-        $item_id = Request::option('item_id');
-        if ($this->isParentAdmin($item_id)){
-            $this->mode = "AssertDeleteItem";
-            $this->msg[$item_id] = "info§" ._("Sie beabsichtigen dieses Element, inklusive aller Unterelemente, zu löschen. ")
-                        . sprintf(_("Es werden insgesamt %s Elemente gelöscht!"),count($this->tree->getKidsKids($item_id))+1)
-                        . "<br>" . _("Wollen Sie diese Elemente wirklich löschen?") . "<br>"
-                        . '<div class="button-group">'
-                        . LinkButton::createAccept(_("JA"), URLHelper::getURL($this->getSelf("cmd=DeleteItem&item_id=$item_id")))
-                        . LinkButton::createCancel(_("NEIN"), URLHelper::getURL($this->getSelf("cmd=Cancel&item_id=$item_id")))
-                        . "</div>";
-        }
-        return false;
-    }
-
-    function execCommandDeleteItem(){
-        $item_id = Request::option('item_id');
-        $deleted = 0;
-        $item_name = $this->tree->tree_data[$item_id]['name'];
-        if ($this->isParentAdmin($item_id) && $this->mode == "AssertDeleteItem"){
-            $this->anchor = $this->tree->tree_data[$item_id]['parent_id'];
-            $items_to_delete = $this->tree->getKidsKids($item_id);
-            $items_to_delete[] = $item_id;
-            $deleted = $this->tree->DeleteItems($items_to_delete);
-            if ($deleted['items']){
-                $this->msg[$this->anchor] = "msg§" . sprintf(_("Das Element <b>%s</b> und alle Unterelemente (insgesamt %s) wurden gelöscht. "),htmlReady($item_name),$deleted['items']);
-            } else {
-                $this->msg[$this->anchor] = "error§" . _("Fehler, es konnten keine Elemente gelöscht werden!");
-            }
-            if ($deleted['categories']){
-                $this->msg[$this->anchor] .= sprintf(_("<br>Es wurden %s Datenfelder gelöscht. "),$deleted['categories']);
-            }
-            $this->mode = "";
-            $this->open_items[$this->anchor] = true;
-        }
-        return true;
-    }
-
-    function execCommandMoveItem(){
-        $item_id = Request::option('item_id');
-        $this->anchor = $item_id;
-        $this->marked_item = $item_id;
-        $this->mode = "MoveItem";
-        return false;
-    }
-
-    function execCommandDoMoveItem(){
-        $item_id = Request::option('item_id');
-        $item_to_move = $this->marked_item;
-        if ($this->mode == "MoveItem" && ($this->isItemAdmin($item_id) || $this->isParentAdmin($item_id))
-            && ($item_to_move != $item_id) && ($this->tree->tree_data[$item_to_move]['parent_id'] != $item_id)
-            && !$this->tree->isChildOf($item_to_move,$item_id)){
-            $view = DbView::getView('range_tree');
-            $view->params = [$item_id, count($this->tree->getKids($item_id)), $item_to_move];
-            $rs = $view->get_query("view:TREE_MOVE_ITEM");
-            if ($rs->affected_rows()){
-                    $this->msg[$item_to_move] = "msg§" . _("Element wurde verschoben.");
-                } else {
-                    $this->msg[$item_to_move] = "error§" . _("Keine Verschiebung durchgeführt.");
-                }
-            }
-        $this->anchor = $item_to_move;
-        $this->open_ranges[$item_id] = true;
-        $this->open_items[$item_to_move] = true;
-        $this->mode = "";
-        return true;
-    }
-
-    function execCommandOrderCat(){
-        $item_id = Request::option('item_id');
-        $direction = Request::quoted('direction');
-        $cat_id = Request::option('cat_id');
-        $items_to_order = [];
-        if ($this->isItemAdmin($item_id)){
-            $range_object = RangeTreeObject::GetInstance($item_id);
-            $categories =& $range_object->getCategories();
-            while($categories->nextRow()){
-                $items_to_order[] = $categories->getField("kategorie_id");
-            }
-            for ($i = 0; $i < count($items_to_order); ++$i){
-                if ($cat_id == $items_to_order[$i])
-                    break;
-            }
-            if ($direction == "up" && isset($items_to_order[$i-1])){
-                $items_to_order[$i] = $items_to_order[$i-1];
-                $items_to_order[$i-1] = $cat_id;
-            } elseif (isset($items_to_order[$i+1])){
-                $items_to_order[$i] = $items_to_order[$i+1];
-                $items_to_order[$i+1] = $cat_id;
-            }
-            $view = DbView::getView('range_tree');
-            for ($i = 0; $i < count($items_to_order); ++$i){
-                $view->params = [$i,$items_to_order[$i]];
-                $rs = $view->get_query("view:CAT_UPD_PRIO");
-            }
-            $this->msg[$item_id] = "msg§" . _("Datenfelder wurden neu geordnet");
-        }
-        $this->anchor = $item_id;
-        return false;
-    }
-
-    function execCommandNewCat(){
-        $item_id = Request::option('item_id');
-        if ($this->isItemAdmin($item_id)){
-            $range_object = RangeTreeObject::GetInstance($item_id);
-            $this->edit_cat_snap =& $range_object->getCategories();
-            $this->edit_cat_snap->result[$this->edit_cat_snap->numRows] =
-                ["kategorie_id" => "new_entry", "range_id" => $item_id, "name" => "Neues Datenfeld", "content" => "Neues Datenfeld",
-                        "priority" => $this->edit_cat_snap->numRows];
-            ++$this->edit_cat_snap->numRows;
-            $this->edit_cat_item_id = $item_id;
-            $this->mode = "NewCat";
-        }
-        $this->anchor = $item_id;
-        return false;
-    }
-
-    function execCommandUpdateCat(){
-        $item_id = Request::option('item_id');
-        $cat_name = Request::getArray('cat_name');
-        $cat_content = Request::getArray('cat_content');
-        $cat_prio = Request::getArray('cat_prio');
-        $inserted = false;
-        $updated = 0;
-        if ($this->isItemAdmin($item_id)){
-            $view = DbView::getView('range_tree');
-            if (isset($cat_name['new_entry'])){
-                $view->params = [DbView::get_uniqid(),$item_id,$cat_name['new_entry'],$cat_content['new_entry'],$cat_prio['new_entry']];
-                $rs = $view->get_query("view:CAT_INS_ALL");
-                if ($rs->affected_rows()){
-                    $inserted = true;
-                }
-                unset($cat_name['new_entry']);
-            }
-            foreach ($cat_name as $key => $value){
-                $view->params = [$value,$cat_content[$key],$key];
-                $rs = $view->get_query("view:CAT_UPD_CONTENT");
-                if ($rs->affected_rows()){
-                    ++$updated;
-                }
-            }
-            if ($updated){
-                $this->msg[$item_id] = "msg§" . sprintf(_("Es wurden %s Datenfelder aktualisiert."),$updated);
-                if ($inserted) {
-                    $this->msg[$item_id] .= _("Ein neues Datenfeld wurde eingefügt.");
-                }
-            } elseif ($inserted){
-                $this->msg[$item_id] = "msg§" . _("Ein neues Datenfeld wurde eingefügt.");
-            } else {
-                $this->msg[$item_id] = "info§" . _("Keine Veränderungen vorgenommen.");
-            }
-        }
-        $this->anchor = $item_id;
-        $this->mode = "";
-        return false;
-    }
-
-    function execCommandDeleteCat(){
-        $item_id = Request::option('item_id');
-        $cat_id = Request::option('cat_id');
-        if ($this->isItemAdmin($item_id)){
-            $view = DbView::getView('range_tree');
-            $view->params[0] = $cat_id;
-            $rs = $view->get_query("view:CAT_DEL");
-            if ($rs->affected_rows()){
-                $this->msg[$item_id] = "msg§" . _("Ein Datenfeld wurde gelöscht.");
-            }
-        }
-        $this->mode = "";
-        $this->anchor = $item_id;
-        return false;
-    }
-
-
-    function execCommandCancel(){
-        $item_id = Request::option('item_id');
-        $this->mode = "";
-        $this->anchor = $item_id;
-        return false;
-    }
-
-    function isItemAdmin($item_id){
-        $admin_ranges = $this->tree->getAdminRange($item_id);
-        for ($i = 0; $i < count($admin_ranges); ++$i){
-            if (
-                isset($this->tree_status[$admin_ranges[$i]])
-                && $this->tree_status[$admin_ranges[$i]] == 1
-            ) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    function isParentAdmin($item_id){
-        $admin_ranges = $this->tree->getAdminRange($this->tree->tree_data[$item_id]['parent_id']);
-        if (!empty($admin_ranges)) {
-            for ($i = 0; $i < count($admin_ranges); ++$i) {
-                if (
-                    isset($this->tree_status[$admin_ranges[$i]])
-                    && $this->tree_status[$admin_ranges[$i]] == 1
-                ) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    function getItemContent($item_id){
-
-        if ($item_id == $this->edit_item_id )
-            return $this->getEditItemContent();
-        if ($item_id == $this->move_item_id){
-            $this->msg[$item_id] = "info§" . sprintf(_("Dieses Element wurde zum Verschieben markiert. Bitte wählen Sie ein Einfügesymbol %s aus, um das Element zu verschieben."), Icon::create('arr_2right', 'sort', ['title' => "Einfügesymbol"])->asImg(16, ["alt" => "Einfügesymbol"]));
-            }
-        $content = "\n<table width=\"90%\" cellpadding=\"2\" cellspacing=\"2\" align=\"center\" style=\"font-size:10pt\">";
-        $content .= $this->getItemMessage($item_id);
-        $content .= "\n<tr><td>";
-
-        if ($this->isItemAdmin($item_id)){
-            $content .= LinkButton::create(_("Neues Objekt"),
-                URLHelper::getURL($this->getSelf("cmd=NewItem&item_id=$item_id")),
-                ['title' => _("Innerhalb dieser Ebene ein neues Element einfügen")]);
-        }
-
-        if ($this->isParentAdmin($item_id) && $item_id !=$this->start_item_id && $item_id != "root"){
-            $content .= LinkButton::create(_("Bearbeiten"),
-                URLHelper::getURL($this->getSelf("cmd=EditItem&item_id=$item_id")));
-
-            $content .= LinkButton::create(_("Löschen"),
-                URLHelper::getURL($this->getSelf("cmd=AssertDeleteItem&item_id=$item_id")));
-
-            if ($this->move_item_id == $item_id && $this->mode == "MoveItem"){
-                $content .= LinkButton::create(_("Abbrechen"),
-                    URLHelper::getURL($this->getSelf("cmd=Cancel&item_id=$item_id")));
-            } else {
-                $content .= LinkButton::create(_("Verschieben"),
-                    URLHelper::getURL($this->getSelf("cmd=MoveItem&item_id=$item_id")));
-            }
-        }
-
-        $content .= "</td></tr></table>";
-        $content .= "\n<table width=\"90%\" cellpadding=\"2\" cellspacing=\"2\" align=\"center\" style=\"font-size:10pt\">";
-        if ($item_id == "root"){
-            if ($this->isItemAdmin($item_id)){
-                $view = DbView::getView('range_tree');
-                $rs = $view->get_query("SELECT i1.Name,i1.Institut_id,COUNT(i2.Institut_id) as num FROM Institute i1 LEFT JOIN Institute i2 ON i1.Institut_id = i2.fakultaets_id AND i2.fakultaets_id<>i2.Institut_id WHERE i1.fakultaets_id=i1.Institut_id GROUP BY i1.Institut_id ORDER BY Name");
-                $content .= "\n<tr><td>";
-                $content .= "\n<form action=\"" . URLHelper::getLink($this->getSelf("cmd=InsertFak")) . "\" method=\"post\" class=\"default\">"
-                    .  CSRFProtection::tokenTag()
-                    . '<div class="col-1"><label>'
-                    . _("Stud.IP Fakultät einfügen:")
-                    . "\n<select style=\"width:300px;vertical-align:middle;\" name=\"insert_fak\">";
-                while($rs->next_record()){
-                    $content .= "\n<option value=\"" . $rs->f("Institut_id") . "\">" . htmlReady(my_substr($rs->f("Name") . '('.$rs->f('num').')',0,60)) . "</option>";
-                }
-                $content .= "</select>"
-                    . '</label></div><div class="col-1">'
-                    . Button::create(_("Fakultät einfügen"))
-                    ."</div></form>";
-                $content .= " </td></tr>";
-            }
-            $content .= "\n<tr><td class=\"table_header_bold\" align=\"left\">" . htmlReady($this->tree->root_name) ." </td></tr>";
-            $content .= "\n<tr><td class=\"blank\" align=\"left\">" . htmlReady($this->root_content) ." </td></tr>";
-            $content .= "\n</table>";
-            return $content;
-        }
-        $range_object = RangeTreeObject::GetInstance($item_id);
-        $name = !empty($range_object->item_data['type']) ? $range_object->item_data['type'] . ": " : "";
-        $name .= $range_object->item_data['name'];
-        $content .= "\n<tr><td class=\"table_header_bold\" align=\"left\" style=\"font-size:10pt\">" . htmlReady($name) ." </td></tr>";
-        if (is_array($range_object->item_data_mapping)){
-            $content .= "\n<tr><td class=\"blank\" align=\"left\" style=\"font-size:10pt\">";
-            foreach ($range_object->item_data_mapping as $key => $value){
-                if ($range_object->item_data[$key]){
-                    $content .= "<b>" . htmlReady($value) . ":</b>&nbsp;";
-                    $content .= formatLinks($range_object->item_data[$key]) . "&nbsp; ";
-                }
-            }
-            $content .= "&nbsp;";
-        } elseif (!$range_object->item_data['studip_object']){
-            $content .= "\n<tr><td class=\"blank\" align=\"left\" style=\"font-size:10pt\">" .
-                        _("Dieses Element ist keine Stud.IP-Einrichtung, es hat daher keine Grunddaten.");
-        } else {
-            $content .= "\n<tr><td class=\"blank\" align=\"left\" style=\"font-size:10pt\">" . _("Keine Grunddaten vorhanden!");
-        }
-        $content .= "\n<div class=\"blank\" align=\"left\" style=\"font-size:10pt\"><b>" . _("Mitarbeiter:") . "</b> " . $range_object->getNumStaff() . "</b></div>";
-        if ($this->isItemAdmin($item_id) && $range_object->item_data['studip_object']){
-            $content .= "\n<div class=\"blank\">";
-
-            $content .= LinkButton::create(_("Grunddaten in Stud.IP bearbeiten"), "dispatch.php/institute/basicdata/index?admin_inst_id=" . $range_object->item_data['studip_object_id']);
-            $content .= "</div>";
-        }
-
-        $content .= "</td></tr><tr><td>&nbsp;</td></tr>";
-
-        if ($this->mode == "NewCat" && ($this->edit_cat_item_id == $item_id)){
-            $categories =& $this->edit_cat_snap;
-        } else {
-            $categories =& $range_object->getCategories();
-        }
-        if (!$this->isItemAdmin($item_id)){
-            if ($categories->numRows){
-                while($categories->nextRow()){
-                    $content .= "\n<tr><td class=\"table_header_bold\" style=\"font-size:10pt\">" . formatReady($categories->getField("name")) . "</td></tr>";
-                    $content .= "\n<tr><td class=\"blank\" style=\"font-size:10pt\">" . formatReady($categories->getField("content")) . "</td></tr>";
-                }
-            } else {
-                $content .= "\n<tr><td class=\"blank\" style=\"font-size:10pt\">" . _("Keine weiteren Daten vorhanden!") . "</td></tr>";
-            }
-        } else {
-            $content .= "<tr><td class=\"blank\" style=\"font-size:10pt\">" . $this->getEditCatContent($item_id,$categories) . "</td></tr>";
-        }
-        $content .= "</table>";
-        return $content;
-    }
-
-    function getItemHead($item_id){
-        $head = "";
-        if ($this->mode == "MoveItem" && ($this->isItemAdmin($item_id) || $this->isParentAdmin($item_id))
-            && ($this->move_item_id != $item_id) && ($this->tree->tree_data[$this->move_item_id]['parent_id'] != $item_id)
-            && !$this->tree->isChildOf($this->move_item_id,$item_id)){
-            $head .= "<a href=\"" . URLHelper::getLink($this->getSelf("cmd=DoMoveItem&item_id=$item_id")) . "\">"
-            .  Icon::create('arr_2right', 'sort', ['title' => "An dieser Stelle einfügen"])->asImg(16, ["alt" => "An dieser Stelle einfügen"])."</a>&nbsp;";
-        }
-        $head .= parent::getItemHead($item_id);
-        if ($item_id != $this->start_item_id && $this->isParentAdmin($item_id) && $item_id != $this->edit_item_id){
-            $head .= "</td><td nowrap align=\"right\" valign=\"bottom\" class=\"printhead\">";
-            if (!$this->tree->isFirstKid($item_id)){
-                $head .= "<a href=\"". URLHelper::getLink($this->getSelf("cmd=OrderItem&direction=up&item_id=$item_id")) .
-                "\">" . Icon::create('arr_2up', 'sort')->asImg(['class' => 'text-top', 'title' => _("Element nach oben verschieben")]) . " ".
-                "</a>";
-            }
-            if (!$this->tree->isLastKid($item_id)){
-                $head .= "<a href=\"". URLHelper::getLink($this->getSelf("cmd=OrderItem&direction=down&item_id=$item_id")) .
-                "\">" . Icon::create('arr_2down', 'sort')->asImg(['class' => 'text-top', 'title' => _("Element nach unten verschieben")]) . " ".
-                "</a>";
-            }
-            $head .= "&nbsp;";
-        }
-        return $head;
-    }
-
-    function getEditItemContent(){
-        $content = '';
-        ob_start();
-        ?>
-        <div style="margin: 0px 5%">
-            <form name="item_form" method="post" class="default"
-                  action="<?= URLHelper::getLink($this->getSelf("cmd=InsertItem&item_id={$this->edit_item_id}")) ?>">
-                <?= CSRFProtection::tokenTag(); ?>
-
-                <input type="hidden" name="parent_id" value="<?= $this->tree->tree_data[$this->edit_item_id]['parent_id'] ?>">
-
-                <table>
-                    <?= $this->getItemMessage($this->edit_item_id, 2) ?>
-                </table>
-
-                <fieldset>
-                    <legend>
-                        <?= _("Element bearbeiten") ?>
-                    </legend>
-
-                    <label>
-                        <?= _("Name des Elements") ?>
-                        <input type="text" name="edit_name" size="50"
-                               value="<?= htmlReady($this->tree->tree_data[$this->edit_item_id]['name']) ?>">
-                    </label>
-                </fieldset>
-
-                <fieldset>
-                    <legend>
-                        <?= _("Element mit einer Stud.IP-Einrichtung verlinken") ?>
-                    </legend>
-
-                    <label>
-                        <?= _("Stud.IP-Einrichtung:") ?>
-
-                        <select name="edit_studip_object" onChange="document.item_form.edit_name.value=document.item_form.edit_studip_object.options[document.item_form.edit_studip_object.selectedIndex].text;">
-                            <option value="none"
-                                <?= ($this->tree->tree_data[$this->edit_item_id]['studip_object']) ? '' : 'selected' ?>
-                            >
-                                <?= _("Kein Link") ?>
-                            </option>
-                            <? if ($this->tree->tree_data[$this->edit_item_id]['studip_object']) : ?>
-                            <option selected value="<?= $this->tree->tree_data[$this->edit_item_id]['studip_object_id']
-                                .':'. $this->tree->tree_data[$this->edit_item_id]['studip_object'] ?>"
-                            >
-                                <?= htmlReady($this->tree->tree_data[$this->edit_item_id]['name']) ?>
-                            </option>
-                            <? endif ?>
-
-                            <? if (is_array($this->search_result) && count($this->search_result)) : ?>
-                                <? foreach ($this->search_result as $key => $value) : ?>
-                                <option value="<?= $key .':'. $value['studip_object'] ?>">
-                                    <?= $value['name'] ?>
-                                </option>
-                                <? endforeach ?>
-                            <? endif ?>
-                        </select>
-                    </label>
-
-                    <label>
-                        <?= _("Stud.IP-Einrichtung suchen:") ?>
-                        <input type="text" name="edit_search">
-                    </label>
-                </fieldset>
-
-                <footer>
-                    <?= Button::createAccept(_("Absenden")) ?>
-                    <?= Button::create(_("Suchen"), [
-                        'formaction' => URLHelper::getURL($this->getSelf("cmd=SearchStudIP&item_id={$this->edit_item_id}"))
-                    ]);  ?>
-
-                    <?= LinkButton::createCancel(_("Abbrechen"), URLHelper::getURL($this->getSelf("cmd=Cancel&item_id=" . ($this->mode == "NewItem" ? $this->tree->tree_data[$this->edit_item_id]['parent_id'] : $this->edit_item_id)))) ?>
-                </footer>
-            </form>
-        </div>
-
-        <?
-        $content = ob_get_clean();
-        return $content;
-    }
-
-    function getEditCatContent($item_id, $cat_snap)
-    {
-        $content = '';
-        ob_start();
-        ?>
-        <form name="cat_form_<?= $item_id ?>" method="post" class="default"
-              action="<?= URLHelper::getLink($this->getSelf("cmd=UpdateCat&item_id=$item_id"))  ?>">
-            <?= CSRFProtection::tokenTag(); ?>
-
-            <? if ($cat_snap->numRows) while ($cat_snap->nextRow()) :  ?>
-                <fieldset>
-                    <legend>
-                        <!-- change position icons -->
-                        <? if ($cat_snap->pos && $cat_snap->getField("kategorie_id") != "new_entry") : ?>
-                            <a href="<?= URLHelper::getLink($this->getSelf("cmd=OrderCat&direction=up&item_id=$item_id&cat_id=" . $cat_snap->getField("kategorie_id"))) ?>">
-                                <?= Icon::create('arr_2up', 'sort')->asImg(['class' => 'text-top', 'title' => _("Datenfeld nach oben")]) ?>
-                            </a>
-                        <? endif ?>
-
-                        <? if ($cat_snap->pos != $cat_snap->numRows-1 && $cat_snap->getField("kategorie_id") != "new_entry") : ?>
-                            <a href="<?= URLHelper::getLink($this->getSelf("cmd=OrderCat&direction=down&item_id=$item_id&cat_id=" . $cat_snap->getField("kategorie_id"))) ?>">
-                                <?= Icon::create('arr_2down', 'sort')->asImg(['class' => 'text-top', 'title' => _("Datenfeld nach unten")]) ?>
-                            </a>
-                        <? endif ?>
-
-                        <?= _('Datenfeld bearbeiten') ?>
-
-                        <a href="<?= URLHelper::getURL($this->getSelf("cmd=DeleteCat&item_id=$item_id&cat_id=" . $cat_snap->getField("kategorie_id"))) ?>">
-                            <?= Icon::create('trash', 'clickable')->asImg(['class' => 'text-top', 'title' => _("Datenfeld löschen")]) ?>
-                        </a>
-                    </legend>
-
-                    <label>
-                        <?= _('Titel') ?>
-                        <input type="text" name="cat_name[<?= $cat_snap->getField("kategorie_id") ?>]"
-                               value="<?= htmlReady($cat_snap->getField("name")) ?>">
-                        <input type="hidden" name="cat_prio[<?= $cat_snap->getField("kategorie_id") ?>]"
-                               value="<?= htmlReady($cat_snap->getField("priority")) ?>">
-                    </label>
-
-                    <label>
-                        <?= _('Inhalt') ?>
-                        <textarea name="cat_content[<?= htmlReady($cat_snap->getField("kategorie_id")) ?>]"><?= htmlReady($cat_snap->getField("content")) ?></textarea>
-                    </label>
-                </fieldset>
-            <? endwhile ?>
-
-            <footer>
-                <? if ($cat_snap->numRows) : ?>
-                <?= Button::create(_("Datenfelder speichern"), 'übernehmen') ?>
-                <? endif ?>
-                <?= LinkButton::create(_("Neues Datenfeld anlegen"), URLHelper::getURL($this->getSelf("cmd=NewCat&item_id=$item_id"))) ?>
-            </footer>
-        </form>
-
-        <? $content = ob_get_clean() . '</td></tr>';
-
-        return $content;
-    }
-
-    function getItemMessage($item_id, $colspan = 1)
-    {
-        $content = "";
-        if (!empty($this->msg[$item_id])) {
-            $msg = explode("§", $this->msg[$item_id]);
-            $pics = [
-                'error' => Icon::create('decline', 'attention'),
-                'info'  => Icon::create('exclaim', 'inactive'),
-                'msg'   => Icon::create('accept', 'accept')];
-            $content = "\n<tr><td colspan=\"{$colspan}\"><table border=\"0\" cellspacing=\"0\" cellpadding=\"2\" width=\"100%\" style=\"font-size:10pt\">
-                        <tr><td class=\"blank\" align=\"center\" width=\"25\">" .  $pics[$msg[0]]->asImg(['class' => 'text-top']) . "</td>
-                        <td class=\"blank\" align=\"left\">" . $msg[1] . "</td></tr>
-                        </table></td></tr><tr>";
-        }
-        return $content;
-    }
-
-    function getSelf($param = ''){
-        $url_params = "foo=" . DbView::get_uniqid();
-        if ($this->mode) $url_params .= "&mode=" . $this->mode;
-        if ($param) $url_params .= '&' . $param;
-        return parent::getSelf($url_params);
-    }
-}
-
-//test
-//page_open(array("sess" => "Seminar_Session", "auth" => "Seminar_Auth", "perm" => "Seminar_Perm", "user" => "Seminar_User"));
-//include 'lib/include/html_head.inc.php';
-//$test = new StudipRangeTreeViewAdmin();
-//$test->showTree();
-//echo "</table>";
-//page_close();
-?>
diff --git a/lib/classes/StudipSemRangeTreeViewSimple.php b/lib/classes/StudipSemRangeTreeViewSimple.php
deleted file mode 100644
index 78b5ccf..0000000
--- a/lib/classes/StudipSemRangeTreeViewSimple.php
+++ /dev/null
@@ -1,247 +0,0 @@
-<?php
-# Lifter001: TEST
-# Lifter002: TODO
-# Lifter007: TODO
-# Lifter003: TODO
-# Lifter010: TODO
-// +---------------------------------------------------------------------------+
-// This file is part of Stud.IP
-// StudipSemRangeTreeViewSimple.php
-// Class to print out the seminar tree
-//
-// Copyright (c) 2003 André Noack <noack@data-quest.de>
-// Suchi & Berg GmbH <info@data-quest.de>
-// +---------------------------------------------------------------------------+
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or any later version.
-// +---------------------------------------------------------------------------+
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-// +---------------------------------------------------------------------------+
-
-
-/**
-* class to print out the range tree
-*
-* This class prints out a html representation a part of the tree
-*
-* @access   public
-* @author   André Noack <noack@data-quest.de>
-* @package
-*/
-class StudipSemRangeTreeViewSimple {
-
-
-    var $tree;
-    var $show_entries;
-    var $start_item_id;
-    var $root_content;
-
-    /**
-    * constructor
-    *
-    * @access public
-    */
-    function __construct($start_item_id = "root", $sem_number = false, $sem_status = false, $visible_only = false){
-        $this->start_item_id = ($start_item_id) ? $start_item_id : "root";
-        $this->root_content = $GLOBALS['UNI_INFO'];
-        $args = null;
-        if ($sem_number !== false){
-            $args['sem_number'] = $sem_number;
-        }
-        if ($sem_status !== false){
-            $args['sem_status'] =  $sem_status;
-        }
-        $args['visible_only'] = $visible_only;
-        $this->tree = TreeAbstract::GetInstance("StudipRangeTree",$args);
-        if (empty($this->tree->tree_data[$this->start_item_id])) {
-            $this->start_item_id = "root";
-        }
-    }
-
-    public function showSemRangeTree($start_id = null)
-    {
-        echo '
-            <table class="show-tree">
-                <tr>
-                    <td style="text-align:left; vertical-align:top; font-size:10pt; padding-bottom: 10px;">
-                        <div style="font-size:10pt; margin-left:0px;display: inline-flex;">
-                            <div class="sem-root-icon"><a href="' .URLHelper::getLink($this->getSelf('start_item_id=root', false)). "\">" .
-                            Icon::create('institute', 'clickable')->asImg(29,['role'=>'root-icon'])
-                            .'</a></div>
-                            <div class="sem-path">'.
-                                '<div class="sem-path-dir">'.
-                                    $this->getSemPath($start_id);
-                        echo '</div>
-                                <div class="sem_path_info">
-                                    <div class="sem_path_title">'.
-                                    formatReady($this->tree->getValue($this->start_item_id, 'name')).
-                                    '</div>
-                                    <div class="sem_path_text">' .
-
-                                    formatReady($this->getTooltip($this->start_item_id)) .
-                                    '</div>
-                                </div>';
-                    echo'</div>
-                        </div>
-                    </td>
-                    <td nowrap style="text-align:right; vertical-align:top; padding-top: 1em;">';
-        if ($this->start_item_id != 'root') {
-            echo '
-                <a href="' .
-                    URLHelper::getLink($this->getSelf('start_item_id=' . $this->tree->tree_data[$this->start_item_id]['parent_id'], false)) .
-                    '">' .
-                    Icon::create('arr_2left', 'clickable')->asImg(['class' => 'text-top', 'title' =>_('eine Ebene zurück')]) .
-                '</a>';
-        } else {
-            echo '&nbsp;';
-        }
-        echo '
-                    </td>
-                </tr>
-                <tr>
-                    <td colspan="2" style="text-align:center;" class="b-top-va-center">';
-        $this->showKids($this->start_item_id);
-        echo '
-                    </td>
-                </tr>
-                <tr>
-                    <td colspan="2" style="text-align:left;" class="b-top-va-center">';
-        $this->showContent($this->start_item_id);
-        echo '
-                    </td>
-                </tr>
-            </table>';
-    }
-
-    function showKids($item_id){
-        $num_kids = $this->tree->getNumKids($item_id);
-        $kids = $this->tree->getKids($item_id);
-        $kids_table = '
-          <table class="show-tree-kids">
-            <tr>
-                <td class="table_row_even kids-tree-row" align="left" valign="top">
-                    <ul class="semtree">';
-        for ($i = 0; $i < $num_kids; ++$i){
-            $num_entries = $this->tree->getNumEntries($kids[$i],true);
-            $kids_table .=  "<li><a " . tooltip(sprintf(_("%s Einträge in allen Unterebenen vorhanden"), $num_entries)) . " href=\"" .URLHelper::getLink($this->getSelf("start_item_id={$kids[$i]}", false)) . "\">";
-            $kids_table .=  htmlReady($this->tree->tree_data[$kids[$i]]['name']);
-            $kids_table .=  " ($num_entries)";
-            $kids_table .=  "</a></li>";
-            if ($i == ceil($num_kids / 2)-1){
-                $kids_table .= '
-                    </ul>
-                </td>
-                <td class="table_row_even kids-tree-row" align="left" valign="top">
-                    <ul class="semtree">';
-            }
-        }
-        if (!$num_kids){
-            $kids_table .=  "<li>";
-            $kids_table .=  _("Auf dieser Ebene existieren keine weiteren Unterebenen.");
-            $kids_table .=  "</li>";
-        }
-        $kids_table .=  "</ul></td></tr></table>";
-        echo $kids_table;
-    }
-
-    function getTooltip($item_id){
-        if ($item_id == "root"){
-            $ret = ($this->root_content) ? $this->root_content : _("Keine weitere Info vorhanden");
-        } else {
-            $info = '';
-            $range_object = RangeTreeObject::GetInstance($item_id);
-            if (is_array($range_object->item_data_mapping)){
-                foreach ($range_object->item_data_mapping as $key => $value){
-                    if ($range_object->item_data[$key]){
-                        $info .= $value . ": ";
-                        $info .= $range_object->item_data[$key].  " ";
-                    }
-                }
-            }
-            $ret = $info ?:  _("Keine weitere Info vorhanden");
-        }
-        return $ret;
-    }
-
-    public function getInfoIcon($item_id)
-    {
-        if ($item_id === 'root') {
-            $info = $this->root_content;
-        }
-        $ret = $info ? tooltipicon(kill_format($info)) : '';
-        return $ret;
-    }
-
-    function showContent($item_id){
-        echo "\n<div align=\"left\" style=\"margin-top:10px;margin-bottom:10px;font-size:10pt\">";
-        if ($item_id != "root"){
-
-            if ($num_entries = $this->tree->getNumEntries($item_id)){
-                if ($this->show_entries != "level"){
-                    echo "<a " . tooltip(_("alle Einträge auf dieser Ebene anzeigen")) ." href=\"" . URLHelper::getLink($this->getSelf("cmd=show_sem_range_tree&item_id=$item_id")) ."\">";
-                }
-                printf(_("<b>%s</b> Einträge auf dieser Ebene.&nbsp;"),$num_entries);
-                if ($this->show_entries != "level"){
-                    echo "</a>";
-                }
-            } else {
-                    echo _("Keine Einträge auf dieser Ebene vorhanden!");
-            }
-            if ($this->tree->hasKids($item_id) && ($num_entries = $this->tree->getNumEntries($this->start_item_id,true))){
-                echo "&nbsp;&nbsp;&sol;&nbsp;&nbsp;";
-                if ($this->show_entries != "sublevels"){
-                    echo "<a " . tooltip(_("alle Einträge in allen Unterebenen anzeigen")) ." href=\"" . URLHelper::getLink($this->getSelf("cmd=show_sem_range_tree&item_id={$this->start_item_id}_withkids")) ."\">";
-                }
-                printf(_("<b>%s</b> Einträge in allen Unterebenen vorhanden"), $num_entries);
-                if ($this->show_entries != "sublevels"){
-                    echo "</a>";
-                }
-            }
-        }
-        echo "\n</div>";
-    }
-
-    public function getSemPath($start_id = null)
-    {
-        $parents = $this->tree->getParents($this->start_item_id);
-        $ret = '';
-        if ($parents) {
-            $add_item = false;
-            $start_id = $start_id === null ? 'root' : $start_id;
-            for($i = count($parents) - 1; $i >= 0; --$i) {
-                if ($add_item || $start_id == $parents[$i]) {
-                    $ret .= ($add_item === TRUE ? '&nbsp;&sol;&nbsp;' : '')
-                            . '<a href="'
-                            . URLHelper::getLink($this->getSelf('start_item_id=' . $parents[$i], false))
-                            . '">'
-                            .  htmlReady($this->tree->tree_data[$parents[$i]]['name'])
-                            . '</a>';
-                    $add_item = true;
-                }
-            }
-        }
-        if ($this->start_item_id == 'root') {
-            $ret = '<a href="' . URLHelper::getLink($this->getSelf('start_item_id=root', false)) . '">' . $this->tree->root_name . '</a>';
-        } else {
-            $ret .= '&nbsp;&sol;&nbsp;<a href="' . URLHelper::getLink($this->getSelf('start_item_id=' . $this->start_item_id, false)). '">'. htmlReady($this->tree->tree_data[$this->start_item_id]['name']). '</a>';
-            $ret .= '&nbsp;&sol;&nbsp;&nbsp;';
-        }
-        return $ret;
-    }
-
-
-
-    function getSelf($param = '', $with_start_item = true){
-        $url_params = (($with_start_item) ? 'start_item_id=' . $this->start_item_id . '&' : '') . $param ;
-        return '?' . $url_params;
-    }
-}
-?>
diff --git a/lib/classes/StudipSemSearch.php b/lib/classes/StudipSemSearch.php
deleted file mode 100644
index 6d86b44..0000000
--- a/lib/classes/StudipSemSearch.php
+++ /dev/null
@@ -1,191 +0,0 @@
-<?php
-# Lifter002: TODO
-# Lifter007: TODO
-# Lifter003: TODO
-# Lifter010: TODO
-// +---------------------------------------------------------------------------+
-// This file is part of Stud.IP
-// StudipSemSearchForm.php
-// Class to build search formular and execute search
-//
-// Copyright (c) 2003 André Noack <noack@data-quest.de>
-// +---------------------------------------------------------------------------+
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or any later version.
-// +---------------------------------------------------------------------------+
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-// +---------------------------------------------------------------------------+
-
-/**
-* Class to build search formular and execute search
-*
-*
-*
-* @access   public
-* @author   André Noack <noack@data-quest.de>
-* @package  DBTools
-**/
-class StudipSemSearch {
-
-    var $form;
-    var $search_result;
-    var $form_name;
-    var $sem_tree;
-    var $range_tree;
-    var $search_done = false;
-    var $found_rows = false;
-    var $search_button_clicked = false;
-    var $new_search_button_clicked = false;
-    var $sem_change_button_clicked = false;
-    var $override_sem = false;
-    var $attributes_default = ['style' => 'width:100%;'];
-    var $search_scopes = [];
-    var $search_ranges = [];
-    var $search_sem_class = 'all';
-    var $visible_only = false;
-    var $sem_dates;
-
-    function __construct($form_name = "search_sem", $auto_search = true, $visible_only = false, $sem_class = 'all'){
-
-        $search_fields = ['title' => ['type' => 'text'],
-                                'sub_title' => ['type' => 'text'],
-                                'number' => ['type' => 'text'],
-                                'comment' => ['type' => 'text'],
-                                'lecturer' => ['type' => 'text'],
-                                'scope' => ['type' => 'text'],
-                                'quick_search' => ['type' => 'text'],
-                                'type' => ['type' => 'select', 'default_value' => 'all', 'max_length' => 35,'options_callback' => [$this, 'getSelectOptions']],
-                                'sem' => ['type' => 'select', 'default_value' => 'all','options_callback' => [$this, 'getSelectOptions']],
-                                'category' => ['type' => 'select', 'default_value' => 'all', 'max_length' => 50,'options_callback' => [$this, 'getSelectOptions']],
-                                'combination' => ['type' => 'select', 'default_value' => 'AND','options_callback' => [$this, 'getSelectOptions']],
-                                'scope_choose' => ['type' => 'select', 'default_value' => 'root', 'max_length' => 45,'options_callback' => [$this, 'getSelectOptions']],
-                                'range_choose' => ['type' => 'select', 'default_value' => 'root', 'max_length' => 45,'options_callback' => [$this, 'getSelectOptions']],
-                                'qs_choose' => ['type' => 'select',
-                                                    'default_value' => 'title_lecturer_number',
-                                                    'options_callback' => [$this, 'getSelectOptions']
-                                                    ]
-                                ];
-        $search_buttons = ['do_search' => ['caption' => _("Suchen"), 'info' => _("Suche starten")],
-                                'sem_change' => ['caption' => _('Auswählen'), 'info' => _("anderes Semester auswählen")],
-                                'new_search' => ['caption' => _('Neue Suche'), 'info' =>_("Neue Suche starten")]];
-        //workaround: Qicksearch ändert den Namen des Eingabefeldes
-        if (Request::get("search_sem_quick_search_parameter")) {
-            Request::set('search_sem_quick_search', Request::get("search_sem_quick_search_parameter"));
-        }
-        $this->form = new StudipForm($search_fields, $search_buttons, $form_name , false);
-        $this->form_name = $form_name;
-        $this->sem_dates = Semester::findAllVisible();
-        $this->visible_only = $visible_only;
-        $this->search_sem_class = $sem_class;
-
-        if($this->form->isClicked('do_search') || ($this->form->isSended() && (!$this->form->isClicked('sem_change') || mb_strlen($this->form->getFormFieldValue('quick_search')) > 2))){
-            $this->search_button_clicked = true;
-            if ($auto_search){
-                $this->doSearch();
-                $this->search_done = true;
-            }
-        }
-
-        $this->new_search_button_clicked = $this->form->isClicked('new_search');
-        $this->sem_change_button_clicked = $this->form->isClicked('do_search');
-
-    }
-
-    function getSearchField($name,$attributes = false,$default = false){
-        if (!$attributes){
-            $attributes = $this->attributes_default;
-        }
-        return $this->form->getFormField($name,$attributes,$default);
-    }
-
-    function getSelectOptions($caller, $name){
-        $options = [];
-        if ($name == "combination"){
-            $options = [['name' =>_("UND"),'value' => 'AND'],['name' => _("ODER"), 'value' => 'OR']];
-        } elseif ($name == "sem"){
-            $options = [['name' =>_("alle"),'value' => 'all']];
-            for ($i = count($this->sem_dates) -1 ; $i >= 0; --$i){
-                $options[] = ['name' => $this->sem_dates[$i]['name'], 'value' => $i];
-            }
-        } elseif ($name == "type"){
-            $options = [['name' =>_("alle"),'value' => 'all']];
-            foreach($GLOBALS['SEM_TYPE'] as $type_key => $type_value){
-                if($this->search_sem_class == 'all' || $type_value['class'] == $this->search_sem_class){
-                    $options[] = ['name' => $type_value['name'] . " (". $GLOBALS['SEM_CLASS'][$type_value['class']]['name'] .")",
-                                        'value' => $type_key];
-                }
-            }
-        } elseif ($name == "category"){
-            $options = [['name' =>_("alle"),'value' => 'all']];
-            foreach($GLOBALS['SEM_CLASS'] as $class_key => $class_value){
-                $options[] = ['name' => $class_value['name'],
-                                        'value' => $class_key];
-                }
-        } elseif ($name == "scope_choose"){
-            if(!is_object($this->sem_tree)){
-                $this->sem_tree = TreeAbstract::GetInstance("StudipSemTree", false);
-            }
-            $options = [['name' => $this->sem_tree->root_name, 'value' => 'root']];
-            for($i = 0; $i < count($this->search_scopes); ++$i){
-                $options[] = ['name' => $this->sem_tree->tree_data[$this->search_scopes[$i]]['name'], 'value' => $this->search_scopes[$i]];
-            }
-        } elseif ($name == "range_choose"){
-            if(!is_object($this->range_tree)){
-                $this->range_tree = TreeAbstract::GetInstance("StudipRangeTree", false);
-            }
-            $options = [['name' => $this->range_tree->root_name, 'value' => 'root']];
-            for($i = 0; $i < count($this->search_ranges); ++$i){
-                $options[] = ['name' => $this->range_tree->tree_data[$this->search_ranges[$i]]['name'], 'value' => $this->search_ranges[$i]];
-            }
-        } elseif ($name == "qs_choose"){
-            foreach(StudipSemSearchHelper::GetQuickSearchFields() as $key => $value){
-                $options[] = ['name' => $value, 'value' => $key];
-            }
-        }
-        return $options;
-    }
-
-    function getFormStart($action = "", $attributes = [])
-    {
-        return $this->form->getFormStart($action, $attributes);
-    }
-
-    function getFormEnd()
-    {
-        $ret = '';
-        if ($this->search_sem_class != 'all'){
-            $ret = $this->form->getHiddenField('category',$this->search_sem_class);
-        }
-        return $ret . $this->form->getFormEnd();
-    }
-
-    function getHiddenField($name, $value = false){
-        return  $this->form->getHiddenField($name, $value);
-    }
-
-    function getSearchButton($attributes = false, $tooltip = false){
-        return $this->form->getFormButton('do_search', $attributes);
-    }
-    function getNewSearchButton($attributes = false, $tooltip = false){
-        return $this->form->getFormButton('new_search', $attributes);
-    }
-    function getSemChangeButton($attributes = false, $tooltip = false){
-        return $this->form->getFormButton('sem_change', $attributes);
-    }
-
-    function doSearch(){
-        $search_helper = new StudipSemSearchHelper($this->form, $this->visible_only);
-        $this->found_rows = $search_helper->doSearch();
-        $this->search_result = $search_helper->getSearchResultAsSnapshot();
-        return $this->found_rows;
-    }
-}
-?>
diff --git a/lib/classes/StudipSemSearchHelper.php b/lib/classes/StudipSemSearchHelper.php
index d221869..821a039 100644
--- a/lib/classes/StudipSemSearchHelper.php
+++ b/lib/classes/StudipSemSearchHelper.php
@@ -111,12 +111,23 @@ class StudipSemSearchHelper {
         $view->params = [];
 
         if ($this->params['scope_choose'] && $this->params['scope_choose'] != 'root'){
-            $sem_tree = TreeAbstract::GetInstance("StudipSemTree", false);
-            $view->params[0] = $sem_types ?: $sem_tree->sem_status;
-            $view->params[1] = $this->visible_only ? "c.visible=1" : "1";
+            $tree_node = StudipStudyArea::find($this->params['scope_choose']);
+            $sem_tree_ids = [];
+            if ($tree_node) {
+                $all_children = $tree_node->getAllChildNodes();
+                foreach ($all_children as $child) {
+                    $sem_tree_ids[] = $child->id;
+                }
+                $sem_tree_ids[] = $tree_node->id;
+            }
 
-            $view->params[2] = $sem_tree->getKidsKids($this->params['scope_choose']);
-            $view->params[2][] = $this->params['scope_choose'];
+            $all_sem_type_ids = [];
+            foreach (SemType::getTypes() as $sem_type) {
+                $all_sem_type_ids[] = $sem_type->id;
+            }
+            $view->params[0] = $sem_types ?: $all_sem_type_ids;
+            $view->params[1] = $this->visible_only ? "c.visible=1" : "1";
+            $view->params[2] = $sem_tree_ids;
             $view->params[3] = $clause;
             $snap = new DbSnapshot($view->get_query("view:SEM_TREE_GET_SEMIDS"));
             if ($snap->numRows){
@@ -128,9 +139,17 @@ class StudipSemSearchHelper {
         }
 
         if ($this->params['range_choose'] && $this->params['range_choose'] != 'root'){
-            $range_object = RangeTreeObject::GetInstance($this->params['range_choose']);
-            $view->params[0] = $range_object->getAllObjectKids();
-            $view->params[0][] = $range_object->item_data['studip_object_id'];
+            $range_node = RangeTreeNode::find($this->params['range_choose']);
+            $range_ids = [];
+            if ($range_node) {
+                $children = $range_node->getChildNodes();
+                foreach ($children as $child) {
+                    $range_ids[] = $child->studip_object_id;
+                }
+                $range_ids[] = $range_node->studip_object_id;
+            }
+
+            $view->params[0] = $range_ids;
             $view->params[1] = ($this->visible_only ? " AND c.visible=1 " : "");
             $view->params[2] = $clause;
             $snap = new DbSnapshot($view->get_query("view:SEM_INST_GET_SEM"));
@@ -218,10 +237,6 @@ class StudipSemSearchHelper {
         return $this->found_rows;
     }
 
-    public function getSearchResultAsSnapshot(){
-        return $this->search_result;
-    }
-
     public function getSearchResultAsArray(){
         if($this->search_result instanceof DBSnapshot && $this->search_result->numRows){
             return array_unique($this->search_result->getRows('seminar_id'));
diff --git a/lib/classes/StudipSemTree.php b/lib/classes/StudipSemTree.php
deleted file mode 100644
index 70743ad..0000000
--- a/lib/classes/StudipSemTree.php
+++ /dev/null
@@ -1,312 +0,0 @@
-<?php
-# Lifter007: TODO
-# Lifter003: TODO
-
-/**
- * class to handle the seminar tree
- *
- * This class provides an interface to the structure of the seminar tree
- *
- * @access    public
- * @author    André Noack <noack@data-quest.de>
- * @license   GPL2 or any later version
- * @copyright 2003 André Noack <noack@data-quest.de>,
- *                 Suchi & Berg GmbH <info@data-quest.de>
- */
-class StudipSemTree extends TreeAbstract
-{
-    public $sem_dates = [];
-    public $sem_number = null;
-    public $visible_only = false;
-    public $sem_status = [];
-    protected $entries_init_done = false;
-
-    /**
-    * constructor
-    *
-    * do not use directly, call TreeAbstract::GetInstance("StudipRangeTree")
-    * @access private
-    */
-    public function __construct($args)
-    {
-        DbView::addView('sem_tree');
-
-        $this->root_name = Config::get()->UNI_NAME_CLEAN;
-        if (isset($args['visible_only'])) {
-            $this->visible_only = (int) $args['visible_only'];
-        }
-        if (isset($args['sem_number']) ){
-            $this->sem_number = array_map('intval', $args['sem_number']);
-        }
-        if (!empty($args['sem_status'])) {
-            $this->sem_status = array_map('intval', $args['sem_status']);
-        } else {
-            foreach ($GLOBALS['SEM_CLASS'] as $key => $value){
-                if ($value['bereiche']){
-                    foreach ($GLOBALS['SEM_TYPE'] as $type_key => $type_value) {
-                        if($type_value['class'] == $key)
-                            $this->sem_status[] = $type_key;
-                    }
-                }
-            }
-        }
-
-        if (!count($this->sem_status)){
-            $this->sem_status[] = -1;
-        }
-
-        parent::__construct(); //calling the baseclass constructor
-        if (isset($args['build_index']) ){
-            $this->buildIndex();
-        }
-
-        $this->sem_dates = Semester::findAllVisible();
-    }
-
-    /**
-    * initializes the tree
-    *
-    * stores all rows from table sem_tree in array $tree_data
-    * @access public
-    */
-    public function init()
-    {
-        parent::init();
-
-        $db = $this->view->get_query("view:SEM_TREE_GET_DATA_NO_ENTRIES");
-
-        while ($db->next_record()){
-            $this->tree_data[$db->f("sem_tree_id")] = ['type' => $db->f('type'), "info" => $db->f("info"), "entries" => 0];
-            $name = $db->f("name");
-            $this->storeItem($db->f("sem_tree_id"), $db->f("parent_id"), $name, $db->f("priority"));
-        }
-    }
-
-    public function initEntries()
-    {
-        $this->view->params[0] = $this->sem_status;
-        $this->view->params[1] = $this->visible_only ? "visible=1" : "1";
-        $this->view->params[1] .= (isset($this->sem_number)) ? " AND ((" . $this->view->sem_number_sql
-                                . ") IN (" . join(",",$this->sem_number) .") OR ((" . $this->view->sem_number_sql
-                                .") <= " . $this->sem_number[count($this->sem_number)-1]
-                                . "  AND ((" . $this->view->sem_number_end_sql . ") >= " . $this->sem_number[count($this->sem_number)-1]
-                                . " OR (" . $this->view->sem_number_end_sql . ") = -1))) " : "";
-
-        $db = $this->view->get_query("view:SEM_TREE_GET_ENTRIES");
-        while ($db->next_record()){
-            $this->tree_data[$db->f("sem_tree_id")]['entries'] = $db->f('entries');
-        }
-        $this->entries_init_done = true;
-    }
-
-    public function isModuleItem($item_id)
-    {
-        return isset($GLOBALS['SEM_TREE_TYPES'][$this->getValue($item_id, 'type')]['is_module']);
-    }
-
-    public function isHiddenItem($item_id)
-    {
-        return !empty($GLOBALS['SEM_TREE_TYPES'][$this->getValue($item_id, 'type')]['hidden']);
-    }
-
-    public function getSemIds($item_id,$ids_from_kids = false)
-    {
-        if (empty($this->tree_data[$item_id])) {
-            return false;
-        }
-        $this->view->params[0] = $this->sem_status;
-        $this->view->params[1] = $this->visible_only ? "visible=1" : "1";
-        if ($ids_from_kids && $item_id != 'root'){
-            $this->view->params[2] = $this->getKidsKids($item_id);
-        }
-        $this->view->params[2][] = $item_id;
-        $this->view->params[3] = (isset($this->sem_number)) ? " HAVING sem_number IN (" . join(",",$this->sem_number) .") OR (sem_number <= " . $this->sem_number[count($this->sem_number)-1] . "  AND (sem_number_end >= " . $this->sem_number[count($this->sem_number)-1] . " OR sem_number_end = -1)) " : "";
-        $ret = false;
-        if ($item_id == 'root' && $ids_from_kids) {
-            unset($this->view->params[2]);
-            $this->view->params = array_values($this->view->params);
-            $rs = $this->view->get_query("view:SEM_TREE_GET_SEMIDS_ROOT");
-        } else {
-            $rs = $this->view->get_query("view:SEM_TREE_GET_SEMIDS");
-        }
-        while($rs->next_record()){
-            $ret[] = $rs->f(0);
-        }
-        return $ret;
-    }
-
-    public function getSemData($item_id,$sem_data_from_kids = false)
-    {
-        if (!$this->tree_data[$item_id])
-            return false;
-        $this->view->params[0] = $this->sem_status;
-        $this->view->params[1] = $this->visible_only ? "visible=1" : "1";
-        if ($sem_data_from_kids && $item_id != 'root'){
-            $this->view->params[2] = $this->getKidsKids($item_id);
-        }
-        $this->view->params[2][] = $item_id;
-        $this->view->params[3] = (isset($this->sem_number)) ? " HAVING sem_number IN (" . join(",",$this->sem_number) .") OR (sem_number <= " . $this->sem_number[count($this->sem_number)-1] . "  AND (sem_number_end >= " . $this->sem_number[count($this->sem_number)-1] . " OR sem_number_end = -1)) " : "";
-        if ($item_id == 'root' && $sem_data_from_kids) {
-            unset($this->view->params[2]);
-            $this->view->params = array_values($this->view->params);
-            $rs = $this->view->get_query("view:SEM_TREE_GET_SEMDATA_ROOT");
-        } else {
-            $rs = $this->view->get_query("view:SEM_TREE_GET_SEMDATA");
-        }
-        return new DbSnapshot($rs);
-    }
-
-    public function getLonelySemData($item_id)
-    {
-        if (!$institut_id = $this->tree_data[$item_id]['studip_object_id'])
-            return false;
-        $this->view->params[0] = $this->sem_status;
-        $this->view->params[1] = $this->visible_only ? "visible=1" : "1";
-        $this->view->params[2] = $institut_id;
-        $this->view->params[3] = (isset($this->sem_number)) ? " HAVING sem_number IN (" . join(",",$this->sem_number) .") OR (sem_number <= " . $this->sem_number[count($this->sem_number)-1] . "  AND (sem_number_end >= " . $this->sem_number[count($this->sem_number)-1] . " OR sem_number_end = -1)) " : "";
-        return new DbSnapshot($this->view->get_query("view:SEM_TREE_GET_LONELY_SEM_DATA"));
-    }
-
-    public function getNumEntries($item_id, $num_entries_from_kids = false)
-    {
-        if (empty($this->tree_data[$item_id])) {
-            return false;
-        }
-
-        if (empty($this->entries_init_done)) {
-            $this->initEntries();
-        }
-
-        return parent::getNumEntries($item_id, $num_entries_from_kids);
-        /*
-        if (!$num_entries_from_kids){
-            return $this->tree_data[$item_id]["entries"];
-        } else {
-            $item_list = $this->getKidsKids($item_id);
-            $item_list[] = $item_id;
-            $ret = 0;
-            $num_items = count($item_list);
-            for ($i = 0; $i < $num_items; ++$i){
-                $ret += $this->tree_data[$item_list[$i]]["entries"];
-            }
-            return $ret;
-        }
-        */
-    }
-
-    public function getAdminRange($item_id)
-    {
-        if (!$this->tree_data[$item_id])
-            return false;
-        if ($item_id == "root")
-            return "root";
-        $ret_id = $item_id;
-        while ($ret_id != "root"){
-            $ret_id = $this->tree_data[$ret_id]['parent_id'];
-        }
-        return $ret_id;
-    }
-
-    public function InsertItem($item_id, $parent_id, $item_name, $item_info, $priority, $studip_object_id, $type)
-    {
-        $view = new DbView();
-        $view->params = [$item_id,$parent_id,$item_name,$priority,$item_info,$studip_object_id, $type];
-        $rs = $view->get_query("view:SEM_TREE_INS_ITEM");
-        // Logging
-        StudipLog::log("STUDYAREA_ADD",$item_id);
-        NotificationCenter::postNotification("StudyAreaDidCreate", $item_id, $GLOBALS['user']->id);
-
-        return $rs->affected_rows();
-    }
-
-    public function UpdateItem($item_id, $item_name, $item_info, $type)
-    {
-        $view = new DbView();
-        $view->params = [$item_name,$item_info,$type,$item_id];
-        $rs = $view->get_query("view:SEM_TREE_UPD_ITEM");
-        NotificationCenter::postNotification("StudyAreaDidUpdate", $item_id, $GLOBALS['user']->id);
-
-        return $rs->affected_rows();
-    }
-
-    public function DeleteItems($items_to_delete)
-    {
-        $view = new DbView();
-        $view->params[0] = (is_array($items_to_delete)) ? $items_to_delete : [$items_to_delete];
-        $view->auto_free_params = false;
-        $rs = $view->get_query("view:SEM_TREE_DEL_ITEM");
-        $deleted['items'] = $rs->affected_rows();
-        $rs = $view->get_query("view:SEMINAR_SEM_TREE_DEL_RANGE");
-        $deleted['entries'] = $rs->affected_rows();
-        // Logging
-        foreach ($items_to_delete as $item_id) {
-            StudipLog::log("STUDYAREA_DELETE",$item_id);
-            NotificationCenter::postNotification("StudyAreaDidDelete", $item_id, $GLOBALS['user']->id);
-         }
-        return $deleted;
-    }
-
-    public function DeleteSemEntries($item_ids = null, $sem_entries = null)
-    {
-        $view = new DbView();
-        if ($item_ids && $sem_entries) {
-            $sem_tree_ids = $view->params[0] = (is_array($item_ids)) ? $item_ids : [$item_ids];
-            $seminar_ids = $view->params[1] = (is_array($sem_entries)) ? $sem_entries : [$sem_entries];
-            $rs = $view->get_query("view:SEMINAR_SEM_TREE_DEL_SEM_RANGE");
-            $ret = $rs->affected_rows();
-            // Logging
-            foreach ($sem_tree_ids as $range) {
-                foreach ($seminar_ids as $sem) {
-                    StudipLog::log("SEM_DELETE_STUDYAREA",$sem,$range);
-                }
-            }
-            if($ret){
-                foreach ($sem_tree_ids as $sem_tree_id){
-                    $studyarea = StudipStudyArea::find($sem_tree_id);
-                    if($studyarea->isModule()) {
-                        foreach ($seminar_ids as $seminar_id) {
-                            NotificationCenter::postNotification('CourseRemovedFromModule', $studyarea, ['module_id' => $sem_tree_id, 'course_id' => $seminar_id]);
-                        }
-                    }
-                }
-            }
-        } elseif ($item_ids){
-            $view->params[0] = (is_array($item_ids)) ? $item_ids : [$item_ids];
-            // Logging
-            foreach ($view->params[0] as $range) {
-                StudipLog::log("SEM_DELETE_STUDYAREA","all",$range);
-            }
-            $rs = $view->get_query("view:SEMINAR_SEM_TREE_DEL_RANGE");
-            $ret = $rs->affected_rows();
-        } elseif ($sem_entries){
-            $view->params[0] = (is_array($sem_entries)) ? $sem_entries : [$sem_entries];
-            // Logging
-            foreach ($view->params[0] as $sem) {
-                StudipLog::log("SEM_DELETE_STUDYAREA",$sem,"all");
-            }
-            $rs = $view->get_query("view:SEMINAR_SEM_TREE_DEL_SEMID_RANGE");
-            $ret = $rs->affected_rows();
-        } else {
-            $ret = false;
-        }
-
-        return $ret;
-    }
-
-    public function InsertSemEntry($sem_tree_id, $seminar_id)
-    {
-        $view = new DbView();
-        $view->params[0] = $seminar_id;
-        $view->params[1] = $sem_tree_id;
-        $rs = $view->get_query("view:SEMINAR_SEM_TREE_INS_ITEM");
-        if($ret = $rs->affected_rows()){
-            // Logging
-            StudipLog::log("SEM_ADD_STUDYAREA",$seminar_id,$sem_tree_id);
-            $studyarea = StudipStudyArea::find($sem_tree_id);
-            if($studyarea->isModule()){
-                NotificationCenter::postNotification('CourseAddedToModule', $studyarea, ['module_id' => $sem_tree_id, 'course_id' => $seminar_id]);
-            }
-        }
-        return $ret;
-    }
-}
diff --git a/lib/classes/StudipSemTreeSearch.php b/lib/classes/StudipSemTreeSearch.php
deleted file mode 100644
index 0d8f935..0000000
--- a/lib/classes/StudipSemTreeSearch.php
+++ /dev/null
@@ -1,241 +0,0 @@
-<?php
-# Lifter002: TODO
-# Lifter007: TODO
-# Lifter003: TODO
-# Lifter010: TODO
-// +---------------------------------------------------------------------------+
-// This file is part of Stud.IP
-// StudipSemTreeSearch.php
-// Class to build search formular and execute search
-//
-// Copyright (c) 2003 André Noack <noack@data-quest.de>
-// +---------------------------------------------------------------------------+
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or any later version.
-// +---------------------------------------------------------------------------+
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-// +---------------------------------------------------------------------------+
-
-/**
-* Class to build search formular and execute search
-*
-*
-*
-* @access   public
-* @author   André Noack <noack@data-quest.de>
-* @package  DBTools
-**/
-class StudipSemTreeSearch {
-
-    var $view;
-    var $num_search_result = false;
-    var $num_inserted;
-    var $num_deleted;
-    var $form_name;
-    var $tree;
-    var $seminar_id;
-    var $institut_id = [];
-    var $sem_tree_ranges = [];
-    var $sem_tree_ids = [];
-    var $selected = [];
-    var $search_result = [];
-    var $search_done = false;
-
-    function __construct($seminar_id,$form_name = "search_sem_tree", $auto_search = true){
-        $this->view = DbView::getView('sem_tree');
-        $this->form_name = $form_name;
-        $this->tree = TreeAbstract::GetInstance("StudipSemTree", false);
-        $this->seminar_id = $seminar_id;
-        $this->view->params[0] = $seminar_id;
-        $rs = $this->view->get_query("view:SEM_GET_INST");
-        while($rs->next_record()){
-            $this->institut_id[] = $rs->f(0);
-        }
-        $this->init();
-        if($auto_search){
-            $this->doSearch();
-        }
-    }
-
-    function init(){
-        $this->sem_tree_ranges = [];
-        $this->sem_tree_ids = [];
-        $this->selected = [];
-        $this->view->params[0] = $this->seminar_id;
-        $rs = $this->view->get_query("view:SEMINAR_SEM_TREE_GET_IDS");
-        while($rs->next_record()){
-            if (!$this->tree->hasKids($rs->f("sem_tree_id"))){
-                $this->sem_tree_ranges[$rs->f("parent_id")][] = $rs->f("sem_tree_id");
-                $this->sem_tree_ids[] = $rs->f("sem_tree_id");
-                $this->selected[$rs->f("sem_tree_id")] = true;
-            }
-        }
-    }
-    /* fuzzy !!!
-    function getExpectedRanges(){
-        $this->view->params[0] = $this->institut_id;
-        $this->view->params[1] = $this->sem_tree_ids;
-        $rs = $this->view->get_query("view:SEMINAR_SEM_TREE_GET_EXP_IDS");
-        while ($rs->next_record()){
-            if (!$this->tree->hasKids($rs->f("sem_tree_id"))){
-                $this->sem_tree_ranges[$rs->f("parent_id")][] = $rs->f("sem_tree_id");
-                $this->sem_tree_ids[] = $rs->f("sem_tree_id");
-            }
-        }
-    }
-    */
-
-    //not fuzzy
-    function getExpectedRanges(){
-        $this->view->params[0] = $this->institut_id;
-        $rs = $this->view->get_query("view:SEM_TREE_GET_FAK");
-        while($rs->next_record()){
-            $the_kids = $this->tree->getKidsKids($rs->f("sem_tree_id"));
-            $the_kids[] = $rs->f("sem_tree_id");
-            for ($i = 0; $i < count($the_kids); ++$i){
-                if (!$this->tree->hasKids($the_kids[$i]) && !in_array($the_kids[$i],$this->sem_tree_ids)){
-                    $this->sem_tree_ranges[$this->tree->tree_data[$the_kids[$i]]['parent_id']][] = $the_kids[$i];
-                    $this->sem_tree_ids[] = $the_kids[$i];
-                }
-            }
-        }
-    }
-
-    function prepRangePath($path, $cols) {
-        $parts=explode(">",$path);
-        $paths=[];
-        $currpath="";
-        foreach ($parts as $part) {
-            if (mb_strlen($part)>$cols) {
-                $p=my_substr($part, 0, $cols);
-            } else {
-                $p = $part;
-            }
-            if (mb_strlen($currpath)+mb_strlen($p)+3 > $cols) {
-                $paths[]=htmlReady($currpath);
-                $currpath="   >> " . $p;
-            } else {
-                if (count($paths)==0 && mb_strlen($currpath)==0) {
-                    $currpath.=$p;
-                } else {
-                    $currpath.=" > ".$p;
-                }
-            }
-        }
-        $paths[]=htmlReady($currpath);
-        return $paths;
-    }
-
-    function getChooserField($attributes = [], $cols = 70, $field_name = 'chooser'){
-        if ($this->institut_id){
-            $this->getExpectedRanges();
-        }
-        $element_name = "{$this->form_name}_{$field_name}[]";
-        $ret = "\n<div class=\"selectbox\"";
-        foreach ($attributes as $key => $value){
-            $ret .= " " . $key . "=\"" . htmlReady($value) . "\"";
-        }
-        $ret .= ">";
-        foreach ($this->sem_tree_ranges as $range_id => $sem_tree_id){
-            $paths=$this->prepRangePath($this->getPath($range_id), $cols);
-            foreach ($paths as $p) {
-                $ret .= "\n<div style=\"margin-top:5px;font-weight:bold;color:red;\">" . $p ."</div>";
-            }
-            $ret .= "\n<div style=\"font-weight:bold;color:red;\">" . str_repeat("¯",$cols) . "</div>";
-            for ($i = 0; $i < count($sem_tree_id); ++$i){
-                $id = $this->form_name . '_' . $field_name . '_' . $sem_tree_id[$i];
-                $ret .= "\n<div>";
-                $ret .= "\n<label for=\"$id\"><input style=\"vertical-align:middle;\" id=\"$id\" type=\"checkbox\" name=\"$element_name\" value=\"".$sem_tree_id[$i]."\" " . (($this->selected[$sem_tree_id[$i]]) ? " checked " : "");
-                $ret .= ">&nbsp;";
-                $ret .= "<span ". (($this->search_result[$sem_tree_id[$i]]) ? " style=\"color:blue;\" " : "") . ">";
-                $ret .= htmlReady(my_substr($this->tree->tree_data[$sem_tree_id[$i]]['name'],0,$cols)) . "</span></label>";
-                $ret .= "\n</div>";
-            }
-        }
-        $ret .= "</div>";
-        return $ret;
-    }
-
-    function getPath($item_id,$delimeter = ">"){
-        return $this->tree->getShortPath($item_id);
-    }
-
-
-    function getSearchField($attributes = []){
-        $ret = "\n<input type=\"text\" name=\"{$this->form_name}_search_field\"";
-        foreach ($attributes as $key => $value){
-            $ret .= " " . $key . "=\"" . htmlReady($value) ."\"";
-        }
-        $ret .= ">";
-        return $ret;
-    }
-
-    function getSearchButton($attributes = [])
-    {
-        $ret = Icon::create('search', 'clickable', ['title' => _('Suche nach Studienbereichen starten')])
-                ->asInput(["type" => "image", "class" => "middle", "name" => $this->form_name . "_do_search"]);
-
-        return $ret;
-    }
-
-    function getFormStart($action = ""){
-        if (!$action){
-            $action = URLHelper::getLink();
-        }
-        $ret = "\n<form action=\"$action\" method=\"post\" name=\"{$this->form_name}\">";
-        $ret .= CSRFProtection::tokenTag();
-        return $ret;
-    }
-
-    function getFormEnd(){
-
-        return "\n<input type=\"hidden\" name=\"{$this->form_name}_send\" value=\"1\">\n</form>";
-    }
-
-    function doSearch(){
-        if (Request::submitted($this->form_name . "_do_search") || Request::submitted($this->form_name . "_send")){
-            if(mb_strlen($_REQUEST[$this->form_name . "_search_field"]) > 2){
-                $this->view->params[0] = "%" . Request::quoted($this->form_name . "_search_field") . "%";
-                $this->view->params[1] = $this->sem_tree_ids;
-                $rs = $this->view->get_query("view:SEM_TREE_SEARCH_ITEM");
-                while($rs->next_record()){
-                    $this->sem_tree_ranges[$rs->f("parent_id")][] = $rs->f("sem_tree_id");
-                    $this->sem_tree_ids[] = $rs->f("sem_tree_id");
-                    $this->search_result[$rs->f("sem_tree_id")] = true;
-                }
-                $this->num_search_result = $rs->num_rows();
-            }
-            $this->search_done = true;
-        }
-        return;
-    }
-
-    public function insertSelectedRanges($selected = null)
-    {
-        if (!$selected){
-            $selected = array_filter(Request::quotedArray("{$this->form_name}_chooser"));
-        }
-
-        if (is_array($selected)){
-            $count_intersect = count(array_intersect($selected,array_keys($this->selected)));
-            if (count($this->selected) != $count_intersect || count($selected) != $count_intersect){
-                $count_del = (count($this->selected)) ? $this->tree->DeleteSemEntries(array_keys($this->selected),$this->seminar_id) : 0;
-                for ($i = 0; $i < count($selected); ++$i){
-                    $new_selected[$selected[$i]] = true;
-                    $count_ins += $this->tree->InsertSemEntry($selected[$i], $this->seminar_id);
-                }
-                $this->num_inserted = $count_ins - $count_intersect;
-                $this->num_deleted = $count_del - $count_intersect;
-                $this->selected = $new_selected;
-            }
-        }
-    }
-}
diff --git a/lib/classes/StudipSemTreeView.php b/lib/classes/StudipSemTreeView.php
deleted file mode 100644
index f2d6fbe..0000000
--- a/lib/classes/StudipSemTreeView.php
+++ /dev/null
@@ -1,215 +0,0 @@
-<?php
-# Lifter002: TODO
-# Lifter007: TODO
-# Lifter003: TODO
-# Lifter010: TODO
-// +---------------------------------------------------------------------------+
-// This file is part of Stud.IP
-// StudipSemTreeView.php
-// Class to print out the seminar tree
-//
-// Copyright (c) 2003 André Noack <noack@data-quest.de>
-// Suchi & Berg GmbH <info@data-quest.de>
-// +---------------------------------------------------------------------------+
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or any later version.
-// +---------------------------------------------------------------------------+
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-// +---------------------------------------------------------------------------+
-
-
-/**
-* class to print out the seminar tree
-*
-* This class prints out a html representation of the whole or part of the tree
-*
-* @access   public
-* @author   André Noack <noack@data-quest.de>
-* @package
-*/
-class StudipSemTreeView extends TreeView {
-
-    /**
-    * constructor
-    *
-    * @access public
-    */
-    function __construct($start_item_id = "root", $sem_number = null){
-        $this->start_item_id = ($start_item_id) ? $start_item_id : "root";
-        $this->root_content = $GLOBALS['UNI_INFO'];
-        $args = null;
-        if ($sem_number){
-            $args = ['sem_number' => $sem_number];
-        }
-        parent::__construct("StudipSemTree", $args); //calling the baseclass constructor
-    }
-
-    /**
-    * manages the session variables used for the open/close thing
-    *
-    * @access   private
-    */
-    function handleOpenRanges(){
-        global $_REQUEST;
-
-        $this->open_ranges[$this->start_item_id] = true;
-        if (Request::option('close_item') || Request::option('open_item')){
-            $toggle_item = (Request::option('close_item')) ? Request::option('close_item') : Request::option('open_item');
-            if (!$this->open_items[$toggle_item]){
-                $this->open_items[$toggle_item] = true;
-            } else {
-                unset($this->open_items[$toggle_item]);
-            }
-
-            if($this->tree->hasKids(Request::option('open_item'))){
-                $this->start_item_id = Request::option('open_item');
-                $this->open_ranges = null;
-                $this->open_items = null;
-                $this->open_items[Request::option('open_item')] = true;
-                $this->open_ranges[Request::option('open_item')] = true;
-            }
-
-            $this->anchor = $toggle_item;
-        }
-
-        if ($this->start_item_id == "root"){
-            $this->open_ranges = null;
-            $this->open_ranges[$this->start_item_id] = true;
-        }
-    }
-
-    function showSemTree(){
-        echo "\n<table width=\"99%\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\">";
-        if ($this->start_item_id != 'root'){
-            echo "\n<tr><td class=\"printhead\" align=\"left\" valign=\"top\">" . $this->getSemPath()
-            . Assets::img('forumleer.gif', ['size' => '1@20']) . "</td></tr>";
-        }
-        echo "\n<tr><td class=\"blank\"  align=\"left\" valign=\"top\">";
-        $this->showTree($this->start_item_id);
-        echo "\n</td></tr></table>";
-    }
-
-    function getSemPath(){
-        //$ret = "<a href=\"" . parent::getSelf("start_item_id=root") . "\">" .htmlReady($this->tree->root_name) . "</a>";
-        if ($parents = $this->tree->getParents($this->start_item_id)){
-            for($i = count($parents)-1; $i >= 0; --$i){
-                $ret .= " &gt; <a class=\"tree\" href=\"" . URLHelper::getLink($this->getSelf("start_item_id={$parents[$i]}&open_item={$parents[$i]}",false))
-                    . "\">" .htmlReady($this->tree->tree_data[$parents[$i]]["name"]) . "</a>";
-            }
-        }
-        return $ret;
-    }
-
-    /**
-    * returns html for the icons in front of the name of the item
-    *
-    * @access   private
-    * @param    string  $item_id
-    * @return   string
-    */
-    function getItemHeadPics($item_id){
-        $head = "";
-        $head .= "<a href=\"";
-        $head .= ($this->open_items[$item_id])? URLHelper::getLink($this->getSelf("close_item={$item_id}")) . "\"" . tooltip(_("Dieses Element schließen"),true) . ">"
-                                            : URLHelper::getLink($this->getSelf("open_item={$item_id}")) . "\"" . tooltip(_("Dieses Element öffnen"),true) . ">";
-        $head .= Icon::create($this->open_items[$item_id] ? 'arr_1down' : 'arr_1right', 'clickable');
-        $head .= (!$this->open_items[$item_id]) ? Assets::img('forumleer.gif', ['size' => '5']) : "";
-        $head .= "</a>";
-        if ($this->tree->hasKids($item_id)){
-            $head .= Icon::create('folder-full', 'clickable', ['title' => $this->open_ranges[$item_id]?_('Alle Unterelemente schliessen'):_('Alle Unterelemente öffnen')])->asImg(16, ['class' => 'text-top']);
-        } else {
-            $head .= Icon::create('folder-empty', 'clickable', ['title' => _('Dieses Element hat keine Unterelemente')])->asImg();
-        }
-    return $head;
-    }
-
-    function getItemContent($item_id){
-        $content = "\n<table width=\"90%\" cellpadding=\"2\" cellspacing=\"0\" align=\"center\" style=\"font-size:10pt\">";
-        if ($item_id == "root"){
-            $content .= "\n<tr><td class=\"table_header_bold\" align=\"left\">" . htmlReady($this->tree->root_name) ." </td></tr>";
-            $content .= "\n<tr><td class=\"table_row_even\" align=\"left\">" . htmlReady($this->root_content) ." </td></tr>";
-            $content .= "\n</table>";
-            return $content;
-        }
-        if ($this->tree->tree_data[$item_id]['info']){
-            $content .= "\n<tr><td class=\"table_row_even\" align=\"left\" colspan=\"2\">";
-            $content .= formatReady($this->tree->tree_data[$item_id]['info']) . "</td></tr>";
-        }
-        $content .= "<tr><td colspan=\"2\" class=\"table_row_even\">" . sprintf(_("Alle Veranstaltungen innerhalb dieses Bereiches in der %sÜbersicht%s"),
-                "<a href=\"" . URLHelper::getLink($this->getSelf("cmd=show_sem_range&item_id=$item_id")) ."\">","</a>") . "</td></tr>";
-        $content .= "<tr><td colspan=\"2\">&nbsp;</td></tr>";
-        if ($this->tree->getNumEntries($item_id)){
-            $content .= "<tr><td class=\"table_row_even\" align=\"left\" colspan=\"2\"><b>" . _("Einträge auf dieser Ebene:");
-            $content .= "</b>\n</td></tr>";
-            $entries = $this->tree->getSemData($item_id);
-            $content .= $this->getSemDetails($entries->getGroupedResult("seminar_id"));
-        } else {
-            $content .= "\n<tr><td class=\"table_row_even\" colspan=\"2\">" . _("Keine Einträge auf dieser Ebene vorhanden!") . "</td></tr>";
-        }
-        $content .= "</table>";
-        return $content;
-    }
-
-    function getSemDetails($sem_data){
-        $content = "";
-        $sem_number = -1;
-        foreach($sem_data as $seminar_id => $data){
-            if (key($data['sem_number']) != $sem_number){
-                $sem_number = key($data['sem_number']);
-                $content .= "\n<tr><td class=\"content_seperator\" colspan=\"2\">" . $this->tree->sem_dates[$sem_number]['name'] . "</td></tr>";
-            }
-            $sem_name = key($data["Name"]);
-            $sem_number_end = key($data["sem_number_end"]);
-            if ($sem_number != $sem_number_end){
-                $sem_name .= " (" . $this->tree->sem_dates[$sem_number]['name'] . " - ";
-                $sem_name .= (($sem_number_end == -1) ? _("unbegrenzt") : $this->tree->sem_dates[$sem_number_end]['name']) . ")";
-            }
-            $content .= "<tr><td class=\"table_row_even\"><a href=\"details.php?sem_id=". $seminar_id
-            ."&send_from_search=true&send_from_search_page=" . rawurlencode(URLHelper::getLink($this->getSelf())) . "\">" . htmlReady($sem_name) . "</a>
-            </td><td class=\"table_row_even\" align=\"right\">(";
-            for ($i = 0; $i < count($data["doz_name"]); ++$i){
-                $content .= "<a href=\"dispatch.php/profile?username=" . key($data["doz_uname"]) ."\">" . htmlReady(key($data["doz_name"])) . "</a>";
-                if($i != count($data["doz_name"])-1){
-                    $content .= ", ";
-                }
-                next($data["doz_name"]);
-                next($data["doz_uname"]);
-            }
-            $content .= ") </td></tr>";
-            }
-            return $content;
-    }
-
-    function getItemHead($item_id){
-        $head = "";
-        $head .= parent::getItemHead($item_id);
-        if ($item_id != "root"){
-            $head .= " (" . $this->tree->getNumEntries($item_id,true) . ") " ;
-        }
-        return $head;
-    }
-
-    function getSelf($param = "", $with_start_item = true){
-        if ($param)
-            $url = (($with_start_item) ? "?start_item_id=" . $this->start_item_id . "&" : "?") . $param . "#anchor";
-        else
-            $url = (($with_start_item) ? "?start_item_id=" . $this->start_item_id : "") . "#anchor";
-        return $url;
-    }
-}
-//test
-//page_open(array("sess" => "Seminar_Session", "auth" => "Seminar_Default_Auth", "perm" => "Seminar_Perm", "user" => "Seminar_User"));
-//include 'lib/include/html_head.inc.php';
-//include ('lib/seminar_open.php'); // initialise Stud.IP-Session
-//$test = new StudipSemTreeView();
-//$test->showTree("c2942084b6140fc2635dfecdf65bf20d");
-//page_close();
-?>
diff --git a/lib/classes/StudipSemTreeViewAdmin.php b/lib/classes/StudipSemTreeViewAdmin.php
index 28755c7..e69de29 100644
--- a/lib/classes/StudipSemTreeViewAdmin.php
+++ b/lib/classes/StudipSemTreeViewAdmin.php
@@ -1,825 +0,0 @@
-<?php
-# Lifter001: TEST
-# Lifter002: TODO
-# Lifter005: TODO
-# Lifter007: TODO
-# Lifter003: TODO
-# Lifter010: TODO
-// +---------------------------------------------------------------------------+
-// This file is part of Stud.IP
-// StudipSemTreeViewAdmin.php
-// Class to print out the seminar tree in administration mode
-//
-// Copyright (c) 2003 André Noack <noack@data-quest.de>
-// Suchi & Berg GmbH <info@data-quest.de>
-// +---------------------------------------------------------------------------+
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or any later version.
-// +---------------------------------------------------------------------------+
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-// +---------------------------------------------------------------------------+
-
-use Studip\Button, Studip\LinkButton;
-
-
-/**
-* class to print out the seminar tree (admin mode)
-*
-* This class prints out a html representation of the whole or part of the tree
-*
-* @access   public
-* @author   André Noack <noack@data-quest.de>
-* @package
-*/
-class StudipSemTreeViewAdmin extends TreeView
-{
-    var $admin_ranges = [];
-    var $msg = [];
-    var $marked_item;
-    var $marked_sem;
-    var $mode;
-    var $move_item_id = null;
-    var $edit_item_id = null;
-
-    /**
-    * constructor
-    *
-    * @access public
-    */
-    function __construct($start_item_id = "root"){
-        $this->start_item_id = ($start_item_id) ? $start_item_id : "root";
-        $this->root_content = $GLOBALS['UNI_INFO'];
-        parent::__construct("StudipSemTree"); //calling the baseclass constructor
-        URLHelper::bindLinkParam("_marked_item", $this->marked_item);
-        $this->marked_sem =& $_SESSION['_marked_sem'];
-        $this->parseCommand();
-    }
-
-    /**
-    * manages the session variables used for the open/close thing
-    *
-    * @access   private
-    */
-    function handleOpenRanges(){
-
-        $this->open_ranges[$this->start_item_id] = true;
-
-        if (Request::option('close_item') || Request::option('open_item')){
-            $toggle_item = (Request::option('close_item')) ? Request::option('close_item') : Request::option('open_item');
-            if (!$this->open_items[$toggle_item]){
-                $this->openItem($toggle_item);
-            } else {
-                unset($this->open_items[$toggle_item]);
-            }
-        }
-
-        if (Request::option('item_id')) $this->anchor = Request::option('item_id');
-
-    }
-
-    function openItem($item_id){
-        if ($this->tree->hasKids($item_id)){
-            $this->start_item_id = $item_id;
-            $this->open_ranges = null;
-            $this->open_items = null;
-            $this->open_items[$item_id] = true;
-            $this->open_ranges[$item_id] = true;
-        } else {
-            $this->open_ranges[$this->tree->tree_data[$item_id]['parent_id']] = true;
-            $this->open_items[$item_id] = true;
-            $this->start_item_id = $this->tree->tree_data[$item_id]['parent_id'];
-        }
-        if ($this->start_item_id == "root"){
-            $this->open_ranges = null;
-            $this->open_ranges[$this->start_item_id] = true;
-        }
-        $this->anchor = $item_id;
-    }
-
-    function parseCommand(){
-        $this->mode = '';
-        if (Request::quoted('mode'))
-        $this->mode = Request::quoted('mode');
-        if (Request::option('cmd')){
-            $exec_func = "execCommand" . Request::option('cmd');
-            if (method_exists($this,$exec_func)){
-                if ($this->$exec_func()){
-                    $this->tree->init();
-                }
-            }
-        }
-        if ($this->mode == "MoveItem" || $this->mode == "CopyItem")
-        $this->move_item_id = $this->marked_item;
-    }
-
-    public function execCommandOrderItemsAlphabetically()
-    {
-        $item_id = Request::option('sort_id');
-        $sorted_items_stmt = DBManager::get()->prepare(
-            'SELECT * FROM sem_tree LEFT JOIN Institute ON studip_object_id = Institut_id WHERE parent_id = :parent_id ORDER BY IF(studip_object_id, Institute.name, sem_tree.name)'
-        );
-        $sorted_items_stmt->execute([
-            'parent_id' => $item_id,
-        ]);
-        $sorted_items = $sorted_items_stmt->fetchAll(PDO::FETCH_ASSOC);
-        foreach ($sorted_items as $priority => $data) {
-            $update_priority_stmt = DBManager::get()->prepare('UPDATE sem_tree SET priority = :priority WHERE sem_tree_id = :sem_tree_id');
-            $update_priority_stmt->execute([
-                'priority' => $priority,
-                'sem_tree_id' => $data['sem_tree_id']
-            ]);
-        }
-        $this->msg[$item_id] = 'info§' . _('Die Einträge im Bereich wurden alphabetisch sortiert.');
-
-        return true;
-    }
-
-    function execCommandOrderItem(){
-        $direction = Request::quoted('direction');
-        $item_id = Request::option('item_id');
-        $items_to_order = $this->tree->getKids($this->tree->tree_data[$item_id]['parent_id']);
-        if (!$this->isParentAdmin($item_id) || !$items_to_order)
-        return false;
-        for ($i = 0; $i < count($items_to_order); ++$i){
-            if ($item_id == $items_to_order[$i])
-            break;
-        }
-        if ($direction == "up" && isset($items_to_order[$i-1])){
-            $items_to_order[$i] = $items_to_order[$i-1];
-            $items_to_order[$i-1] = $item_id;
-        } elseif (isset($items_to_order[$i+1])){
-            $items_to_order[$i] = $items_to_order[$i+1];
-            $items_to_order[$i+1] = $item_id;
-        }
-        $view = DbView::getView('sem_tree');
-        for ($i = 0; $i < count($items_to_order); ++$i){
-            $view->params = [$i, $items_to_order[$i]];
-            $rs = $view->get_query("view:SEM_TREE_UPD_PRIO");
-        }
-        $this->mode = "";
-        $this->msg[$item_id] = "msg§" . (($direction == "up") ? _("Element wurde eine Position nach oben verschoben.") : _("Element wurde eine Position nach unten verschoben."));
-        return true;
-    }
-
-    function execCommandNewItem(){
-        $item_id = Request::option('item_id');
-        if ($this->isItemAdmin($item_id)){
-            $new_item_id = DbView::get_uniqid();
-            $this->tree->storeItem($new_item_id,$item_id,_("Neuer Eintrag"), $this->tree->getNumKids($item_id) +1);
-            $this->openItem($new_item_id);
-            $this->edit_item_id = $new_item_id;
-            if ($this->mode != "NewItem") $this->msg[$new_item_id] = "info§" . _("Hier können Sie die Bezeichnung und die Kurzinformation zu diesem Bereich eingeben.");
-            $this->mode = "NewItem";
-        }
-        return false;
-    }
-
-    function execCommandEditItem(){
-        $item_id = Request::option('item_id');
-        if ($this->isItemAdmin($item_id) || $this->isParentAdmin($item_id)){
-            $this->mode = "EditItem";
-            $this->anchor = $item_id;
-            $this->edit_item_id = $item_id;
-            if($this->tree->tree_data[$this->edit_item_id]['studip_object_id']){
-                $this->msg[$item_id] = "info§" . _("Hier können Sie die Kurzinformation zu diesem Bereich eingeben. Der Name kann nicht geändert werden, da es sich um eine Stud.IP-Einrichtung handelt.");
-            } else {
-                $this->msg[$item_id] = "info§" . _("Hier können Sie die Bezeichnung und die Kurzinformation zu diesem Bereich eingeben");
-            }
-        }
-        return false;
-    }
-
-    function execCommandInsertItem(){
-        $item_id = Request::option('item_id');
-        $parent_id = Request::option('parent_id');
-        $item_name = Request::quoted('edit_name');
-        $item_info = Request::quoted('edit_info');
-        $item_type = Request::int('edit_type');
-        if ($this->mode == "NewItem" && $item_id){
-            if ($this->isItemAdmin($parent_id)){
-                $priority = count($this->tree->getKids($parent_id));
-                if ($this->tree->InsertItem($item_id,$parent_id,$item_name,$item_info,$priority,null,$item_type)){
-                    $this->mode = "";
-                    $this->tree->init();
-                    $this->openItem($item_id);
-                    $this->msg[$item_id] = "msg§" . _("Dieser Bereich wurde neu eingefügt.");
-                }
-            }
-        }
-        if ($this->mode == "EditItem"){
-            if ($this->isParentAdmin($item_id)){
-                if ($this->tree->UpdateItem($item_id, $item_name, $item_info, $item_type)){
-                    $this->msg[$item_id] = "msg§" . _("Bereich wurde geändert.");
-                } else {
-                    $this->msg[$item_id] = "info§" . _("Keine Veränderungen vorgenommen.");
-                }
-                $this->mode = "";
-                $this->tree->init();
-                $this->openItem($item_id);
-            }
-        }
-        return false;
-    }
-
-    function execCommandAssertDeleteItem(){
-        $item_id = Request::option('item_id');
-        if ($this->isParentAdmin($item_id)){
-            $this->mode = "AssertDeleteItem";
-            $this->open_items[$item_id] = true;
-            $this->msg[$item_id] = "info§" ._("Sie beabsichtigen diesen Bereich inklusive aller Unterbereiche zu löschen. ")
-            . sprintf(_("Es werden insgesamt %s Bereiche gelöscht!"),count($this->tree->getKidsKids($item_id))+1)
-            . "<br>" . _("Wollen Sie diese Bereiche wirklich löschen?") . "<br>"
-            . LinkButton::createAccept(_('Ja!'),
-                    URLHelper::getURL($this->getSelf('cmd=DeleteItem&item_id='.$item_id)),
-                    ['title' => _('löschen')])
-            . "&nbsp;"
-            . LinkButton::createCancel(_('Nein!'),
-                    URLHelper::getURL($this->getSelf('cmd=Cancel&item_id='. $item_id)));
-        }
-        return false;
-    }
-
-    function execCommandDeleteItem(){
-        $item_id = Request::option('item_id');
-        $item_name = $this->tree->tree_data[$item_id]['name'];
-        if ($this->isParentAdmin($item_id) && $this->mode == "AssertDeleteItem"){
-            $this->openItem($this->tree->tree_data[$item_id]['parent_id']);
-            $items_to_delete = $this->tree->getKidsKids($item_id);
-            $items_to_delete[] = $item_id;
-            $deleted = $this->tree->DeleteItems($items_to_delete);
-            if ($deleted['items']){
-                $this->msg[$this->anchor] = "msg§" . sprintf(_("Der Bereich <b>%s</b> und alle Unterbereiche (insgesamt %s) wurden gelöscht. "),htmlReady($item_name),$deleted['items']);
-            } else {
-                $this->msg[$this->anchor] = "error§" . _("Fehler, es konnten keine Bereiche gelöscht werden !");
-            }
-            if ($deleted['entries']){
-                $this->msg[$this->anchor] .= sprintf(_("<br>Es wurden %s Veranstaltungszuordnungen gelöscht. "),$deleted['entries']);
-            }
-            $this->mode = "";
-        }
-        return true;
-    }
-
-    function execCommandMoveItem(){
-        $item_id = Request::option('item_id');
-        $this->anchor = $item_id;
-        $this->marked_item = $item_id;
-        $this->mode = "MoveItem";
-        return false;
-    }
-
-    function execCommandCopyItem(){
-        $item_id = Request::option('item_id');
-        $this->anchor = $item_id;
-        $this->marked_item = $item_id;
-        $this->mode = "CopyItem";
-        return false;
-    }
-
-    function execCommandDoMoveItem(){
-        $item_id = Request::option('item_id');
-        $item_to_move = $this->marked_item;
-        if ($this->mode == "MoveItem" && ($this->isItemAdmin($item_id) || $this->isParentAdmin($item_id))
-        && ($item_to_move != $item_id) && ($this->tree->tree_data[$item_to_move]['parent_id'] != $item_id)
-        && !$this->tree->isChildOf($item_to_move,$item_id)){
-            $view = DbView::getView('sem_tree');
-            $view->params = [$item_id, count($this->tree->getKids($item_id)), $item_to_move];
-            $rs = $view->get_query("view:SEM_TREE_MOVE_ITEM");
-            if ($rs->affected_rows()){
-                $this->msg[$item_to_move] = "msg§" . _("Bereich wurde verschoben.");
-            } else {
-                $this->msg[$item_to_move] = "error§" . _("Keine Verschiebung durchgeführt.");
-            }
-        }
-        $this->tree->init();
-        $this->openItem($item_to_move);
-        $this->mode = "";
-        return false;
-    }
-
-    function execCommandDoCopyItem(){
-        $item_id = Request::option('item_id');
-        $item_to_copy = $this->marked_item;
-        if ($this->mode == "CopyItem" && ($this->isItemAdmin($item_id) || $this->isParentAdmin($item_id))
-        && ($item_to_copy != $item_id) && ($this->tree->tree_data[$item_to_copy]['parent_id'] != $item_id)
-        && !$this->tree->isChildOf($item_to_copy,$item_id)){
-            $items_to_copy = $this->tree->getKidsKids($item_to_copy);
-            $seed = DbView::get_uniqid();
-            $new_item_id = md5($item_to_copy . $seed);
-            $parent_id = $item_id;
-            $num_copy = $this->tree->InsertItem($new_item_id,$parent_id,
-            addslashes($this->tree->tree_data[$item_to_copy]['name']),
-            addslashes($this->tree->tree_data[$item_to_copy]['info']),
-            $this->tree->getMaxPriority($parent_id)+1,
-            ($this->tree->tree_data[$item_to_copy]['studip_object_id'] ? $this->tree->tree_data[$item_to_copy]['studip_object_id'] : null),
-            $this->tree->tree_data[$item_to_copy]['type']);
-            if($num_copy){
-                if ($items_to_copy){
-                    for ($i = 0; $i < count($items_to_copy); ++$i){
-                        $num_copy += $this->tree->InsertItem(md5($items_to_copy[$i] . $seed),
-                        md5($this->tree->tree_data[$items_to_copy[$i]]['parent_id'] . $seed),
-                        addslashes($this->tree->tree_data[$items_to_copy[$i]]['name']),
-                        addslashes($this->tree->tree_data[$items_to_copy[$i]]['info']),
-                        $this->tree->tree_data[$items_to_copy[$i]]['priority'],
-                        ($this->tree->tree_data[$items_to_copy[$i]]['studip_object_id'] ? $this->tree->tree_data[$items_to_copy[$i]]['studip_object_id'] : null),
-                        $this->tree->tree_data[$item_to_copy]['type']);
-                    }
-                }
-                $items_to_copy[] = $item_to_copy;
-                for ($i = 0; $i < count($items_to_copy); ++$i){
-                    $sem_entries = $this->tree->getSemIds($items_to_copy[$i], false);
-                    if ($sem_entries){
-                        for ($j = 0; $j < count($sem_entries); ++$j){
-                            $num_entries += $this->tree->InsertSemEntry(md5($items_to_copy[$i] . $seed), $sem_entries[$j]);
-                        }
-                    }
-                }
-            }
-
-            if ($num_copy){
-                $this->msg[$new_item_id] = "msg§" . sprintf(_("%s Bereich(e) wurde(n) kopiert."), $num_copy) . "<br>"
-                . sprintf(_("%s Veranstaltungszuordnungen wurden kopiert"), $num_entries);
-            } else {
-                $this->msg[$new_item_id] = "error§" . _("Keine Kopie durchgeführt.");
-            }
-            $this->tree->init();
-            $this->openItem($new_item_id);
-        }
-        $this->mode = "";
-        return false;
-    }
-
-    function execCommandInsertFak(){
-        if($this->isItemAdmin("root") && Request::quoted('insert_fak')){
-            $view = DbView::getView('sem_tree');
-            $item_id = $view->get_uniqid();
-            $view->params = [$item_id,'root','',$this->tree->getNumKids('root')+1,'',Request::quoted('insert_fak'),0];
-            $rs = $view->get_query("view:SEM_TREE_INS_ITEM");
-            if ($rs->affected_rows()){
-                $this->tree->init();
-                $this->openItem($item_id);
-                $this->msg[$item_id] = "msg§" . _("Dieser Bereich wurde neu eingefügt.");
-                return false;
-            }
-        }
-        return false;
-    }
-
-    function execCommandMarkSem(){
-        $item_id = Request::option('item_id');
-        $marked_sem_array =  Request::quotedArray('marked_sem');
-        $marked_sem = array_values(array_unique($marked_sem_array));
-        $sem_aktion = explode("_",Request::quoted('sem_aktion'));
-        if (($sem_aktion[0] == 'mark' || $sem_aktion[1] == 'mark') && count($marked_sem)){
-            $count_mark = 0;
-            for ($i = 0; $i < count($marked_sem); ++$i){
-                if (!isset($this->marked_sem[$marked_sem[$i]])){
-                    ++$count_mark;
-                    $this->marked_sem[$marked_sem[$i]] = true;
-                }
-            }
-            if ($count_mark){
-                $this->msg[$item_id] = "msg§" . sprintf(_("Es wurde(n) %s Veranstaltung(en) der Merkliste hinzugefügt."),$count_mark);
-            }
-        }
-        if ($this->isItemAdmin($item_id)){
-            if (($sem_aktion[0] == 'del' || $sem_aktion[1] == 'del') && count($marked_sem)){
-                $not_deleted = [];
-                foreach($marked_sem as $key => $seminar_id){
-                    $course = Course::find($seminar_id);
-                    if (count($course->getStudyAreas()) === 1) {
-                        $not_deleted[] = $course->name;
-                        unset($marked_sem[$key]);
-                    }
-                }
-                if ($this->msg[$item_id]){
-                    $this->msg[$item_id] .= "<br>";
-                } else {
-                    $this->msg[$item_id] = "msg§";
-                }
-                if(count($marked_sem)){
-                    $count_del = $this->tree->DeleteSemEntries($item_id, $marked_sem);
-                    $this->msg[$item_id] .= sprintf(_("%s Veranstaltungszuordnung(en) wurde(n) aufgehoben."),$count_del);
-                }
-                if(count($not_deleted)){
-                    $this->msg[$item_id] .= '<br>'
-                                         . sprintf(_("Für folgende Veranstaltungen wurde die Zuordnung nicht aufgehoben, da es die einzige Zuordnung ist: %s")
-, '<br>'.htmlready(join(', ', $not_deleted)));
-                }
-            }
-            $this->anchor = $item_id;
-            $this->open_items[$item_id] = true;
-            return true;
-        }
-        return false;
-    }
-
-    function execCommandCancel(){
-        $item_id = Request::option('item_id');
-        $this->mode = "";
-        $this->anchor = $item_id;
-        return false;
-    }
-
-    function showSemTree(){
-        ?>
-        <script type="text/javascript">
-        function invert_selection(the_form){
-            my_elements = document.forms[the_form].elements['marked_sem[]'];
-            if(!my_elements.length){
-                if(my_elements.checked)
-                my_elements.checked = false;
-                else
-                my_elements.checked = true;
-            } else {
-                for(i = 0; i < my_elements.length; ++i){
-                    if(my_elements[i].checked)
-                    my_elements[i].checked = false;
-                    else
-                    my_elements[i].checked = true;
-                }
-            }
-        }
-        </script>
-        <?
-        echo "\n<table width=\"99%\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\">";
-        if ($this->start_item_id != 'root'){
-            echo "\n<tr><td class=\"table_row_odd\" align=\"left\" valign=\"top\"><div style=\"font-size:10pt;margin-left:10px\"><b>"
-            . _("Studienbereiche") . ":</b><br>" .  $this->getSemPath()
-            . "</div></td></tr>";
-        }
-        echo "\n<tr><td class=\"blank\"  align=\"left\" valign=\"top\">";
-        $this->showTree($this->start_item_id);
-        echo "\n</td></tr></table>";
-    }
-
-    function getSemPath(){
-        $ret = "";
-        //$ret = "<a href=\"" . parent::getSelf("start_item_id=root") . "\">" .htmlReady($this->tree->root_name) . "</a>";
-        if ($parents = $this->tree->getParents($this->start_item_id)){
-            for($i = count($parents)-1; $i >= 0; --$i){
-                $ret .= " &gt; <a class=\"tree\" href=\"" . URLHelper::getLink($this->getSelf("start_item_id={$parents[$i]}&open_item={$parents[$i]}",false))
-                . "\">" .htmlReady($this->tree->tree_data[$parents[$i]]["name"]) . "</a>";
-            }
-        }
-        return $ret;
-    }
-
-    /**
-    * returns html for the icons in front of the name of the item
-    *
-    * @access   private
-    * @param    string  $item_id
-    * @return   string
-    */
-    function getItemHeadPics($item_id){
-        $head = $this->getItemHeadFrontPic($item_id);
-        $head .= "\n<td  class=\"printhead\" nowrap  align=\"left\" valign=\"bottom\">";
-        if ($this->tree->hasKids($item_id)){
-            $head .= Icon::create('folder-full', Icon::ROLE_CLICKABLE, ['title' => !empty($this->open_ranges[$item_id]) ? _('Alle Unterelemente schliessen') : _('Alle Unterelemente öffnen')])->asImg(['class' => 'text-top']);
-        } else {
-            $head .= Icon::create('folder-empty', 'clickable', ['title' => _('Dieses Element hat keine Unterelemente')])->asImg();
-        }
-        return $head . "</td>";
-    }
-
-    function getItemContent($item_id){
-        if ($item_id == $this->edit_item_id) {
-            return $this->getEditItemContent();
-        }
-        if (empty($GLOBALS['SEM_TREE_TYPES'][$this->tree->getValue($item_id, 'type')]['editable'])){
-            $is_not_editable = true;
-            $this->msg[$item_id] = "info§" . sprintf(_("Der Typ dieses Elementes verbietet eine Bearbeitung."));
-        }
-        if ($item_id == $this->move_item_id) {
-            $this->msg[$item_id] = "info§" . sprintf(_("Dieses Element wurde zum Verschieben / Kopieren markiert. Bitte wählen Sie ein Einfügesymbol %s aus, um das Element zu verschieben / kopieren."), Icon::create('arr_2right', 'sort', ['title' => "Einfügesymbol"])->asImg(16, ["alt" => "Einfügesymbol"]));
-        }
-        $content = "\n<table width=\"90%\" cellpadding=\"2\" cellspacing=\"2\" align=\"center\" style=\"font-size:10pt;\">";
-        $content .= $this->getItemMessage($item_id);
-        $content .= "\n<tr><td style=\"font-size:10pt;\">";
-        if (empty($is_not_editable)) {
-            if ($this->isItemAdmin($item_id) ){
-                $content .= LinkButton::create(_('Neues Objekt'),
-                        URLHelper::getURL($this->getSelf('cmd=NewItem&item_id='.$item_id)),
-                        ['title' => _('Innerhalb dieser Ebene ein neues Element einfügen')]) . '&nbsp;';
-                $content .= LinkButton::create(_('Sortieren'),
-                        URLHelper::getURL($this->getSelf('cmd=OrderItemsAlphabetically&sort_id='.$item_id)),
-                        ['title' => _('Sortiert die untergeordneten Elemente alphabetisch')]) . '&nbsp;';
-            }
-            if ($this->isParentAdmin($item_id) && $item_id != "root"){
-                $content .= LinkButton::create(_('Bearbeiten'),
-                        URLHelper::getURL($this->getSelf('cmd=EditItem&item_id=' . $item_id)),
-                        ['title' => 'Dieses Element bearbeiten']) . '&nbsp;';
-
-                $content .= LinkButton::create(_('Löschen'),
-                        URLHelper::getURL($this->getSelf('cmd=AssertDeleteItem&item_id=' . $item_id)),
-                        ['title' => _('Dieses Element löschen')]) . '&nbsp;';
-
-                if ($this->move_item_id == $item_id && ($this->mode == "MoveItem" || $this->mode == "CopyItem")){
-                    $content .= LinkButton::create(_('Abbrechen'),
-                            URLHelper::getURL($this->getSelf('cmd=Cancel&item_id=' . $item_id)),
-                            ['title' => _('Verschieben / Kopieren abbrechen')]) . '&nbsp;';
-                } else {
-                    $content .= LinkButton::create(_('Verschieben'),
-                            URLHelper::getURL($this->getSelf('cmd=MoveItem&item_id='.$item_id)),
-                            ['title' => _('Dieses Element in eine andere Ebene verschieben')]) . '&nbsp;';
-                    $content .= LinkButton::create(_('Kopieren'),
-                            URLHelper::getURL($this->getSelf('cmd=CopyItem&item_id='.$item_id)),
-                            ['title' => _('Dieses Element in eine andere Ebene kopieren')]);
-                }
-            }
-        }
-        if ($item_id == 'root' && $this->isItemAdmin($item_id)){
-            $view = DbView::getView('sem_tree');
-            $rs = $view->get_query("view:SEM_TREE_GET_LONELY_FAK");
-            $content .= "\n<p><form action=\"" . URLHelper::getLink($this->getSelf("cmd=InsertFak")) . "\" method=\"post\" class=\"default\">"
-                . CSRFProtection::tokenTag()
-                . '<div><label>'
-                . _("Stud.IP-Fakultät einfügen")
-                . "\n<select style=\"width:200px;\" name=\"insert_fak\">";
-            while($rs->next_record()){
-                $content .= "\n<option value=\"" . $rs->f("Institut_id") . "\">" . htmlReady(my_substr($rs->f("Name"),0,50)) . "</option>";
-            }
-            $content .= "</select></label></div><div class=\"col-1\"> " . Button::create(_('Eintragen'), ['title' => _("Fakultät einfügen")]) . "</div></form></p>";
-        }
-        $content .= "</td></tr></table>";
-
-        $content .= "\n<table border=\"0\" width=\"90%\" cellpadding=\"2\" cellspacing=\"0\" align=\"center\" style=\"font-size:10pt\">";
-        if ($item_id == "root"){
-            $content .= "\n<tr><td  class=\"table_header_bold\" align=\"left\" style=\"font-size:10pt;\">" . htmlReady($this->tree->root_name) ." </td></tr>";
-            $content .= "\n<tr><td  class=\"table_row_even\" align=\"left\" style=\"font-size:10pt;\">" . htmlReady($this->root_content) ." </td></tr>";
-            $content .= "\n</table>";
-            return $content;
-        }
-        if ($this->tree->tree_data[$item_id]['info']){
-            $content .= "\n<tr><td style=\"font-size:10pt;\" class=\"table_row_even\" align=\"left\" colspan=\"3\">";
-            $content .= formatReady($this->tree->tree_data[$item_id]['info']) . "</td></tr>";
-        }
-        $content .= "<tr><td style=\"font-size:10pt;\"colspan=\"3\">&nbsp;</td></tr>";
-        if ($this->tree->getNumEntries($item_id)) {
-            $content .= "<tr><td class=\"table_row_even\" style=\"font-size:10pt;\" align=\"left\" colspan=\"3\"><b>" . _("Einträge auf dieser Ebene:");
-            $content .= "</b>\n</td></tr>";
-            $entries = $this->tree->getSemData($item_id);
-            $content .= $this->getSemDetails($entries,$item_id);
-        } else {
-            $content .= "\n<tr><td class=\"table_row_even\" style=\"font-size:10pt;\" colspan=\"3\">" . _("Keine Einträge auf dieser Ebene vorhanden!") . "</td></tr>";
-        }
-        $content .= "</table>";
-        return $content;
-    }
-
-    function getSemDetails($snap, $item_id, $lonely_sem = false){
-        $form_name = DbView::get_uniqid();
-        $content = "<form class=\"default\" name=\"$form_name\" action=\"" . URLHelper::getLink($this->getSelf("cmd=MarkSem")) ."\" method=\"post\">
-        <input type=\"hidden\" name=\"item_id\" value=\"$item_id\">";
-        $content .= CSRFProtection::tokenTag();
-        $group_by_data = $snap->getGroupedResult("sem_number", "seminar_id");
-        $sem_data = $snap->getGroupedResult("seminar_id");
-        $group_by_duration = $snap->getGroupedResult("sem_number_end", ["sem_number","seminar_id"]);
-        foreach ($group_by_duration as $sem_number_end => $detail){
-            if ($sem_number_end != -1 && ($detail['sem_number'][$sem_number_end] && count($detail['sem_number']) == 1)){
-                continue;
-            } else {
-                foreach ($detail['seminar_id'] as $seminar_id => $foo){
-                    $start_sem = key($sem_data[$seminar_id]["sem_number"]);
-                    if ($sem_number_end == -1){
-                        $sem_number_end = count($this->tree->sem_dates)-1;
-                    }
-                    for ($i = $start_sem; $i <= $sem_number_end; ++$i){
-                        if ($group_by_data[$i] && !$tmp_group_by_data[$i]){
-                            foreach($group_by_data[$i]['seminar_id'] as $id => $bar){
-                                $tmp_group_by_data[$i]['seminar_id'][$id] = key($sem_data[$id]["Name"]);
-                            }
-                        }
-                        $tmp_group_by_data[$i]['seminar_id'][$seminar_id] = key($sem_data[$seminar_id]["Name"]);
-                    }
-                }
-            }
-        }
-        if (is_array($tmp_group_by_data)){
-            foreach ($tmp_group_by_data as $start_sem => $detail){
-                $group_by_data[$start_sem] = $detail;
-            }
-        }
-
-        foreach ($group_by_data as $group_field => $sem_ids){
-            foreach ($sem_ids['seminar_id'] as $seminar_id => $foo){
-                $name = mb_strtolower(key($sem_data[$seminar_id]["Name"]));
-                $name = str_replace("ä","ae",$name);
-                $name = str_replace("ö","oe",$name);
-                $name = str_replace("ü","ue",$name);
-                $group_by_data[$group_field]['seminar_id'][$seminar_id] = $name;
-            }
-            uasort($group_by_data[$group_field]['seminar_id'], 'strnatcmp');
-        }
-
-        krsort($group_by_data, SORT_NUMERIC);
-
-        foreach ($group_by_data as $sem_number => $sem_ids){
-            $content .= "\n<tr><td class=\"content_seperator\" colspan=\"3\" style=\"font-size:10pt;\" >" . $this->tree->sem_dates[$sem_number]['name'] . "</td></tr>";
-            if (is_array($sem_ids['seminar_id'])){
-                foreach(array_keys($sem_ids['seminar_id']) as $seminar_id) {
-                    $sem_name = key($sem_data[$seminar_id]["Name"]);
-                    $sem_number_start = key($sem_data[$seminar_id]["sem_number"]);
-                    $sem_number_end = key($sem_data[$seminar_id]["sem_number_end"]);
-                    if ($sem_number_start != $sem_number_end){
-                        $sem_name .= " (" . $this->tree->sem_dates[$sem_number_start]['name'] . " - ";
-                        $sem_name .= (($sem_number_end == -1) ? _("unbegrenzt") : $this->tree->sem_dates[$sem_number_end]['name']) . ")";
-                    }
-                    $content .= "<tr><td class=\"table_row_even\" width=\"1%\"><input type=\"checkbox\" name=\"marked_sem[]\" value=\"$seminar_id\" style=\"vertical-align:middle\">
-                    </td><td class=\"table_row_even\" style=\"font-size:10pt;\"><a href=\"dispatch.php/course/details/?sem_id=". $seminar_id
-                    ."&send_from_search=true&send_from_search_page=" . rawurlencode(URLHelper::getLink($this->getSelf())) . "\">" . htmlReady($sem_name) . "</a>
-                    </td><td class=\"table_row_even\" align=\"right\" style=\"font-size:10pt;\">(";
-                    $doz_name = array_keys($sem_data[$seminar_id]['doz_name']);
-                    $doz_uname = array_keys($sem_data[$seminar_id]['doz_uname']);
-                    if (is_array($doz_name)){
-                        uasort($doz_name, 'strnatcasecmp');
-                        $i = 0;
-                        foreach ($doz_name as $index => $value){
-                            if ($i == 4){
-                                $content .= "... <a href=\"dispatch.php/course/details/?sem_id=". $seminar_id
-                                ."&send_from_search=true&send_from_search_page=" . rawurlencode(URLHelper::getLink($this->getSelf())) . "\">("._("mehr").")</a>";
-                                break;
-                            }
-                            $content .= "<a href=\"dispatch.php/profile?username=" . $doz_uname[$index] ."\">" . htmlReady($value) . "</a>";
-                            if($i != count($doz_name)-1){
-                                $content .= ", ";
-                            }
-                            ++$i;
-                        }
-                    }
-                    $content .= ") </td></tr>";
-                }
-            }
-        }
-        $content .= "<tr><td class=\"table_row_even\" colspan=\"2\">"
-            . LinkButton::create(_('Auswählen'), ['title' => _('Auswahl umkehren'), 'onClick' => 'invert_selection(\''. $form_name .'\');return false;'])
-            . "</td><td class=\"table_row_even\" align=\"right\"><div class=\"hgroup\">
-        <select name=\"sem_aktion\" style=\"margin-right: 1em;\" " . tooltip(_("Aktion auswählen"),true) . ">
-        <option value=\"mark\">" . _("in Merkliste übernehmen") . "</option>";
-        if (!$lonely_sem && $this->isItemAdmin($item_id)){
-            $content .= "<option value=\"del_mark\">" . _("löschen und in Merkliste übernehmen") . "</option>
-            <option value=\"del\">" . _("löschen") . "</option>";
-        }
-        $content .= "</select>" . Button::createAccept(_('OK'), ['title' => _("Gewählte Aktion starten")])
-                 . "</div></td></tr> </form>";
-        return $content;
-    }
-
-    function getEditItemContent(){
-        ob_start();
-        ?>
-        <form name="item_form" action="<?= URLHelper::getLink($this->getSelf("cmd=InsertItem&item_id={$this->edit_item_id}")) ?>" method="POST" class="default" style="width: 90%; margin: auto;">
-            <?= CSRFProtection::tokenTag(); ?>
-            <input type="hidden" name="parent_id" value="<?= $this->tree->tree_data[$this->edit_item_id]['parent_id'] ?>">
-
-            <table style="width: 100%"><?= $this->getItemMessage($this->edit_item_id,2) ?></table>
-
-            <fieldset>
-                <legend><?= _("Bereich editieren") ?></legend>
-
-                <label>
-                    <?= _("Name des Elements") ?>
-                    <input type="text" name="edit_name"
-                        <?= ($this->tree->tree_data[$this->edit_item_id]['studip_object_id']) ? 'disabled="disabled"' : '' ?>
-                           value="<?= htmlReady($this->tree->tree_data[$this->edit_item_id]['name']) ?>">
-                </label>
-
-               <? if (count($GLOBALS['SEM_TREE_TYPES']) > 1) : ?>
-               <label>
-                   <?= _("Typ des Elements") ?>
-                    <select name="edit_type">
-                    <? foreach ($GLOBALS['SEM_TREE_TYPES'] as $sem_tree_type_key => $sem_tree_type) :
-                        if ($sem_tree_type['editable']) :
-                            $selected = $sem_tree_type_key == $this->tree->getValue($this->edit_item_id, 'type') ? 'selected' : '';
-                            echo '<option value="'.htmlReady($sem_tree_type_key).'"'.$selected.'>';
-                            echo htmlReady($sem_tree_type['name'] ? $sem_tree_type['name'] : $sem_tree_type_key);
-                            echo '</option>';
-                        endif;
-                    endforeach;
-                    ?>
-                    </select>
-                </label>
-                <? else : # Auswahl ausblenden, wenn nur ein Typ vorhanden ?>
-                <input type='hidden' name='edit_type' value='0'>
-                <? endif ?>
-
-                <? $buttonlink_id = ($this->mode == "NewItem") ? $this->tree->tree_data[$this->edit_item_id]['parent_id'] : $this->edit_item_id; ?>
-
-                <label>
-                    <?= _("Infotext:") ?>
-                    <textarea rows="5" name="edit_info" wrap="virtual"><?= htmlReady($this->tree->tree_data[$this->edit_item_id]['info']) ?></textarea>
-                </label>
-            </fieldset>
-
-            <footer>
-                <?= Button::createAccept(_('Absenden'), ['title' => _('Einstellungen übernehmen')]) ?>
-                <?= LinkButton::createCancel(_('Abbrechen'),
-                    URLHelper::getURL($this->getSelf('cmd=Cancel&item_id='.$buttonlink_id)),
-                    ['title' => _('Aktion abbrechen')])
-                ?>
-            </footer>
-        </form>
-
-        <?
-        return ob_get_clean();
-    }
-
-
-    function isItemAdmin($item_id){
-        global $auth;
-        if ($auth->auth['perm'] == "root"){
-            return true;
-        }
-        if (!($admin_id = $this->tree->tree_data[$this->tree->getAdminRange($item_id)]['studip_object_id'])){
-            return false;
-        }
-        if(!isset($this->admin_ranges[$admin_id])){
-            $view = DbView::getView('sem_tree');
-            $view->params[0] = $auth->auth['uid'];
-            $view->params[1] = $admin_id;
-            $rs = $view->get_query("view:SEM_TREE_CHECK_PERM");
-            $this->admin_ranges[$admin_id] = ($rs->next_record()) ? true : false;
-        }
-        if ($this->admin_ranges[$admin_id]){
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    function isParentAdmin($item_id){
-        return $this->isItemAdmin($this->tree->tree_data[$item_id]['parent_id']);
-    }
-
-    function getItemHead($item_id){
-        $head = "";
-        if (($this->mode == "MoveItem" || $this->mode == "CopyItem") && ($this->isItemAdmin($item_id) || $this->isParentAdmin($item_id))
-        && ($this->move_item_id != $item_id) && ($this->tree->tree_data[$this->move_item_id]['parent_id'] != $item_id)
-        && !$this->tree->isChildOf($this->move_item_id,$item_id)){
-            $head .= "<a href=\"" . URLHelper::getLink($this->getSelf("cmd=Do" . $this->mode . "&item_id=$item_id")) . "\">"
-            . Icon::create('arr_2right', 'sort', ['title' => _("An dieser Stelle einfügen")])->asImg(16, ["alt" => _("An dieser Stelle einfügen")])."</a>&nbsp;";
-        }
-        $head .= parent::getItemHead($item_id);
-        if ($item_id != "root"){
-            $head .= " (" . $this->tree->getNumEntries($item_id,true) . ") " ;
-        }
-        if ($item_id != $this->start_item_id && $this->isParentAdmin($item_id) && $item_id != $this->edit_item_id){
-            $head .= "</td><td nowrap align=\"right\" valign=\"bottom\" class=\"printhead\">";
-            if (!$this->tree->isFirstKid($item_id)){
-                $head .= "<a href=\"". URLHelper::getLink($this->getSelf("cmd=OrderItem&direction=up&item_id=$item_id")) .
-                "\">" .  Icon::create('arr_2up', 'sort')->asImg(['class' => 'text-top', 'title' => _("Element nach oben")]) .
-                "</a>";
-            }
-            if (!$this->tree->isLastKid($item_id)){
-                $head .= "<a href=\"". URLHelper::getLink($this->getSelf("cmd=OrderItem&direction=down&item_id=$item_id")) .
-                "\">" . Icon::create('arr_2down', 'sort')->asImg(['class' => 'text-top', 'title' => _("Element nach unten")]) .
-                "</a>";
-            }
-            $head .= "&nbsp;";
-        }
-        return $head;
-    }
-
-    function getItemMessage($item_id,$colspan = 1){
-        $content = "";
-        if (!empty($this->msg[$item_id])) {
-            $msg = explode("§",$this->msg[$item_id]);
-            $pics = [
-                'error' => Icon::create('decline', 'attention'),
-                'info'  => Icon::create('exclaim', 'inactive'),
-                'msg'   => Icon::create('accept', 'accept')];
-            $content = "\n<tr><td colspan=\"{$colspan}\"><table border=\"0\" cellspacing=\"0\" cellpadding=\"2\" width=\"100%\" style=\"font-size:10pt\">
-                        <tr><td class=\"blank\" align=\"center\" width=\"25\">" .  $pics[$msg[0]]->asImg(['class' => 'text-top']) . "</td>
-            <td class=\"blank\" align=\"left\">" . $msg[1] . "</td></tr>
-            </table></td></tr><tr>";
-        }
-        return $content;
-    }
-
-    function getSelf($param = "", $with_start_item = true){
-        $url_params = "foo=" . DbView::get_uniqid();
-        if ($this->mode) $url_params .= "&mode=" . $this->mode;
-        if ($with_start_item) $url_params .= "&start_item_id=" . $this->start_item_id;
-        if ($param) $url_params .= '&' . $param;
-        return parent::getSelf($url_params);
-    }
-}
-//test
-//page_open(array("sess" => "Seminar_Session", "auth" => "Seminar_Default_Auth", "perm" => "Seminar_Perm", "user" => "Seminar_User"));
-//include 'lib/include/html_head.inc.php';
-//include ('lib/seminar_open.php'); // initialise Stud.IP-Session
-//$test = new StudipSemTreeViewAdmin(Request::quoted('start_item_id'));
-//$test->showSemTree();
-//echo "<hr><pre>";
-//print_r($_open_items);
-//page_close();
-?>
diff --git a/lib/classes/StudipSemTreeViewSimple.php b/lib/classes/StudipSemTreeViewSimple.php
deleted file mode 100644
index 239275b..0000000
--- a/lib/classes/StudipSemTreeViewSimple.php
+++ /dev/null
@@ -1,244 +0,0 @@
-<?php
-# Lifter001: TEST
-# Lifter002: TODO
-# Lifter007: TODO
-# Lifter003: TODO
-# Lifter010: TODO
-// +---------------------------------------------------------------------------+
-// This file is part of Stud.IP
-// StudipSemTreeViewSimple.php
-// Class to print out the seminar tree
-//
-// Copyright (c) 2003 André Noack <noack@data-quest.de>
-// Suchi & Berg GmbH <info@data-quest.de>
-// +---------------------------------------------------------------------------+
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or any later version.
-// +---------------------------------------------------------------------------+
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-// +---------------------------------------------------------------------------+
-
-/**
-* class to print out the seminar tree
-*
-* This class prints out a html representation a part of the tree
-*
-* @access   public
-* @author   André Noack <noack@data-quest.de>
-* @package
-*/
-class StudipSemTreeViewSimple
-{
-    var $tree;
-    var $show_entries;
-    var $start_item_id;
-    var $root_content;
-
-    /**
-    * constructor
-    *
-    */
-    public function __construct($start_item_id = 'root', $sem_number = false, $sem_status = false, $visible_only = false)
-    {
-        $this->start_item_id = ($start_item_id) ? $start_item_id : "root";
-        $this->root_content = $GLOBALS['UNI_INFO'];
-        $args = null;
-        if ($sem_number !== false){
-            $args['sem_number'] = $sem_number;
-        }
-        if ($sem_status !== false){
-            $args['sem_status'] =  $sem_status;
-        }
-        $args['visible_only'] = $visible_only;
-        $this->tree = TreeAbstract::GetInstance("StudipSemTree",$args);
-        $this->tree->enable_lonely_sem = false;
-        if (empty($this->tree->tree_data[$this->start_item_id])) {
-            $this->start_item_id = "root";
-        }
-    }
-
-    public function showSemTree($start_id = null)
-    {
-        echo '
-            <table class="show-tree">
-                <tr>
-                    <td style="text-align:left; vertical-align:top; font-size:10pt; padding-bottom: 10px; ">
-                        <div style="font-size:10pt; margin-left:0px;display: inline-flex;">
-                        <div class="sem-root-icon"><a href="'. URLHelper::getLink($this->getSelf("start_item_id=root",false)) . "\">" .Icon::create('literature', 'clickable')->asImg(29,['role'=>'root-icon'])
-                        .'</a></div>
-                        <div class="sem-path">'.
-                            '<div class="sem-path-dir">'.
-                                $this->getSemPath($start_id);
-                    echo
-                        '</div>
-                        <div class="sem_path_info">
-                            <div class="sem_path_title">'.
-                            formatReady($this->tree->getValue($this->start_item_id, 'name')).
-                            '</div>
-                            <div class="sem_path_text">';
-                            if ($this->tree->getValue($this->start_item_id, 'info')) {
-                                echo formatReady($this->tree->getValue($this->start_item_id, 'info'));
-                            }else{
-                                echo _("Keine weitere Info vorhanden");
-                            }
-                        echo'</div>
-                            </div>
-                        </div>';
-        echo '
-                        </div>
-                    </td>
-                    <td nowrap style="text-align:right; vertical-align:top; padding-top: 1em;">';
-        if ($this->start_item_id != 'root') {
-            echo '
-                        <a href="' .
-                        URLHelper::getLink($this->getSelf('start_item_id=' .
-                                $this->tree->tree_data[$this->start_item_id]['parent_id'], false)) .
-                        '">' .
-                        Icon::create('arr_2left', 'clickable')->asImg(['class' => 'text-top', 'title' =>_('eine Ebene zurück')]) .
-                        '</a>';
-        } else {
-            echo '&nbsp;';
-        }
-        echo '
-                    </td>
-                </tr>
-                <tr>
-                    <td colspan="2" style="text-align:center;" class="b-top-va-center">';
-        $num_all_entries = $this->showKids($this->start_item_id);
-        echo '
-                    </td>
-                </tr>
-                <tr>
-                    <td colspan="2" style="text-align:left;" class="b-top-va-center">';
-        $this->showContent($this->start_item_id, $num_all_entries);
-        echo '
-                    </td>
-                </tr>
-            </table>';
-    }
-
-    public function showKids($item_id)
-    {
-        $num_kids = $this->tree->getNumKids($item_id);
-        $all_kids = $this->tree->getKids($item_id);
-        $kids = [];
-        if(!$GLOBALS['perm']->have_perm(Config::GetInstance()->getValue('SEM_TREE_SHOW_EMPTY_AREAS_PERM')) && $num_kids){
-            foreach($all_kids as $kid){
-                if($this->tree->getNumKids($kid) || $this->tree->getNumEntries($kid,true)) $kids[] = $kid;
-            }
-            $num_kids = count($kids);
-        } else {
-            $kids = $all_kids;
-        }
-        $num_all_entries = 0;
-       $kids_table = '
-          <table class="show-tree-kids">
-            <tr>
-                <td class="table_row_even kids-tree-row" align="left" valign="top">
-                    <ul class="semtree">';
-        for ($i = 0; $i < $num_kids; ++$i){
-            $num_entries = 0;
-            if ($this->start_item_id != 'root') {
-                $num_entries = $this->tree->getNumEntries($kids[$i],true);
-                $num_all_entries += $num_entries;
-            }
-            $kids_table .= "<li><a " . ($num_entries ? tooltip(sprintf(_("%s Einträge in allen Unterebenen vorhanden"), $num_entries), false) : '') . " href=\"" .URLHelper::getLink($this->getSelf("start_item_id={$kids[$i]}", false)) . "\">";
-            $kids_table .= htmlReady($this->tree->getValue($kids[$i], 'name'));
-            if ($num_entries) $kids_table .= " ($num_entries)";
-            $kids_table .= "</a></li>";
-            if ($i == ceil($num_kids / 2)-1){
-                $kids_table .= '
-                    </ul>
-                </td>
-                <td class="table_row_even kids-tree-row" align="left" valign="top">
-                    <ul class="semtree">';
-            }
-        }
-        if (!$num_kids){
-            $kids_table .= "<li>";
-            $kids_table .= _("Auf dieser Ebene existieren keine weiteren Unterebenen.");
-            $kids_table .= "</li>";
-        }
-
-        $kids_table .= "</ul></td></tr></table>";
-        echo $kids_table;
-        return $num_all_entries;
-    }
-
-    public function getInfoIcon($item_id)
-    {
-        $info = $item_id === 'root' ? $this->root_content : '';
-        return $info ? tooltipicon(kill_format($info)) : '';
-    }
-
-    public function showContent($item_id, $num_all_entries = 0)
-    {
-        echo "\n<div align=\"left\" style=\"margin-top:10px;margin-bottom:10px;font-size:10pt\">";
-        if ($item_id != "root"){
-            if ($num_entries = $this->tree->getNumEntries($item_id)){
-                if ($this->show_entries != "level"){
-                    echo "<a " . tooltip(_("alle Einträge auf dieser Ebene anzeigen"), false) ." href=\"" . URLHelper::getLink($this->getSelf("cmd=show_sem_range&item_id=$item_id")) ."\">";
-                }
-                printf(_("<b>%s</b> Einträge auf dieser Ebene.&nbsp;"),$num_entries);
-                if ($this->show_entries != "level"){
-                    echo "</a>";
-                }
-            } else {
-                    echo _("Keine Einträge auf dieser Ebene vorhanden!");
-            }
-            if ($this->tree->hasKids($item_id) && $num_all_entries){
-                echo "&nbsp;&nbsp;&sol;&nbsp;&nbsp;";
-                if ($this->show_entries != "sublevels"){
-                    if ($num_all_entries <= 100) echo "<a " . tooltip(_("alle Einträge in allen Unterebenen anzeigen"), false) ." href=\"" . URLHelper::getLink($this->getSelf("cmd=show_sem_range&item_id={$this->start_item_id}_withkids")) ."\">";
-                }
-                printf(_("<b>%s</b> Einträge in allen Unterebenen vorhanden"), $num_all_entries);
-                if ($this->show_entries != "sublevels"){
-                    echo "</a>";
-                }
-            }
-        }
-        echo "\n</div>";
-    }
-
-    public function getSemPath($start_id = null)
-    {
-        $ret = '';
-        $parents = $this->tree->getParents($this->start_item_id);
-        if ($parents) {
-            $add_item = false;
-            $start_id = $start_id === null ? 'root' : $start_id;
-            for($i = count($parents) - 1; $i >= 0; --$i){
-                if ($add_item || $start_id == $parents[$i]) {
-                    $ret .= ($add_item === TRUE ? '&nbsp;&sol;&nbsp;' : '')
-                            . "<a href=\"". URLHelper::getLink($this->getSelf("start_item_id={$parents[$i]}", false)). "\">". htmlReady($this->tree->getValue($parents[$i], "name"))."</a>";
-                    $add_item = true;
-                }
-            }
-        }
-        if ($this->start_item_id == "root") {
-            $ret = "<a href=\"" . URLHelper::getLink($this->getSelf("start_item_id=root",false)) . "\">" . $this->tree->root_name  . "</a>";
-        } else {
-            $ret .= "&nbsp;&sol;&nbsp;<a href=\"" . URLHelper::getLink($this->getSelf("start_item_id={$this->start_item_id}",false)) . "\">" . htmlReady($this->tree->getValue($this->start_item_id, "name")) . "</a>";
-            $ret .= "&nbsp;&sol;&nbsp;&nbsp;";
-        }
-        return $ret;
-    }
-
-    /**
-     * @return string url NOT escaped
-     */
-    public function getSelf($param = "", $with_start_item = true)
-    {
-        $url_params = (($with_start_item) ? "start_item_id=" . $this->start_item_id . "&" : "") . $param ;
-        return URLHelper::getURL('?' . $url_params);
-    }
-}
-?>
diff --git a/lib/classes/TreeAbstract.php b/lib/classes/TreeAbstract.php
deleted file mode 100644
index a1413b3..0000000
--- a/lib/classes/TreeAbstract.php
+++ /dev/null
@@ -1,431 +0,0 @@
-<?php
-# Lifter002: TODO
-# Lifter007: TODO
-# Lifter003: TODO
-# Lifter010: TODO
-// +---------------------------------------------------------------------------+
-// This file is part of Stud.IP
-// TreeAbstract.php
-// Abstract Base Class to handle in-memory tree structures
-//
-// Copyright (c) 2002 André Noack <noack@data-quest.de>
-// Suchi & Berg GmbH <info@data-quest.de>
-// +---------------------------------------------------------------------------+
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or any later version.
-// +---------------------------------------------------------------------------+
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-// +---------------------------------------------------------------------------+
-
-
-/**
-* Abstract Base Class to handle in-memory tree structures
-*
-* This class provides an interface to basic handling of structure of tree structures
-*
-* @access   public
-* @author   André Noack <noack@data-quest.de>
-* @package
-*/
-class TreeAbstract {
-
-    /**
-    * the name of the root element
-    *
-    * @access private
-    * @var string $root_name
-    */
-    var $root_name;
-    /**
-    * object to handle database queries
-    *
-    * @access private
-    * @var object DbView $view
-    */
-    var $view;
-    /**
-    * array containing all tree items
-    *
-    * associative array, key is an unique identifier (eg primary key from DB table)
-    * value is another assoc. array containing the other fieldname/fieldvalue pairs
-    * these fieldnames must be used :
-    * parent_id, name, priority
-    * @access public
-    * @var array    $tree_data
-    */
-    var $tree_data = [];
-    /**
-    * array containing the direct childs of all items
-    *
-    * assoc. array, key is one from $tree_data, value is numeric array with keys from childs
-    * @access private
-    * @var array    $tree_childs
-    */
-    var $tree_childs = [];
-
-    /**
-    * array containing the number of direct childs of all items
-    *
-    * assoc. array, key is one from $tree_data
-    * @access private
-    * @var array    $tree_num_childs
-    */
-    var $tree_num_childs = [];
-
-    var $index_offset = 0;
-
-    /**
-    * static method used to ensure that only one instance exists
-    *
-    * use this method if you need a reference to the tree object <br>
-    * usage: <pre>$my_tree = StudipRangeTree::GetInstance("name_of_tree_class")</pre>
-    *
-    * @param    string  $class_name     the name of the used tree_class
-    * @param    mixed   $args           argumentlist passed to the constructor in the tree_class (if needed)
-    * @return   mixed   always an object, type is one of AbstractTree s childclasses
-    */
-    public static function GetInstance($class_name, $args = null, $invalidate_cache = false)
-    {
-        static $tree_instance;
-        $class_hash = '';
-        if ($args){
-            $class_hash = $class_name . "_" . md5(serialize($args));
-        } elseif ($args === false && is_array($tree_instance)){
-            foreach ($tree_instance as $key => $value){
-                $tmp_name = explode("_",$key);
-                if ($tmp_name[0] == $class_name){
-                    $class_hash = $key;
-                    break;
-                }
-            }
-            if (!$class_hash){
-                $class_hash = $class_name;
-            }
-        } else {
-            $class_hash = $class_name;
-        }
-        if (empty($tree_instance[$class_hash]) || $invalidate_cache){
-            $tree_instance[$class_hash] = new $class_name($args);
-        }
-
-        return $tree_instance[$class_hash];
-    }
-
-    /**
-    * constructor
-    *
-    * do not use directly, call &GetInstance()
-    */
-    protected function __construct()
-    {
-        $this->view = new DbView();
-        $this->init();
-    }
-
-    /**
-    * initializes the tree
-    *
-    * stores all tree items in array $tree_data
-    * must be overriden
-    */
-    public function init()
-    {
-        $this->tree_childs = [];
-        $this->tree_num_childs = [];
-        $this->tree_data = [];
-        $this->index_offset = 0;
-        $this->tree_data['root'] = ['parent_id' => null, 'name' => &$this->root_name, 'index' => 0];
-    }
-
-    /**
-    * store one item in tree_data array
-    *
-    * store one item in tree_data array
-    *
-    * @param    string  $item_id
-    * @param    string  $parent_id
-    * @param    string  $name
-    * @param    integer $priority
-    *
-    */
-    public function storeItem($item_id,$parent_id,$name,$priority)
-    {
-        $this->tree_data[$item_id]["parent_id"] = $parent_id;
-        $this->tree_data[$item_id]["priority"] = $priority;
-        $this->tree_data[$item_id]["name"] = $name;
-        $this->tree_childs[$parent_id][] = $item_id;
-        if (empty($this->tree_num_childs[$parent_id])) {
-            $this->tree_num_childs[$parent_id] = 0;
-        }
-        $this->tree_num_childs[$parent_id]++;
-        return;
-    }
-
-    /**
-    * build an index for sorting purpose
-    *
-    * build an index for sorting purpose
-    *
-    * @param    string  $item_id
-    *
-    */
-    public function buildIndex($item_id = false)
-    {
-        if ($item_id === false && $this->index_offset > 0) {
-            return;
-        }
-        if (!$item_id) {
-            $item_id = "root";
-        }
-        $this->tree_data[$item_id]['index'] = $this->index_offset;
-        ++$this->index_offset;
-        if (($num_kids = $this->getNumKids($item_id))) {
-            for($i = 0; $i < $num_kids; ++$i){
-                $this->buildIndex($this->tree_childs[$item_id][$i]);
-            }
-        }
-        return;
-    }
-
-    /**
-    * returns all direct kids
-    *
-    * @param    string  $item_id
-    * @return   array
-    */
-    public function getKids($item_id)
-    {
-        return (isset($this->tree_childs[$item_id]) && is_array($this->tree_childs[$item_id])) ? $this->tree_childs[$item_id] : [];
-    }
-
-    /**
-    * returns the number of all direct kids
-    *
-    * @param    string  $item_id
-    * @param    bool    $in_recursion
-    * @return   int
-    */
-    public function getNumKids($item_id)
-    {
-        if(!isset($this->tree_num_childs[$item_id])){
-            $this->tree_num_childs[$item_id] = (!empty($this->tree_childs[$item_id]) && is_array($this->tree_childs[$item_id])) ? count($this->tree_childs[$item_id]) : 0;
-        }
-        return $this->tree_num_childs[$item_id];
-    }
-
-    /**
-    * returns all direct kids and kids of kids and so on...
-    *
-    * @param    string  $item_id
-    * @param    bool    $in_recursion   only used in recursion
-    * @return   array
-    */
-    public function getKidsKids($item_id, $in_recursion = false)
-    {
-        static $kidskids;
-        if (!$kidskids || !$in_recursion){
-            $kidskids = [];
-        }
-        $num_kids = $this->getNumKids($item_id);
-        if ($num_kids){
-            $kids = $this->getKids($item_id);
-            $kidskids = array_merge((array)$kidskids, (array)$kids);
-            for ($i = 0; $i < $num_kids; ++$i){
-                $this->getKidsKids($kids[$i],true);
-            }
-        }
-        return (!$in_recursion) ? $kidskids : [];
-    }
-
-    /**
-    * returns the number of all kids and kidskids...
-    *
-    * @param    string  $item_id
-    * @param    bool    $in_recursion
-    * @return   int
-    */
-    public function getNumKidsKids($item_id, $in_recursion = false)
-    {
-        static $num_kidskids;
-        if (!$num_kidskids || !$in_recursion){
-            $num_kidskids = 0;
-        }
-        $num_kids = $this->getNumKids($item_id);
-        if ($num_kids){
-            $kids = $this->getKids($item_id);
-            $num_kidskids += $num_kids;
-            for ($i = 0; $i < $num_kids; ++$i){
-                $this->getNumKidsKids($kids[$i],true);
-            }
-        }
-        return (!$in_recursion) ? $num_kidskids : 0;
-    }
-
-    /**
-    * checks if item is the last kid
-    *
-    * @param    string  $item_id
-    * @return   boolean
-    */
-    public function isLastKid($item_id)
-    {
-        $parent_id = $this->tree_data[$item_id]['parent_id'];
-        $num_kids = $this->getNumKids($parent_id);
-        if (!$parent_id || !$num_kids) {
-            return false;
-        }
-        return $this->tree_childs[$parent_id][$num_kids-1] == $item_id;
-    }
-
-    /**
-    * checks if item is the first kid
-    *
-    * @param    string  $item_id
-    * @return   boolean
-    */
-    public function isFirstKid($item_id)
-    {
-        $parent_id = $this->tree_data[$item_id]['parent_id'];
-        $num_kids = $this->getNumKids($parent_id);
-        if (!$parent_id || !$num_kids) {
-            return false;
-        }
-        return $this->tree_childs[$parent_id][0] == $item_id;
-    }
-
-    /**
-    * checks if given item is a kid or kidkid...of given ancestor
-    *
-    * checks if given item is a kid or kidkid...of given ancestor
-    *
-    * @param    string  $ancestor_id
-    * @param    string  $item_id
-    * @return   boolean
-    */
-    public function isChildOf($ancestor_id,$item_id)
-    {
-        return in_array($item_id,$this->getKidsKids($ancestor_id));
-    }
-
-    /**
-    * checks if item has one or more kids
-    *
-    * @param    string  $item_id
-    * @return   boolean
-    */
-    public function hasKids($item_id)
-    {
-        return $this->getNumKids($item_id) > 0;
-    }
-
-    /**
-    * Returns tree path
-    *
-    * returns a string with the item and all parents separated with a slash
-    *
-    * @param    string  $item_id
-    * @return   string
-    */
-    public function getItemPath($item_id)
-    {
-        if (!$this->tree_data[$item_id]) {
-            return false;
-        }
-
-        $path = $this->tree_data[$item_id]['name'];
-        while($item_id && $item_id !== 'root') {
-            $item_id = $this->tree_data[$item_id]['parent_id'];
-            $path = $this->tree_data[$item_id]['name'] . " / " . $path;
-        }
-        return $path;
-    }
-
-    /**
-    * Returns tree path as array of item_id s
-    *
-    * returns an array containing all parents of given item
-    *
-    * @param    string  $item_id
-    * @return   array
-    */
-    public function getParents($item_id)
-    {
-        if (empty($this->tree_data[$item_id])) {
-            return [];
-        }
-
-        $result = [];
-        while ($item_id && $item_id !== 'root') {
-            $item_id   = $this->tree_data[$item_id]['parent_id'];
-            $result[] = $item_id;
-        }
-        return $result;
-    }
-
-    public function getShortPath($item_id, $length = null, $delimeter = ">", $offset = 0)
-    {
-        if (!$this->tree_data[$item_id] || $item_id === 'root') {
-            return false;
-        }
-        $parents = array_reverse($this->getParents($item_id));
-        array_shift($parents);
-        array_push($parents, $item_id);
-        $that = $this;
-        $parents_names = array_map(function($i) use ($that) {return $that->tree_data[$i]['name'];}, array_slice($parents, $offset, $length ? $length : null));
-        return join(" $delimeter ", $parents_names);
-    }
-
-    /**
-    * Returns the maximum priority value from a parents child
-    *
-    * @param    string  $parent_id
-    * @return   int
-    */
-    public function getMaxPriority($parent_id)
-    {
-        $children = $this->getKids($parent_id);
-        $last = $this->getNumKids($parent_id) - 1;
-        return (int) $this->tree_data[$children[$last]]['priority'];
-    }
-
-    public function getNumEntries($item_id, $num_entries_from_kids = false)
-    {
-        if (!$num_entries_from_kids || !$this->hasKids($item_id)){
-                return $this->tree_data[$item_id]["entries"];
-        } else {
-            return $this->getNumEntriesKids($item_id);
-        }
-    }
-
-    public function getNumEntriesKids($item_id, $in_recursion = false)
-    {
-        static $num_entries;
-        if (!$in_recursion){
-            $num_entries = 0;
-        }
-        $num_entries += $this->tree_data[$item_id]["entries"];
-        $num_kids = $this->getNumKids($item_id);
-        if ($num_kids){
-            $kids = $this->getKids($item_id);
-            for ($i = 0; $i < $num_kids; ++$i){
-                $this->getNumEntriesKids($kids[$i],true);
-            }
-        }
-        return (!$in_recursion) ? $num_entries : null;
-    }
-
-    public function getValue($item_id, $field)
-    {
-        return isset($this->tree_data[$item_id][$field])
-             ? $this->tree_data[$item_id][$field]
-             : null;
-    }
-}
diff --git a/lib/classes/TreeView.php b/lib/classes/TreeView.php
deleted file mode 100644
index 0bc2810..0000000
--- a/lib/classes/TreeView.php
+++ /dev/null
@@ -1,444 +0,0 @@
-<?php
-# Lifter001: TEST
-# Lifter002: TODO
-# Lifter007: TODO
-
-// +---------------------------------------------------------------------------+
-// This file is part of Stud.IP
-// TreeView.php
-// Class to print out html represantation of a tree object based on TreeAbstract.php
-//
-// Copyright (c) 2002 André Noack <noack@data-quest.de>
-// Suchi & Berg GmbH <info@data-quest.de>
-// +---------------------------------------------------------------------------+
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or any later version.
-// +---------------------------------------------------------------------------+
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-// +---------------------------------------------------------------------------+
-
-/**
-* Class to print out html represantation of a tree object based on TreeAbstract.php
-*
-* @access   public
-* @author   André Noack <noack@data-quest.de>
-* @package
-*/
-class TreeView {
-
-    /**
-    * Reference to the tree structure
-    *
-    * @access   private
-    * @var  object StudipRangeTree $tree
-    */
-    var $tree;
-    /**
-    * name of used tree class
-    *
-    * @access   private
-    * @var  string $tree_class_name
-    */
-    var $tree_class_name;
-    /**
-    * contains the item with the current html anchor
-    *
-    * @access   public
-    * @var  string  $anchor
-    */
-    var $anchor;
-    /**
-    * array containing all open items
-    *
-    * this is a reference to a global session variable, managed by PHPLib
-    * @access   public
-    * @var  array   $open_items
-    */
-    var $open_items;
-    /**
-    * array containing all open item nodes
-    *
-    * this is a reference to a global session variable, managed by PHPLib
-    * @access   public
-    * @var  array   $open_ranges
-    */
-    var $open_ranges;
-    /**
-    * the item to start with
-    *
-    * @access   private
-    * @var  string  $start_item_id
-    */
-    var $start_item_id;
-    /**
-    * the content of the root element
-    *
-    * @access   public
-    * @var  string  $root_content
-    */
-    var $root_content;
-
-    /**
-    * the maximum amount of columns in a title
-    *
-    * @access   public
-    * @var  string  $max_cols
-    */
-    var $max_cols = 80;
-
-    /**
-    * draw red icons
-    *
-    * @access   public
-    * @var  boolean $use_aging
-    */
-    var $use_aging = false;
-    var $pic_open;
-    var $pic_close;
-
-    /**
-    * constructor
-    *
-    * @access public
-    * @param    string  $tree_class_name    name of used tree class
-    * @param    mixed   $args               argument passed to the tree class
-    */
-    public function __construct($tree_class_name,$args = null)
-    {
-        $this->tree_class_name = $tree_class_name;
-        $this->tree            = TreeAbstract::GetInstance($tree_class_name, $args);
-        // TODO Die Logik hinter forumgrau2 und forumgraurunt2 muss
-        // komplett erneuert werden; dann können auch Instanzen der
-        // Klasse "Icon" verwendet werden.
-        $this->pic_open        = $this->use_aging
-                               ? 'forumgraurunt2.png'
-                               : 'icons/blue/arr_1down.svg';
-        $this->pic_close       = $this->use_aging
-                               ? 'forumgrau2.png'
-                               : 'icons/blue/arr_1right.svg';
-
-        URLHelper::bindLinkParam('open_ranges', $this->open_ranges);
-        URLHelper::bindLinkParam('open_items', $this->open_items);
-
-        $this->handleOpenRanges();
-    }
-
-    /**
-    * manages the link parameters used for the open/close thing
-    *
-    * @access   private
-    */
-    private function handleOpenRanges()
-    {
-        $close_range = Request::option('close_range');
-        if ($close_range) {
-            if ($close_range === 'root'){
-                $this->open_ranges = null;
-                $this->open_items  = null;
-            } else {
-                $kidskids   = $this->tree->getKidsKids($close_range);
-                $kidskids[] = $close_range;
-                foreach ($kidskids as $kid) {
-                    unset($this->open_ranges[$kid]);
-                    unset($this->open_items[$kid]);
-                }
-            }
-            $this->anchor = $close_range;
-        }
-
-        $open_range = Request::option('open_range');
-        if ($open_range) {
-            $kidskids   = $this->tree->getKidsKids($open_range);
-            $kidskids[] = $open_range;
-            foreach ($kidskids as $kid) {
-                $this->open_ranges[$kid] = true;
-            }
-            $this->anchor = $open_range;
-        }
-
-        $toggle_item = Request::option('close_item') ?: Request::option('open_item');
-        if ($toggle_item){
-            if (!empty($this->open_items[$toggle_item])) {
-                unset($this->open_items[$toggle_item]);
-            } else {
-                $this->openItem($toggle_item);
-                $this->openRange($toggle_item);
-            }
-            $this->anchor = $toggle_item;
-        }
-
-        if (Request::option('item_id')) {
-            $this->anchor = Request::option('item_id');
-        }
-    }
-
-    function openItem($item_id)
-    {
-        $this->open_items[$item_id] = true;
-        $this->openRange($this->tree->tree_data[$item_id]['parent_id']);
-    }
-
-    function openRange($item_id)
-    {
-        $this->open_ranges[$item_id] = true;
-
-        $parents = $this->tree->getParents($item_id);
-        foreach ($parents as $parent) {
-            $this->open_ranges[$parent] = true;
-        }
-    }
-
-    /**
-    * prints out the tree beginning with a given item
-    *
-    * @access   public
-    * @param    string  $item_id
-    */
-    function showTree($item_id = "root"){
-    $items = [];
-    if (!is_array($item_id)){
-        $items[0] = $item_id;
-        $this->start_item_id = $item_id;
-    } else {
-        $items = $item_id;
-    }
-    $num_items = count($items);
-    for ($j = 0; $j < $num_items; ++$j){
-        $this->printLevelOutput($items[$j]);
-        $this->printItemOutput($items[$j]);
-        if ($this->tree->hasKids($items[$j]) && !empty($this->open_ranges[$items[$j]])) {
-            $this->showTree($this->tree->tree_childs[$items[$j]]);
-        }
-    }
-    return;
-}
-
-    /**
-    * prints out the lines before an item ("Strichlogik" (c) rstockm)
-    *
-    * @access   private
-    * @param    string  $item_id
-    */
-    function printLevelOutput($item_id)
-    {
-        $level_output = "";
-        if ($item_id != $this->start_item_id){
-            if ($this->tree->isLastKid($item_id))
-                $level_output = "<td class=\"blank tree-indent\" valign=\"top\" nowrap>"
-                              . Assets::img('forumstrich2.gif')
-                              . "</td>"; //last
-            else
-                $level_output = "<td class=\"blank tree-indent\" valign=\"top\" nowrap>"
-                              . Assets::img('forumstrich3.gif')
-                              . "</td>"; //crossing
-            $parent_id = $item_id;
-            while($this->tree->tree_data[$parent_id]['parent_id'] != $this->start_item_id){
-                $parent_id = $this->tree->tree_data[$parent_id]['parent_id'];
-                if ($this->tree->isLastKid($parent_id))
-                    $level_output = "<td class=\"blank tree-indent\" valign=\"top\" width=\"10\" nowrap>"
-                                  . Assets::img('forumleer.gif', ['size' => '10@20'])
-                                  . "</td>" . $level_output; //nothing
-                else
-                    $level_output = "<td class=\"blank tree-indent\" valign=\"top\" nowrap>"
-                                  . Assets::img('forumstrich.gif')
-                                  . "</td>" . $level_output; //vertical line
-            }
-        }
-        echo "\n<table border=\"0\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\"><tr>$level_output";
-        return;
-    }
-
-    /**
-    * prints out one item
-    *
-    * @access   private
-    * @param    string  $item_id
-    */
-    function printItemOutput($item_id)
-    {
-        echo $this->getItemHeadPics($item_id);
-        echo "\n<td class=\"printhead\" nowrap width=\"1\" valign=\"middle\">";
-        if ($this->anchor == $item_id)
-            echo "<a name=\"anchor\">";
-        echo Assets::img('forumleer.gif', ['size' => '1@20']);
-        if ($this->anchor == $item_id)
-            echo "</a>";
-        echo "\n</td><td class=\"printhead\" align=\"left\" width=\"99%\" nowrap valign=\"bottom\">";
-        echo $this->getItemHead($item_id);
-        echo "</td></tr></table>";
-        if (!empty($this->open_items[$item_id])) {
-            $this->printItemDetails($item_id);
-        }
-        return;
-    }
-
-    /**
-    * prints out the details for an item, if item is open
-    *
-    * @access   private
-    * @param    string  $item_id
-    */
-    function printItemDetails($item_id){
-        $level_output = '';
-        if (!$this->tree->hasKids($item_id) || !$this->open_ranges[$item_id] || $item_id == $this->start_item_id)
-            $level_output = "<td class=\"blank\" background=\"" . Assets::image_path('forumleer.gif') . "\">"
-                          . Assets::img('forumleer.gif', ['size' => '10@20'])
-                          . "</td>" . $level_output;
-        else
-            $level_output = "<td class=\"blank\" background=\"" . Assets::image_path('forumstrich.gif') . "\">"
-                          . Assets::img('forumleer.gif', ['size' => '10@20'])
-                          . "</td>" . $level_output;
-
-        if (($this->tree->isLastKid($item_id) && !($item_id == $this->start_item_id)) || (!$this->open_ranges[$item_id] && $item_id == $this->start_item_id) || ($item_id == $this->start_item_id && !$this->tree->hasKids($item_id)))
-            $level_output = "<td class=\"blank\" background=\"" . Assets::image_path('forumleer.gif') . "\">"
-                          . Assets::img('forumleer.gif', ['size' => '10@20'])
-                          . "</td>" . $level_output;
-        else
-            $level_output = "<td class=\"blank\" background=\"" . Assets::image_path('forumstrich.gif') ."\">"
-                          . Assets::img('forumleer.gif', ['size' => '10@20'])
-                          . "</td>" . $level_output;
-        if ($item_id != $this->start_item_id){
-            $parent_id = $item_id;
-            while($this->tree->tree_data[$parent_id]['parent_id'] != $this->start_item_id){
-                $parent_id = $this->tree->tree_data[$parent_id]['parent_id'];
-                if ($this->tree->isLastKid($parent_id))
-                    $level_output = "<td class=\"blank\" background=\"" . Assets::image_path('forumleer.gif') . "\">"
-                                  . Assets::img('forumleer.gif', ['size' => '10@20'])
-                                  . "</td>" . $level_output; //nothing
-                else
-                    $level_output = "<td class=\"blank\" background=\"" . Assets::image_path('forumstrich.gif') . "\">"
-                                  . Assets::img('forumleer.gif', ['size' => '10@20'])
-                                  . "</td>" . ($level_output ?? ''); //vertical line
-            }
-        }
-        //$level_output = "<td class=\"blank\" background=\"".$GLOBALS['ASSETS_URL']."images/forumleer.gif\" ><img src=\"".$GLOBALS['ASSETS_URL']."images/forumleer.gif\" width=\"20\" height=\"20\" border=\"0\" ></td>" . $level_output;
-
-        echo "<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\" width=\"100%\"><tr>$level_output";
-        echo "<td class=\"printcontent\" width=\"100%\"><br>";
-        echo $this->getItemContent($item_id);
-        echo "<br></td></tr></table>";
-    }
-
-    /**
-    * returns html for the icons in front of the name of the item
-    *
-    * @access   private
-    * @param    string  $item_id
-    * @return   string
-    */
-    function getItemHeadPics($item_id)
-    {
-        $head = $this->getItemHeadFrontPic($item_id);
-        $head .= "\n<td  class=\"printhead\" nowrap align=\"left\" valign=\"bottom\">";
-        if ($this->tree->hasKids($item_id)){
-            $head .= "<a href=\"";
-            $head .= !empty($this->open_ranges[$item_id])
-                ? URLHelper::getLink($this->getSelf("close_range={$item_id}"))
-                : URLHelper::getLink($this->getSelf("open_range={$item_id}"));
-            $head .= "\">";
-            $head .= Icon::create('folder-full', 'clickable', ['title' => !empty($this->open_ranges[$item_id]) ? _('Alle Unterelemente schließen') : _('Alle Unterelemente öffnen')])->asImg(16, ['class' => 'text-top']);
-            $head .= "</a>";
-        } else {
-            $head .= Icon::create('folder-empty', 'clickable', ['title' => _('Dieses Element hat keine Unterelemente')])->asImg();
-        }
-    return $head . "</td>";
-    }
-
-    function getItemHeadFrontPic($item_id)
-    {
-        if ($this->use_aging){
-            $head = "<td bgcolor=\"" . $this->getAgingColor($item_id) . "\" class=\""
-            . (($this->open_items[$item_id]) ? 'printhead3' : 'printhead2')
-            . "\" nowrap width=\"1%\"  align=\"left\" valign=\"top\">";
-        } else {
-            $head = "<td class=\"printhead\" nowrap align=\"left\" valign=\"bottom\">";
-        }
-        $head .= "<a href=\"";
-        $head .= !empty($this->open_items[$item_id])
-            ? URLHelper::getLink($this->getSelf("close_item={$item_id}")) . "\"" . tooltip(_("Dieses Element schließen"),true) . ">"
-            : URLHelper::getLink($this->getSelf("open_item={$item_id}")) . "\"" . tooltip(_("Dieses Element öffnen"),true) . ">";
-        $head .= Assets::img(!empty($this->open_items[$item_id]) ? $this->pic_open : $this->pic_close);
-        #$head .= (!$this->open_items[$item_id]) ? "<img  src=\"".$GLOBALS['ASSETS_URL']."images/forumleer.gif\" width=\"5\" border=\"0\">" : "";
-        $head .= "</a>";
-        $head .= '</td>';
-        return $head;
-    }
-
-    /**
-    * returns html for the name of the item
-    *
-    * @access   private
-    * @param    string  $item_id
-    * @return   string
-    */
-    function getItemHead($item_id){
-        $head = "";
-        $head .= "&nbsp;<a class=\"tree\" href=\"";
-        $head .= !empty($this->open_items[$item_id])
-            ? URLHelper::getLink($this->getSelf("close_item={$item_id}")) . "\"" . tooltip(_("Dieses Element schließen"),true) . "><b>"
-            : URLHelper::getLink($this->getSelf("open_item={$item_id}")) . "\"" . tooltip(_("Dieses Element öffnen"),true) . ">";
-        $head .= htmlReady(my_substr($this->tree->tree_data[$item_id]['name'],0,$this->max_cols));
-        $head .= (!empty($this->open_items[$item_id])) ? "</b></a>" : "</a>";
-        return $head;
-    }
-
-    /**
-    * returns html for the content body of the item
-    *
-    * @access   private
-    * @param    string  $item_id
-    * @return   string
-    */
-    function getItemContent($item_id){
-        $content = "\n<table width=\"90%\" cellpadding=\"2\" cellspacing=\"2\" align=\"center\" style=\"font-size:10pt\">";
-        if ($item_id == "root"){
-            $content .= "\n<tr><td class=\"table_header_bold\" align=\"left\">" . htmlReady($this->tree->root_name) ." </td></tr>";
-            $content .= "\n<tr><td class=\"blank\" align=\"left\">" . $this->root_content ." </td></tr>";
-            $content .= "\n</table>";
-            return $content;
-        }
-        $content .= "\n<tr><td class=\"blank\" align=\"left\">Inhalt für Element <b>{$this->tree->tree_data[$item_id]['name']} ($item_id)</b><br>".formatReady($this->tree->tree_data[$item_id]['description'])."</td></tr>";
-        $content .= "</table>";
-        return $content;
-    }
-
-    function getAgingColor($item_id){
-        $the_time = time();
-        $chdate = $this->tree->tree_data[$item_id]['chdate'];
-        if ($chdate == 0){
-            $timecolor = "#BBBBBB";
-        } else {
-            if (($the_time - $chdate) < 86400){
-                $timecolor = "#FF0000";
-            } else {
-                $timediff = (int) log(($the_time - $chdate) / 86400 + 1) * 15;
-                if ($timediff >= 68){
-                    $timediff = 68;
-                }
-                $red = dechex(255 - $timediff);
-                $other = dechex(119 + $timediff);
-                $timecolor = "#" . $red . $other . $other;
-            }
-        }
-        return $timecolor;
-    }
-
-    /**
-    * returns script name
-    *
-    * @access   private
-    * @param    string  $param
-    * @return   string
-    */
-    function getSelf($param = ""){
-        return "?" . $param . "#anchor";
-    }
-}
diff --git a/lib/extern/ExternPageCourseDetails.php b/lib/extern/ExternPageCourseDetails.php
index 8cbc7a1..d9e64d9 100644
--- a/lib/extern/ExternPageCourseDetails.php
+++ b/lib/extern/ExternPageCourseDetails.php
@@ -180,12 +180,13 @@ class ExternPageCourseDetails extends ExternPage
      */
     protected function getContentRangePaths(Course $course): array
     {
-        $content = [];
-        $paths = get_sem_tree_path($course->id, $this->rangepathlevel);
-        if (is_array($paths)) {
-            $content = array_values($paths);
+        $paths = [];
+        foreach ($course->study_areas as $study_area) {
+            $paths[] = $study_area->getPath();
         }
-        return ['RANGE_PATHS' => $content];
+        asort($paths);
+
+        return ['RANGE_PATHS' => $paths];
     }
 
     /**
diff --git a/lib/functions.php b/lib/functions.php
index e1b29ed..5659aa5 100644
--- a/lib/functions.php
+++ b/lib/functions.php
@@ -425,28 +425,6 @@ function get_userid($username = "")
 
 
 /**
- * Return an array containing the nodes of the sem-tree-path
- *
- * @param string $seminar_id the seminar to get the path for
- * @param int    $depth      the depth
- * @param string $delimeter  a string to separate the path parts
- *
- * @return array
- */
-function get_sem_tree_path($seminar_id, $depth = false, $delimeter = ">")
-{
-    $the_tree = TreeAbstract::GetInstance("StudipSemTree");
-    $view = DbView::getView('sem_tree');
-    $ret = [];
-    $view->params[0] = $seminar_id;
-    $rs = $view->get_query("view:SEMINAR_SEM_TREE_GET_IDS");
-    while ($rs->next_record()){
-        $ret[$rs->f('sem_tree_id')] = $the_tree->getShortPath($rs->f('sem_tree_id'), null, $delimeter, $depth ? $depth - 1 : 0);
-    }
-    return $ret;
-}
-
-/**
  * check_and_set_date
  *
  * Checks if given date is valid and sets field in array accordingly.
diff --git a/lib/meine_seminare_func.inc.php b/lib/meine_seminare_func.inc.php
index 297bf3f..39f4fa1 100644
--- a/lib/meine_seminare_func.inc.php
+++ b/lib/meine_seminare_func.inc.php
@@ -20,16 +20,8 @@ function get_group_names(string $group_field, array $groups): array
             return (string) $all_semester[$key]['name'];
         };
     } elseif ($group_field === 'sem_tree_id') {
-        $the_tree = TreeAbstract::GetInstance(StudipSemTree::class, ['build_index' => true]);
-        $mapper = function ($key) use ($the_tree): string {
-            if (!empty($the_tree->tree_data[$key])) {
-                return implode(' > ', array_filter([
-                    $the_tree->getShortPath($the_tree->tree_data[$key]['parent_id']),
-                    $the_tree->tree_data[$key]['name'],
-                ]));
-            }
-
-            return _('keine Studienbereiche eingetragen');
+        $mapper = function ($key): string {
+            return StudipStudyArea::getNode($key)->getPath(' > ');
         };
     } elseif ($group_field === 'sem_status') {
         $mapper = function ($key): string {
@@ -82,8 +74,9 @@ function sort_groups($group_field, &$groups)
 
         case 'sem_tree_id':
             uksort($groups, function ($a, $b) {
-                $the_tree = TreeAbstract::GetInstance('StudipSemTree', ['build_index' => true]);
-                return $the_tree->tree_data[$a]['index'] - $the_tree->tree_data[$b]['index'];
+                $a_obj = StudipStudyArea::getNode($a);
+                $b_obj = StudipStudyArea::getNode($b);
+                return strcmp($a_obj->name, $b_obj->name);
             });
             break;
 
diff --git a/lib/models/StudipStudyArea.php b/lib/models/StudipStudyArea.php
index 6c3f582..4e407b4 100644
--- a/lib/models/StudipStudyArea.php
+++ b/lib/models/StudipStudyArea.php
@@ -479,6 +479,25 @@ class StudipStudyArea extends SimpleORMap implements StudipTreeNode
     }
 
     /**
+     * Retrieves all child nodes of this study area as a flat list.
+     *
+     * @param bool $only_visible Whether to include only visible nodes (true)
+     *     or all nodes (false). Defaults to false.
+     *
+     * @return StudipStudyArea[] A list of all child nodes of this node.
+     */
+    public function getAllChildNodes(bool $only_visible = false) : array
+    {
+        $result = [];
+        $children = $this->getChildNodes($only_visible);
+        foreach ($children as $child) {
+            $result[] = $child;
+            $result = array_merge($result, $child->getAllChildNodes($only_visible));
+        }
+        return $result;
+    }
+
+    /**
      * @see StudipTreeNode::countCourses()
      */
     public function countCourses(
diff --git a/lib/modules/CoreOverview.php b/lib/modules/CoreOverview.php
index 94005da..8d4606d 100644
--- a/lib/modules/CoreOverview.php
+++ b/lib/modules/CoreOverview.php
@@ -89,9 +89,20 @@ class CoreOverview extends CorePlugin implements StudipModule
         $navigation->setActiveImage(Icon::create('seminar', Icon::ROLE_INFO));
         if ($object_type !== 'sem') {
             $navigation->addSubNavigation('info', new Navigation(_('Kurzinfo'), 'dispatch.php/institute/overview'));
-            $navigation->addSubNavigation('courses', new Navigation(_('Veranstaltungen'), 'show_bereich.php?level=s&id='.$course_id));
-            $navigation->addSubNavigation('schedule', new Navigation(_('Veranstaltungs-Stundenplan'), 'dispatch.php/institute/schedule/index/' . $course_id));
-
+            $range_tree_node = RangeTreeNode::findOneByStudip_object_id($course_id);
+            if ($range_tree_node) {
+                $navigation->addSubNavigation(
+                    'courses',
+                    new Navigation(_('Veranstaltungen'),
+                        'dispatch.php/search/courses',
+                        [
+                            'node_id' => 'RangeTreeNode_' . $range_tree_node->id,
+                            'type' => 'rangetree'
+                        ]
+                    )
+                );
+                $navigation->addSubNavigation('schedule', new Navigation(_('Veranstaltungs-Stundenplan'), 'dispatch.php/institute/schedule/index/' . $course_id));
+            }
             if ($GLOBALS['perm']->have_studip_perm('admin', $course_id)) {
                 $navigation->addSubNavigation('admin', new Navigation(_('Administration der Einrichtung'), 'dispatch.php/institute/basicdata/index?new_inst=TRUE'));
             }
diff --git a/lib/navigation/SearchNavigation.php b/lib/navigation/SearchNavigation.php
index 66ca672..7562feb 100644
--- a/lib/navigation/SearchNavigation.php
+++ b/lib/navigation/SearchNavigation.php
@@ -32,35 +32,198 @@ class SearchNavigation extends Navigation
     }
 
     /**
+     * Returns a new navigation object for the sidebar according to the name
+     * of the option.
+     * The option name is the key of an entry in the array with the navigation
+     * options.
+     *
+     * The navigation options are configured in the global configuration as an
+     * array. For further details see documentation of entry
+     * COURSE_SEARCH_NAVIGATION_OPTIONS in global configuration.
+     *
+     * This is an example with all possible options.
+     * Note that the "target" attribute has no meaning anymore and is only there
+     * for backwards compatibility with existing configurations. The target is
+     * now hardcoded to "sidebar".
+     *
+     * {
+     *     // "courses", "semtree" and "rangetree" are the "old" search options.
+     *     // The link text is fixed.
+     *     "courses":{
+     *         "visible":true,
+     *         // The target indicates where the link to this search option is
+     *         // placed. Possible values are "sidebar" for a link in the sidebar
+     *         // or "courses" to show a link (maybe with picture) below the
+     *         // "course search".
+     *         "target":"sidebar"
+     *     },
+     *     "semtree":{
+     *         "visible":true,
+     *         "target":"sidebar"
+     *     },
+     *     "rangetree":{
+     *         "visible":false,
+     *         "target":"sidebar"
+     *     },
+     *     // New option to acivate the search for modules and the systematic
+     *     // search in studycourses, field of study and degrees.
+     *     "module":{
+     *         "visible":true,
+     *         "target":"sidebar"
+     *     },
+     *     // This option shows a direct link in the sidebar to an entry (level)
+     *     // in the range tree. The link text is the name of the level.
+     *     "fb3_hist":{
+     *         "visible":true,
+     *         "target":"sidebar",
+     *         "range_tree_id":"d1a07cf0c8057c664279214cc070b580"
+     *     },
+     *     // The same for an entry in the sem tree.
+     *     "grundstudium":{
+     *         "visible":true,
+     *         "target":"sidebar",
+     *         "sem_tree_id":"e1a07cf0c8057c664279214cc070b580"
+     *     },
+     *     // This shows a link in the sidebar to the course search. The text is
+     *     // availlable in two languages.
+     *     "vvz":{
+     *         "visible":true,
+     *         "target":"sidebar",
+     *         "url":"dispatch.php/search/courses?level=f&option=vav",
+     *         "title":{
+     *             "de_DE":"Veranstaltungsverzeichnis",
+     *             "en_GB":"Course Catalogue"
+     *         }
+     *     },
+     *     // This option uses an url with search option and shows a link in the
+     *     // sidebar to an entry in the range tree with all courses.
+     *     "test":{
+     *         "visible":true,
+     *         "target":"sidebar",
+     *         "url":"dispatch.php/search/courses?start_item_id=d1a07cf0c8057c664279214cc070b580&cmd=show_sem_range_tree&item_id=d1a07cf0c8057c664279214cc070b580_withkids&level=ev",
+     *         "title":{
+     *             "de_DE":"Historisches Institut",
+     *             "en_GB":"Historical Institute"
+     *         }
+     *     },
+     *     // This option shows a link to the sem tree with picture below the
+     *     // course search (target: courses).
+     *     // This is the behaviour of Stud.IP < 4.2.
+     *     "csemtree":{
+     *         "visible":true,
+     *         "target":"courses",
+     *         "url":"dispatch.php/search/courses?level=vv",
+     *         "img":{
+     *             "filename":"directory-search.png",
+     *             "attributes":{
+     *                 "size":"260@100"
+     *             }
+     *         },
+     *         "title":{
+     *             "de_DE":"Suche im Vorlesungsverzeichnis",
+     *             "en_GB":"Search course directory"
+     *         }
+     *     },
+     *     // This option shows a link to the range tree with picture below the
+     *     // course search (target: courses).
+     *     // This is the behaviour of Stud.IP < 4.2.
+     *     "crangetree":{
+     *         "visible":true,
+     *         "target":"courses",
+     *         "url":"dispatch.php/search/courses?level=ev",
+     *         "img":{
+     *             "filename":"institute-search.png",
+     *             "attributes":{
+     *                 "size":"260@100"
+     *             }
+     *         },
+     *         "title":{
+     *             "de_DE":"Suche in Einrichtungen",
+     *             "en_GB":"Search institutes"
+     *         }
+     *     }
+     * }
+     *
+     *
+     * @param string $option_name
+     * @return Navigation|null
+     */
+    protected function getSearchOptionNavigation(?string $option_name = null): ?Navigation
+    {
+        // return first visible search option
+        if ($option_name === null) {
+            $options = Config::get()->COURSE_SEARCH_NAVIGATION_OPTIONS;
+            foreach ($options as $name => $option) {
+                if ($option['visible'] && $option['target'] === 'sidebar') {
+                    return $this->getSearchOptionNavigation($name);
+                }
+            }
+            return null;
+        }
+
+        $installed_languages = array_keys(Config::get()->INSTALLED_LANGUAGES);
+        $language = $_SESSION['_language'] ?? reset($installed_languages);
+        $option = Config::get()->COURSE_SEARCH_NAVIGATION_OPTIONS[$option_name];
+        if (!$option['visible'] || $option['target'] !== 'sidebar') {
+            return null;
+        }
+        if (empty($option['url'])) {
+            return match ($option_name) {
+                'courses',
+                'semtree' =>
+                    new Navigation(
+                        _('Vorlesungsverzeichnis'),
+                        URLHelper::getURL('dispatch.php/search/courses', ['type' => 'semtree'], true)
+                    ),
+                'rangetree' =>
+                    new Navigation(
+                        _('Einrichtungsverzeichnis'),
+                        URLHelper::getURL('dispatch.php/search/courses', ['type' => 'rangetree'], true)
+                    ),
+                'module' =>
+                    new MVVSearchNavigation(
+                        _('Modulverzeichnis'),
+                        URLHelper::getURL('dispatch.php/search/module'),
+                        null,
+                        true
+                    )
+            };
+        } else {
+            return new Navigation($option['title'][$language],
+                URLHelper::getURL($option['url'], ['option' => $option_name], true));
+        }
+    }
+
+    /**
      * Initialize the subnavigation of this item. This method
      * is called once before the first item is added or removed.
      */
     public function initSubNavigation()
     {
         parent::initSubNavigation();
-        if($GLOBALS['user']->id != 'nobody'){ 
-            // global search 
-            $navigation = new Navigation(_('Globale Suche'), 'dispatch.php/search/globalsearch'); 
-            $this->addSubNavigation('globalsearch', $navigation); 
-        } 
+        if($GLOBALS['user']->id != 'nobody'){
+            // global search
+            $navigation = new Navigation(_('Globale Suche'), 'dispatch.php/search/globalsearch');
+            $this->addSubNavigation('globalsearch', $navigation);
+        }
 
         // browse courses
         // get first search option
-        if (($GLOBALS['user']->id == 'nobody' && Config::get()->COURSE_SEARCH_IS_VISIBLE_NOBODY) || $GLOBALS['user']->id != 'nobody') { 
-            $navigation_option = SemBrowse::getSearchOptionNavigation('sidebar'); 
+        if (($GLOBALS['user']->id == 'nobody' && Config::get()->COURSE_SEARCH_IS_VISIBLE_NOBODY) || $GLOBALS['user']->id != 'nobody') {
+            $navigation_option = $this->getSearchOptionNavigation();
 
-            if ($navigation_option) { 
-                $navigation = new Navigation( 
-                    _('Veranstaltungsverzeichnis'), 
-                    $navigation_option->getURL() 
-                ); 
-                foreach (array_keys(Config::get()->COURSE_SEARCH_NAVIGATION_OPTIONS) as $name) { 
-                    $navigation_option = SemBrowse::getSearchOptionNavigation('sidebar', $name); 
-                    if ($navigation_option) { 
-                        $navigation->addSubNavigation($name, $navigation_option); 
-                    } 
+            if ($navigation_option) {
+                $navigation = new Navigation(
+                    _('Veranstaltungsverzeichnis'),
+                    $navigation_option->getURL()
+                );
+                foreach (array_keys(Config::get()->COURSE_SEARCH_NAVIGATION_OPTIONS) as $name) {
+                    $navigation_option = $this->getSearchOptionNavigation($name);
+                    if ($navigation_option) {
+                        $navigation->addSubNavigation($name, $navigation_option);
+                    }
                 }
-                    $this->addSubNavigation('courses', $navigation); 
+                    $this->addSubNavigation('courses', $navigation);
             }
         }
 
diff --git a/public/show_bereich.php b/public/show_bereich.php
deleted file mode 100644
index 2a5e55d..0000000
--- a/public/show_bereich.php
+++ /dev/null
@@ -1,147 +0,0 @@
-<?php
-# Lifter001: TEST
-# Lifter002: TEST
-# Lifter007: TEST
-# Lifter003: TEST
-# Lifter010: TEST
-/*
-show_bereich.php - Anzeige von Veranstaltungen eines Bereiches oder Institutes
-Copyright (C) 2000 Cornelis Kater <ckater@gwdg.de>
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-*/
-
-require '../lib/bootstrap.php';
-
-ob_start();
-page_open(["sess" => "Seminar_Session", "auth" => "Seminar_Auth", "perm" => "Seminar_Perm", "user" => "Seminar_User"]);
-
-include 'lib/seminar_open.php'; // initialise Stud.IP-Session
-
-$intro_text = $head_text = '';
-
-$level = Request::option('level');
-$id = Request::option('id');
-
-if ($id) {
-    URLHelper::bindLinkParam('id',$id);
-    URLHelper::bindLinkParam('level',$level);
-}
-
-$group_by = Request::int('group_by', 0);
-
- // store the seleced semester in the session
-if (Request::option('select_sem')) {
-    $_SESSION['_default_sem'] = Request::option('select_sem');
-}
-
-$show_semester = Request::option('select_sem', $_SESSION['_default_sem']);
-$sem_browse_obj = new SemBrowse(['group_by' => 0]);
-$sem_browse_obj->sem_browse_data['default_sem'] = "all";
-$sem_browse_obj->sem_number = false;
-$sem_browse_obj->target_url = "dispatch.php/course/details/";  //teilt der nachfolgenden Include mit, wo sie die Leute hinschicken soll
-$sem_browse_obj->target_id = "sem_id";        //teilt der nachfolgenden Include mit, wie die id die übergeben wird, bezeichnet werden soll
-$sem_browse_obj->sem_browse_data['level'] = $level;
-if ($show_semester) {
-    $sem_number = Semester::getIndexById($show_semester);
-    $sem_browse_obj->sem_browse_data['default_sem'] = $sem_number;
-    $sem_browse_obj->sem_number[0] = $sem_number;
-}
-
-switch ($level) {
-case "sbb":
-    $sem_browse_obj->sem_browse_data['start_item_id'] = $id;
-    $sem_browse_obj->get_sem_range($id, false);
-    $sem_browse_obj->show_result = true;
-    $sem_browse_obj->sem_browse_data['sset'] = false;
-
-    $the_tree = $sem_browse_obj->sem_tree->tree;
-    $bereich_typ = _("Studienbereich");
-    $head_text = _("Übersicht aller Veranstaltungen eines Studienbereichs");
-    $intro_text = sprintf(_("Alle Veranstaltungen, die dem Studienbereich: <br><b>%s</b><br> zugeordnet wurden."),
-        htmlReady($the_tree->getShortPath($id)));
-    $excel_text = strip_tags(DecodeHtml($intro_text));
-    break;
-case "s":
-    $db = DBManager::get();
-    $bereich_typ=_("Einrichtung");
-    $head_text = _("Übersicht aller Veranstaltungen einer Einrichtung");
-    $intro_text = sprintf(_("Alle Veranstaltungen der Einrichtung: <b>%s</b>"), htmlReady(Institute::find($id)->name));
-    $excel_text = strip_tags(DecodeHtml($intro_text));
-
-    $parameters = [$id];
-    if ($show_semester) {
-        $query = "SELECT seminar_inst.seminar_id
-                  FROM seminar_inst
-                  LEFT JOIN seminare AS s ON (seminar_inst.seminar_id = s.Seminar_id)
-                  LEFT JOIN semester_courses ON (semester_courses.course_id = s.Seminar_id)
-                  WHERE (
-                          semester_courses.semester_id = ?
-                          OR semester_courses.semester_id IS NULL
-                      )
-                      AND seminar_inst.Institut_id = ?";
-        array_unshift($parameters, $show_semester);
-    } else {
-        $query = "SELECT seminar_inst.seminar_id
-                  FROM seminar_inst
-                  LEFT JOIN seminare AS s ON (seminar_inst.seminar_id = s.Seminar_id)
-                  WHERE seminar_inst.Institut_id = ?";
-    }
-    if (!$GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM)) {
-        $query .= " AND s.visible = 1";
-    }
-    $statement = DBManager::get()->prepare($query);
-    $statement->execute($parameters);
-    $seminar_ids = $statement->fetchAll(PDO::FETCH_COLUMN);
-    $sem_browse_obj->sem_browse_data['search_result'] = array_flip($seminar_ids);
-    $sem_browse_obj->show_result = true;
-    break;
-}
-
-PageLayout::setHelpKeyword("Basis.Informationsseite");
-PageLayout::setTitle(($level == "s" ? Context::getHeaderLine() ." - " : "").$head_text);
-if ($level == "s" && Context::getId() && Context::isInstitute()) {
-    Navigation::activateItem('/course/main/courses');
-}
-
-$sidebar = Sidebar::get();
-$semester = new SelectWidget(_("Semester:"), URLHelper::getURL(), 'select_sem');
-foreach (array_reverse(Semester::getAll()) as $one) {
-    $semester->addElement(new SelectElement($one->id, $one->name, $one->id == $show_semester));
-}
-$sidebar->addWidget($semester);
-$grouping = new LinksWidget();
-$grouping->setTitle(_("Anzeige gruppieren:"));
-foreach ($sem_browse_obj->group_by_fields as $i => $field){
-    $grouping->addLink(
-        $field['name'],
-        URLHelper::getURL('?', ['group_by' => $i]),
-        $group_by == $i ? Icon::create('arr_1right', 'attention') : null
-    );
-}
-$sidebar->addWidget($grouping);
-
-
-?>
-<div><?= $intro_text ?></div>
-<? $sem_browse_obj->print_result(); ?>
-
-<?php
-$layout = $GLOBALS['template_factory']->open('layouts/base.php');
-
-$layout->content_for_layout = ob_get_clean();
-
-echo $layout->render();
-page_close();
diff --git a/templates/sembrowse/quick-search.php b/templates/sembrowse/quick-search.php
deleted file mode 100644
index dbf6e2f..0000000
--- a/templates/sembrowse/quick-search.php
+++ /dev/null
@@ -1,65 +0,0 @@
-<?= $search_obj->getFormStart(URLHelper::getLink(), ['class' => 'default']) ?>
-
-<fieldset>
-    <legend>
-        <?= $GLOBALS['SEM_CLASS'][$_SESSION['sem_portal']["bereich"]]["description"]
-                ?: _('Suche nach Veranstaltungen') ?>
-    </legend>
-
-    <label class="col-3">
-        <?= _('Suchbegriff') ?>
-        <?= $quicksearch->render() ?>
-    </label>
-
-    <label class="col-3">
-        <?= _('Suchen in') ?>
-        <?= $search_obj->getSearchField('qs_choose', [ 'id' => 'search_sem_qs_choose' ]) ?>
-    </label>
-
-    <? if ($sem_browse_data['level'] === 'vv'): ?>
-        <label class="col-3">
-            <?= _('in') ?>
-            <?= $search_obj->getSearchField('scope_choose', [ 'id' => 'search_sem_scope_choose' ] ,$sem_tree->start_item_id) ?>
-            <input type="hidden" name="level" value="vv">
-        </label>
-    <? endif; ?>
-
-    <? if ($sem_browse_data['level'] === 'ev'): ?>
-        <label class="col-3">
-            <?=  _('in') ?>:
-            <?= $search_obj->getSearchField('range_choose', [ 'id' => 'search_sem_range_choose', ], $range_tree->start_item_id) ?>
-            <input type="hidden" name="level" value="ev">
-        </label>
-    <? endif; ?>
-
-    <input type="hidden" name="search_sem_sem" value="<?= htmlReady($_SESSION['sem_browse_data']['default_sem']) ?>">
-</fieldset>
-
-<footer>
-    <span class="button-group">
-        <?= $search_obj->getSearchButton(
-            [
-                'style' => 'vertical-align:middle',
-                'class' => 'quicksearchbutton',
-            ],
-            true
-        ) ?>
-        <?
-        $option = Request::get('option');
-        $nav = SemBrowse::getSearchOptionNavigation(
-                Config::get()->COURSE_SEARCH_NAVIGATION_OPTIONS[$option]['target'], $option);
-        $url = $nav ? $nav->getUrl() :   URLHelper::getUrl('',
-                [
-                    'level' => $_SESSION['sem_browse_data']['level'],
-                    'cmd'   => 'qs'
-                ]);
-        ?>
-        <?= Studip\LinkButton::create(
-            _('Zurücksetzen'),
-            URLHelper::getURL($url, ['reset_all' => 1]),
-            ['title' => _('Zurücksetzen')]
-        ) ?>
-    </span>
-</footer>
-
-<?= $search_obj->getFormEnd() ?>
diff --git a/tests/unit/lib/classes/MarkupClassTest.php b/tests/unit/lib/classes/MarkupClassTest.php
index 347e453..cba0009 100644
--- a/tests/unit/lib/classes/MarkupClassTest.php
+++ b/tests/unit/lib/classes/MarkupClassTest.php
@@ -22,7 +22,6 @@ require_once 'tests/unit/fakeserver.php';
 
 # needed by visual.inc.php
 require_once 'lib/classes/DbView.php';
-require_once 'lib/classes/TreeAbstract.php';
 
 # needed by Markup.php
 require_once 'lib/visual.inc.php';
-- 
cgit v1.0

