
import { LasalRuntimeSigElement, SigPolymer } from '../../sigmatek/sig-element/sig-element.js';
import { Filemanager } from './sig-control-filemanager-mixin.js';
import './sig-control-filemanager-tree.js';
import "../sig-control-titlebar/sig-control-titlebar.js";
import "../sig-control-titlebar/sig-control-titlebar-css.js";
import "../sig-control-button/sig-control-button.js";
import "../sig-control-button/sig-control-button-css.js";
import "../sig-control-input/sig-control-input.js";
import "../sig-control-input/sig-control-input-css.js";
import "../sig-control-listview/sig-control-listview.js";
import "../sig-control-listview/sig-control-listview-css.js";

import './moment-with-locales.js';

/******************************************************************************************************************************************************************************************************
 * @class
 * @classdesc Implements sig-control-filemanager.
 * @mixes Filemanager
 * @extends {LasalRuntimeSigElement}
 * 
 * @property {Number} queueInterval The reference number returned by setInterval, after setting up the queue interval.
 * @property {Number} queueIntervalDelay The delay in milliseconds, the queue checks for a new command.
 * @property {Boolean} queueActive If true the queue is currently executing a command.
 * @property {Object} queueActiveCommand The reference to the currently executed command object.
 * @property {Boolean} queueRunning If true the queue is running and will process the commands in the queue.
 * @property {Object} wmApi The reference to the Window Manager API.
 * @property {Object} fmApi The reference to the File Manager API.
 * @property {Object} utilsApi The reference to the Utils API.
 * @property {Object} tmApi The reference to the Text Manager API.
 * @property {Object} gridConfig The configuration data of the listview.
 * @property {Number} iswaitingTimeout The reference number returned by setTimeout, after setting up the isWaiting timeout.
 * @property {Number} iswaitingDelay The delay in milliseconds until the progess dialog is shown.  
 * @property {Number} statusAutoClearTimeout The delay in milliseconds until the status message is cleared.
 * @property {String} defaultStatus The text of the default status message.
 * @property {String} controlTextList The name of the text list which contains the translated texts. 
 * @property {Number} refreshCount This counter is increased each time the current pane is refreshed.
 * @property {Number} refreshCountMax This defines how many time a refresh of the same pane is allowed, before the current pane is redirected to the filesystem root. 
 * @property {Boolean} toolbarsFirstRenderDone If true the toolbar buttons have been rendered for the first time.
 * @property {String} validStartPathLeft The valid start path of the left pane.
 * @property {String} validStartPathRight The valid start path of the right pane.
 * @property {String} fileFolderSeparator This text is used to separate files and folder of the polymer properties 'leftactiveselectiondata' and 'rightactiveselectiondata'
 * @property {String} itemSeparator This text is used to separate each item of files and folder of the polymer properties 'leftactiveselectiondata' and 'rightactiveselectiondata'
****************************************************************************************************/
export class LasalRuntimeSigControlFilemanager extends Filemanager(LasalRuntimeSigElement) {

    /******************************************************************************************************************************************************************************************************
     * Returns the components registered tag name.
     *
     * @readonly
     * @static
     * @returns {string} The controls tag name.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    static get is() {
        return "sig-control-filemanager";
    }

    /******************************************************************************************************************************************************************************************************
     * Returns the the import path url used by Polymer.
     *
     * @readonly
     * @static
     * @returns {string} The import path url.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    static get importMeta() { return import.meta; }

    /******************************************************************************************************************************************************************************************************
     * Returns the HTML literal of the component.
     *
     * @readonly
     * @static
     * @returns {HTMLLIElement} The template literal of the component.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    static get template() {
        return SigPolymer.html`
            <style
            include="sig-element-css sig-control-titlebar-css sig-control-button-css sig-control-input-css sig-control-listview-css">
            :host {
                /* Basic styling of the component */
                color: var(--theme-sig-control-filemanager-color, rgba(255, 255, 255, 1));
                background-color: var(--theme-sig-control-filemanager-background-color, rgba(42, 42, 42, 1));
                border-width: var(--theme-sig-control-filemanager-border-width, 0);
                border-color: var(--theme-sig-control-filemanager-border-color, transparent);
                border-style: var(--theme-sig-control-filemanager-border-style, none);
                border-radius: var(--theme-sig-control-filemanager-border-radius, 0);

                /* Basic box model settings */
                display: block;
                position: absolute;
                overflow: hidden;

                --theme-sig-control-filemanager-pathbar-height-half: calc(var(--theme-sig-control-filemanager-pathbar-height, 26px) / 2);
            }

            :host * {
                /* Reset margin and padding for child elements and turn off text selection */
                @apply --notextselect;
                margin: 0;
                padding: 0;
            }

            .clearfix:after {
                /* Import the global clearfix css mixin */
                @apply --clearfix
            }

            #fm {
                position: relative;
                height: 100%;
                min-height: 100%;
                display: flex;
                flex-direction: column; 
            }

            #pathbar {
                background: var(--theme-sig-control-filemanager-pathbar-background-color, rgba(42, 42, 42, 1));
                color: var(--theme-sig-control-filemanager-pathbar-color, rgba(177, 177, 176, 1));
                border-bottom: 1px solid var(--theme-sig-control-filemanager-pathbar-horizontal-separator-color, rgba(86, 89, 97, 1));
                height: calc(var(--theme-sig-control-filemanager-pathbar-height, 26px) - 1px + var(--theme-sig-control-filemanager-pathbar-scrollbar-height, 5px));
                position: relative;
                overflow-x: scroll;
                overflow-y: hidden;
            }

            #pathbar::-webkit-scrollbar {
                width: 5px;
                height: var(--theme-sig-control-filemanager-pathbar-scrollbar-height, 5px);
            }

            #pathbar::-webkit-scrollbar-button {
                display: none;
            }

            #pathbar::-webkit-scrollbar-thumb {
                background: var(--theme-sig-control-filemanager-pathbar-scrollbar-thumb-background-color, rgba(174, 200, 26, 1));
                border: 1px solid var(--theme-sig-control-filemanager-pathbar-scrollbar-thumb-background-color, rgba(174, 200, 26, 1));
                border-radius: 0;
            }

            #pathbar::-webkit-scrollbar-thumb:hover {
                background: var(--theme-sig-control-filemanager-pathbar-scrollbar-thumb-background-color, rgba(174, 200, 26, 1));
            }

            #pathbar::-webkit-scrollbar-thumb:active {
                background: var(--theme-sig-control-filemanager-pathbar-scrollbar-thumb-background-color, rgba(174, 200, 26, 1));
            }

            #pathbar::-webkit-scrollbar-track {
                background: var(--theme-sig-control-filemanager-pathbar-scrollbar-track-background-color, rgba(64, 66, 72, 1));
                border: 0px none transparent;
                border-radius: 0;
            }

            #pathbar::-webkit-scrollbar-track:hover {
                background: var(--theme-sig-control-filemanager-pathbar-scrollbar-track-background-color, rgba(64, 66, 72, 1));
            }

            #pathbar::-webkit-scrollbar-track:active {
                background: var(--theme-sig-control-filemanager-pathbar-scrollbar-track-background-color, rgba(64, 66, 72, 1));
            }

            #pathbar::-webkit-scrollbar-corner {
                background: var(--theme-sig-control-filemanager-pathbar-scrollbar-track-background-color, transparent);
            }

            #toolbar {
                background: var(--theme-sig-control-filemanager-toolbar-background-color, rgba(42, 42, 42, 1));
                border-bottom: 1px solid var(--theme-sig-control-filemanager-toolbar-horizontal-separator-color, rgba(86, 89, 97, 1));
                height: auto;
            }

            #panes {
                display: flex;
                flex-flow: row nowrap;
                width: 100%;
                height: 100%;
                background-color: transparent;
            }

            :host([dualpaneview="column"]) #panes {
                display: flex;
                flex-flow: column nowrap;
                width: 100%;    
                height: 100%;
                background-color: transparent;
            }

            #panefolders {
                background-color: var(--theme-sig-control-filemanager-pane-folders-background-color, rgba(160, 160, 160, 1));
                width: 20%;
                overflow: hidden;
                position: relative;
            }

            #paneleft {
                background-color: var(--theme-sig-control-filemanager-pane-left-background-color, rgba(160, 160, 160, 1));
                flex: 1 1 100%;
                overflow: hidden;
                position: relative;
                vertical-align: top;
                text-align: left;
            }

            :host([dualpaneview="column"]) #paneleft{
                background-color: var(--theme-sig-control-filemanager-pane-left-background-color, rgba(160, 160, 160, 1));
                flex: 1 1 100%;
                overflow: hidden;
                position: relative;
                vertical-align: top;
                text-align: left;
            }

            #panemiddle {
                background-color: var(--theme-sig-control-filemanager-actionbar-background-color, rgba(160, 160, 160, 1));
                flex: 0 0 auto;
                overflow: hidden;
                position: relative;
                display: none;
                vertical-align: top;
                text-align: center;
                width: var(--theme-sig-control-filemanager-actionbar-min-width, 36px);
                border-left: 1px solid var(--theme-sig-control-filemanager-actionbar-vertical-separator-color, rgba(64, 66, 72, 1));
                border-right: 1px solid var(--theme-sig-control-filemanager-actionbar-vertical-separator-color, rgba(64, 66, 72, 1));
            }

            :host([dualpaneview="column"]) #panemiddle{
                background-color: var(--theme-sig-control-filemanager-actionbar-background-color, rgba(160, 160, 160, 1));
                flex: 0 0 auto;
                width: 100%;
                overflow: hidden;
                position: relative;
                display: none;
                vertical-align: top;
                text-align: center;
                height: var(--theme-sig-control-filemanager-actionbar-min-width, 36px);
                border: none;
                border-top: 1px solid var(--theme-sig-control-filemanager-actionbar-vertical-separator-color, rgba(64, 66, 72, 1));
                border-bottom: 1px solid var(--theme-sig-control-filemanager-actionbar-vertical-separator-color, rgba(64, 66, 72, 1));
            }

            #paneright {
                background-color: var(--theme-sig-control-filemanager-pane-right-background-color, rgba(160, 160, 160, 1));
                flex: 1 1 100%;
                display: none;
                position: relative;
                overflow: hidden;
                vertical-align: top;
                text-align: left;
            }

            :host([dualpaneview="column"]) #paneright{
                background-color: var(--theme-sig-control-filemanager-pane-right-background-color, rgba(160, 160, 160, 1));
                flex: 1 1 100%;
                display: none;
                position: relative;
                overflow: hidden;
                vertical-align: top;
                text-align: left;
            }

            #actionbar{
                display: flex;
                flex-flow: column nowrap;
            }

            :host([dualpaneview="column"]) #actionbar{
                display: flex;
                flex-flow: row nowrap;
                height: 100%;
                align-items: center;
            }

            :host sig-control-input.filefilter {
                position: unset;
                top: unset;
                left: unset;
                height: var(--theme-sig-control-filemanager-pane-path-height,var(--theme-sig-element-height, 26px));
                width: var(--theme-sig-element-width, 50px);
                text-indent: 0;
            }

            :host([activepane=left][dualpane]) #pathleft,
            :host([activepane=right]) #pathright {
                background-color: var(--theme-sig-control-filemanager-pane-path-active-background-color,rgba(160, 160, 160, 1));
                color: var(--theme-sig-control-filemanager-pane-path-active-color, rgba(255, 255, 255, 1));
            }

            .files {
                width: 100%;
                height: calc(100% - var(--theme-sig-control-filemanager-pane-path-height, 26px));
                overflow: hidden;
                position: absolute;
                left: 0;
                top: var(--theme-sig-control-filemanager-pane-path-height, 26px);
            }

            :host([hidepanepath]) .files {
                height: 100%;
                top: 0;
            }

            .tree {
                width: 100%;
                height: 100%;
                overflow: auto;
                position: absolute;
                left: 0;
                top: 0;
            }

            :host([dualpane]) #paneright,
            :host([dualpane]) #panemiddle {
                display: table-cell !important;
            }

            :host([hidepathbar]) #pathbar {
                display: none;
            }

            :host([hidetoolbar]) #toolbar {
                display: none;
            }

            :host([hideactionbar]) #actionbar {
                display: none;
            }
            
            :host([hideactionbar]) #panemiddle {
                min-width: 1%;
            }

            :host([hideactionbar][dualpaneview="column"]) #panemiddle {
                min-height: 1%;
            }

            :host([hidestatusbar]) #statusbar {
                display: none;
            }

            :host([hidetitlebar]) #titlebar {
                display: none;
            }

            :host([hidefolders]) #panefolders {
                display: none;
            }

            :host(:not([isactive])) #fm {
                opacity: .8;
            }

            :host([hidefilefilters]) .filefilter {
                display: none;
            }

            :host([hidepanepath]) .path {
                display: none;
            }

            .toolbutton {
                float: left;
                top: unset;
                left: unset;
                position: relative;
                margin: 2px var(--theme-sig-control-filemanager-toolbar-button-spacing, 2px) !important;
            }

            .actionbutton {
                margin: var(--theme-sig-control-filemanager-actionbar-button-spacing, 2px) auto !important; 
                top: unset;
                left: unset;
                position: relative;
                overflow: hidden;
            }

            :host([dualpaneview="column"]) .actionbutton {
                margin: 2px var(--theme-sig-control-filemanager-actionbar-button-spacing, 2px) !important; 
                top: unset;
                left: unset;
                position: relative;
                overflow: hidden;
            }

            ul.arrows {
                position: absolute;
                overflow: hidden;
                height: calc(var(--theme-sig-control-filemanager-pathbar-height, 26px) - 1px);
                white-space: nowrap;
                width: auto;
                padding-right: var(--theme-sig-control-filemanager-pathbar-height-half) !important;
                text-decoration: inherit;
            }

            :host([isdesignmode]) ul.arrows {
                width: 150%;
            }

            .arrows li {
                list-style-type: none;
                display: inline-block;
                width: auto;
                cursor: pointer;
                background: var(--theme-sig-control-filemanager-pathbar-selected-background-color, rgba(64, 66, 72, 1));
                color: var(--theme-sig-control-filemanager-pathbar-selected-color, rgba(177, 177, 176, 1));
                line-height: calc(var(--theme-sig-control-filemanager-pathbar-height, 26px) - 1px);
                padding: 0 10px 0 var(--theme-sig-control-filemanager-pathbar-height, 26px) !important;
                position: relative;
                text-decoration: inherit;
                height: auto;
            }

            .arrows li:after {
                position: absolute;
                width: 0;
                height: 0;
                content: '';
                border-top: var(--theme-sig-control-filemanager-pathbar-height-half) solid transparent;
                border-bottom: var(--theme-sig-control-filemanager-pathbar-height-half) solid transparent;
                border-left: var(--theme-sig-control-filemanager-pathbar-height-half) solid var(--theme-sig-control-filemanager-pathbar-selected-background-color, rgba(64, 66, 72, 1));
                right: calc(var(--theme-sig-control-filemanager-pathbar-height-half) * -1 + 3px);
                z-index: 3;
            }

            .arrows li span {
                position: relative;
                text-decoration: inherit;
                display: inline-block;
            }

            .arrows li span:after {
                position: absolute;
                width: 0;
                height: 0;
                content: '';
                border-top: var(--theme-sig-control-filemanager-pathbar-height-half) solid transparent;
                border-bottom: var(--theme-sig-control-filemanager-pathbar-height-half) solid transparent;
                border-left: var(--theme-sig-control-filemanager-pathbar-height-half) solid var(--theme-sig-control-filemanager-pathbar-selected-symbol-color, rgba(177, 177, 176, 1));
                right: calc((var(--theme-sig-control-filemanager-pathbar-height-half) + 10px) * -1);
                z-index: 2;
            }

            .arrows li.first {
                padding-left: 10px !important;
            }

            .arrows li.last {
                background-color: transparent;
                pointer-events: none;
                color: inherit;
            }

            .arrows li.last:after,
            .arrows li.last span:after {
                display: none;
            }

            #titlebar {
                position: unset;
            }

            #titlebar .inactive {
                text-transform: initial;
                opacity: .6;
            }

            #statusbar {
                --theme-sig-control-filemanager-footer-height-calced: calc(var(--theme-sig-control-filemanager-footer-height, 26px) - 1px);
                height: var(--theme-sig-control-filemanager-footer-height-calced);
                line-height: var(--theme-sig-control-filemanager-footer-height-calced);
                color: var(--theme-sig-control-filemanager-footer-color, rgba(160, 160, 160, 1));
                background-color: var(--theme-sig-control-filemanager-footer-background-color, rgba(64, 66, 72, 1));
                border-top: 1px solid var(--theme-sig-control-filemanager-footer-horizontal-separator-color, rgba(64, 66, 72, 1));
                padding: 0 5px;
                position: relative;
                width: 100%;
            }

            #spinner {
                display: none;
                right: 10px;
                position: absolute;
                top: calc(var(--theme-sig-control-filemanager-footer-height, 26px)/2 - var(--theme-sig-control-filemanager-footer-spinner-size, 25px)/2);
                stroke: var(--theme-sig-control-filemanager-footer-spinner-color, rgba(215, 215, 215, 1));
                width: var(--theme-sig-control-filemanager-footer-spinner-size, 25px);
                height: var(--theme-sig-control-filemanager-footer-spinner-size, 25px);
                background: none;
            }

             :host(:not([isdesignmode])) .spinneranimation {
                animation: 1s linear infinite spin;
            }

            :host([iswaiting]) #spinner,
            :host([isdesignmode]) #spinner {
                display: block;
            }

            @keyframes spin {
                0% { transform: rotate(0deg); }
                100% { transform: rotate(360deg); }
            }

            .path {
                overflow: hidden;
                height: var(--theme-sig-control-filemanager-pane-path-height, 26px);
                line-height: var(--theme-sig-control-filemanager-pane-path-height, 26px);
                text-indent: 5px;
                background-color: var(--theme-sig-control-filemanager-pane-path-background-color, rgba(160, 160, 160, 1));
                color: var(--theme-sig-control-filemanager-pane-path-color, rgba(64, 66, 72, 1));
                border-bottom: 1px solid rgba(64, 66, 72, 1);
                position: absolute;
                width: 100%;
            }

            .path .left {
                float: left;
                position: absolute;
                width: calc(100% - 55px);
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: nowrap;
                text-decoration: inherit;
            }

            :host([hidefilefilters]) .path .left {
                width: 100%;
            }

            .path .right {
                float: right;
                text-decoration: inherit;
            }

            #wait {
                position: absolute;
                display: none;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background: transparent none;
                z-index: 2000;
            }

             :host([isdesignmode]) #wait {
                 z-index: 200;
             }

            :host([showiswaiting]) #wait {
                display: block;
            }

            :host([showprogress]) #wait,
            :host(:not([isonline])) #wait {
                background-color: var(--theme-sig-control-filemanager-progress-dialog-modal-background-color, rgba(215, 215, 215, 1));
            }

            .disabled {
                opacity: .5;
                pointer-events: none;
            }

            #progressbox {
                position: absolute;
                background-color: var(--theme-sig-control-filemanager-progress-dialog-background-color, rgba(42, 42, 42, 1));
                color: var(--theme-sig-control-filemanager-progress-dialog-color, rgba(255, 255, 255, 1));
                top: 0;
                left: 0;
                right: 0;
                bottom: 0;
                margin: auto;
                width: 80%;
                height: var(--theme-sig-control-filemanager-progress-dialog-height, 120px);
                min-height: 120px;
                display: none;
                overflow: hidden;
            }

            :host([showprogress]:not([progresswindowset])) #progressbox {
                display: block;
            }

            :host([isdesignmode]) #progressbox {
                pointer-events: none;
            }

            .progressbarouter {
                left: 0;
                bottom: 60px;
                position: absolute;
                overflow: hidden;
                width: 100%;
                height: calc(var(--theme-sig-control-filemanager-progress-dialog-height, 120px) - 60px - 25px - 10px);
                text-decoration: inherit;
            }

            .progressbarinner {
                top: 0;
                left: 0;
                position: relative;
                margin: 0 10px !important;
                width: calc(100% - 20px);
                height: 100%;
                text-decoration: inherit;
            }

            .progressbar {
                position: absolute;
                top: 0;
                left: 0;
                height: 100%;
                width: 0;
                overflow: hidden;
                background-color: var(--theme-sig-control-filemanager-progress-dialog-bar-background-color, rgba(160, 160, 160, 1));
                color: var(--theme-sig-control-filemanager-progress-dialog-bar-color, rgba(255, 255, 255, 1));
                line-height: calc(var(--theme-sig-control-filemanager-progress-dialog-height, 120px) - 60px - 25px - 10px);
                text-indent: 5px;
                text-align: center;
                text-decoration: inherit;
            }

            .progressmessage {
                padding: 10px !important;
                position: absolute;
                text-overflow: ellipsis;
                overflow: hidden;
                white-space: nowrap;
                width: calc(100% - 20px);
                height: auto;
                text-decoration: inherit;
            }

            #progressbuttons {
                padding: 10px;
                background-color: var(--theme-sig-control-filemanager-progress-dialog-background-color, rgba(42, 42, 42, 1));
                border-top: 1px solid var(--theme-sig-control-filemanager-progress-dialog-button-horizontal-separator-color, rgba(86, 89, 97, 1));
                width: calc(100% - 20px);
                height: auto;
                position: absolute;
                bottom: 0;
                text-decoration: inherit;
            }

            :host(:not([isonline])) #progressbuttons {
                display: none;
            }

            .progressbutton {
                float: right;
                padding: 5px 10px !important;
                cursor: pointer;
                text-align: center;
                margin-left: 10px !important;
                border-radius: 3px;
                color: var(--theme-sig-control-filemanager-progress-dialog-button-color, rgba(160, 160, 160, 1));
                background-color: var(--theme-sig-control-filemanager-progress-dialog-button-background-color, rgba(64, 66, 72, 1));
                width: calc(var(--theme-sig-control-filemanager-progress-dialog-button-width, auto) - 20px);
                height: calc(var(--theme-sig-control-filemanager-progress-dialog-button-height, auto) - 10px);
                text-decoration: inherit;
                line-height: calc(var(--theme-sig-control-filemanager-progress-dialog-button-height, auto) - 10px);
            }

            .progressbutton:active {
                color: var(--theme-sig-control-filemanager-progress-dialog-button-pressed-color, rgba(42, 42, 42, 1));
                background-color: var(--theme-sig-control-filemanager-progress-dialog-button-pressed-background-color, rgba(215, 215, 215, 1));
            }

            .progressstatus {
                float: left;
                vertical-align: middle;
                font-size: 12px;
            }

            :host sig-control-button.toolbutton {
                height: var(--theme-sig-element-height, 30px);
                width: var(--theme-sig-element-width, 30px);
            }

            :host sig-control-button.actionbutton {
                height: var(--theme-sig-element-height, 30px);
                width: var(--theme-sig-element-width, 30px);
                --theme-sig-control-button-padding: 2px;
            }

            :host sig-control-input {
                height: var(--theme-sig-element-height, 26px);
            } 

           :host sig-control-titlebar {
                position: unset;
                display: block;
                width:100%;
                height: var(--theme-sig-element-height, 26px);
                --theme-sig-control-filemanger-titlebar-height: var(--theme-sig-element-height, 26px);
            }

            :host sig-control-listview {
                --theme-sig-control-list-view-folder-icon-color: var(--theme-sig-control-filemanager-folder-icon-color, rgba(255, 165, 0, 1));
                --theme-sig-control-list-view-folder-up-icon-color: var(--theme-sig-control-filemanager-folder-up-icon-color, rgba(0, 0, 0, 1));
                --theme-sig-control-list-view-file-icon-color: var(--theme-sig-control-filemanager-file-icon-color, rgba(211, 211, 211, 1));
                --theme-sig-control-list-view-volume-icon-color: var(--theme-sig-control-filemanager-volume-icon-color, rgba(169, 169, 169, 1));
            }

            @-moz-document url-prefix() {
                /*Fix for FF because no scroll bar styling possible */
                #pathbar {
                    height: calc(var(--theme-sig-control-filemanager-pathbar-height, 26px) - 1px + var(--theme-sig-control-filemanager-pathbar-scrollbar-height, 18px));
                }
            }

            .fullheigth {
                flex: 1;
            }
        </style>
        <div id="fm" class="clearfix" on-tap="_activateOnTap">
            <div id="wait">
                <div id="progressbox">
                    <div class="progressbarouter">
                        <div class="progressbarinner">
                            <div id="progressbar" class="progressbar">[[progress]] %</div>
                        </div>
                    </div>
                    <div class="progressmessage">[[status]]</div>
                    <div id="progressbuttons" class="clearfix">
                        <div id="progressstatus" class="progressstatus">[[waitingstatus]]</div>
                        <template is="dom-if" if="[[_canCancel(queueActive, queuestats.count)]]">
                            <div id="cmdCancel" class="progressbutton cancel" on-tap="_queueCancelCommand" title="ESC">
                                [[texts.cancel]]</div>
                        </template>
                        <template is="dom-if" if="[[_canCancelAll(queueActive, queuestats.count)]]">
                            <div id="cmdCancelAll" class="progressbutton cancelall" on-tap="_queueCancelAllCommand"
                                title="C">[[texts.cancelAll]] ([[queuestats.count]])</div>
                        </template>
                        <template is="dom-if" if="[[_canPause(queueActive, queuestats.count)]]">
                            <div id="cmdPause" class="progressbutton pause" on-tap="_queuePause" title="SPACEBAR">
                                [[texts.pause]]</div>
                        </template>
                        <template is="dom-if" if="[[_canContinue(queueActive, queuestats.count, queueRunning)]]">
                            <div id="cmdContinue" class="progressbutton continue" on-tap="_queueContinue"
                                title="SPACEBAR">[[texts.continue]]</div>
                        </template>
                    </div>
                </div>
            </div>
            <sig-control-titlebar id="titlebar" value="[[texts.caption]]" shadowactive="[[titlebarshadowactive]]"
                applybordereffect="[[applybordereffect]]">
            </sig-control-titlebar>
            <div id="pathbar" class="clearfix" on-tap="_handleBarTap"></div>
            <div id="toolbar" class="clearfix" on-tap="_handleBarTap"></div>
            <div class="fullheigth">
            <div id="panes">
                <div id="panefolders">
                    <sig-control-filemanager-tree id="tree" class="tree"></sig-control-filemanager-tree>
                </div>
                <div id="paneleft" class="active" on-mousedown="_togglePaneLeft">
                    <div id="pathleft" class="path" title="[[activepathleft]]">
                        <div class="left">[[activepathleft]]</div>
                        <div class="right">
                            <sig-control-input id="filefilterleft" class="filefilter" value="{{filefilterleft}}"
                                titletext="[[texts.filterTitle]]" placeholder="[[texts.filter]]">
                            </sig-control-input>
                        </div>
                    </div>
                    <sig-control-listview id="filesleft" class="files"></sig-control-listview>
                </div>
                <div id="panemiddle">
                    <div id="actionbar" on-tap="_handleBarTap">
                    </div>
                </div>
                <div id="paneright" on-mousedown="_togglePaneRight">
                    <div id="pathright" class="path">
                        <div class="left">[[activepathright]]</div>
                        <div class="right">
                            <sig-control-input id="filefilterright" class="filefilter" value="{{filefilterright}}"
                                titletext="[[texts.filterTitle]]" placeholder="[[texts.filter]]">
                            </sig-control-input>
                        </div>
                    </div>
                    <sig-control-listview id="filesright" class="files"></sig-control-listview>
                </div>
            </div>
            </div>
            <div id="statusbar">
                [[status]] [[progressc]]
                <svg id="spinner" width="200px" height="200px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"
                    preserveAspectRatio="xMidYMid" class="spinneranimation">
                    <circle cx="50" cy="50" fill="none" stroke-width="10" r="20"  stroke-dasharray="94.24777960769379 33.41592653589793" transform="rotate(126 50 50)"></circle>
                </svg>
            </div>
        </div>
        `;
    }

    /******************************************************************************************************************************************************************************************************
     * Returns the defined polymer properties of the component.
     * 
     * @readonly
     * @static
     * @returns {Object} The defined polymer properties.
     * @memberof LasalRuntimeSigControlFilemanager
     * 
     * @property {Boolean} dualpane  If true, the file manager has two panes.
     * @property {String} dualpaneview  Specifies if the panes are displayed in a row or a column.
     * @property {Boolean} hidepathbar If true, the pathbar is hidden.
     * @property {Boolean} hidetoolbar If true, the toolbar is hidden.
     * @property {Boolean} hidepanepath If true, the pane path is hidden.
     * @property {Boolean} hideactionbar If true, the action bar is hidden.
     * @property {Boolean} hidestatusbar If true, the status bar is hidden.
     * @property {Boolean} hidetitlebar If true, the title bar is hidden.
     * @property {Boolean} hidefilefilters If true, the file filters are hidden. Note: This property is currently not exported in the json description.
     * @property {Boolean} hidefolders If true, the folder tree is hidden. Note: The folder tree is not implemented, so leave this value untouched.
     * @property {String} activepane A string 'left' or 'right', which represents the current active pane.
     * @property {String} status A string containing the message, which currently is displayed in the status bar.
     * @property {String} waitingstatus A string containing the status message, which is currently displayed in the progess dialog.
     * @property {Boolean} isactive If true, the control is active and accepts input.
     * @property {String} startpathleft A unix style path, loaded on startup in the left pane.
     * @property {String} startpathright A unix style path, loaded on startup in the right pane.
     * @property {String} activepathleft  A unix style path, which is currently active in the left pane.
     * @property {String} activepathright A unix style path, which is currently active in the right pane.
     * @property {String} currentpath A unix style path, representing the path of the currently active pane.
     * @property {Boolean} iswaiting If true, this indicates the queue is waiting for the next command.
     * @property {Array} clipboard Contains the paths of all the files and folders currently in the clipboard.
     * @property {String} clipboardmode A string, either "copy" of "cut", representing the current mode of the clipboard.
     * @property {String} allowedvolumes A comma seperated string of volume labels like "C,D" .... which may show up in the panes. If left blank, all volumes are allowed. Note: This is only for development!
     * @property {Number} progress The progress count in percentage returned by the api during a file operation.
     * @property {String} progressc The calculated string of the progress property, which is showed in the template.
     * @property {Object} texts An object containing the text strings for the current language.
     * @property {Array} queue This array is holding all file manager command objects.
     * @property {Object} queuestats An object containing status properties of the queue. The current available property is "count". 
     * @property {Boolean} isonline If true, the file manager has a working dataservice connection. 
     * @property {Boolean} showiswaiting If true, the file manager waiting screen is shown.
     * @property {Boolean} showprogress If true, the progress dialog is shown.
     * @property {Boolean} allowmultiselection If true, it is possible to select multiple files and folders in both panes.
     * @property {Boolean} disableautodeactivate If true, the file manager stays active if you click outside the control and still listen to keyboard strokes.
     * @property {Boolean} disablekeyactions If true, all the keyboard shortcuts for actions are disabled in both panes.
     * @property {Boolean} disablekeymovement If true, the cursor control is disabled in both panes.
     * @property {Boolean} disablekeysindialogs If true, the keyboard shortcuts are disabled while a dialog is opened.
     * @property {Boolean} nofolders If true, no folders are listed.
     * @property {Boolean} nofiles If true, no files are listed.
     * @property {Object} activerow An object with two properties "left" and "right" containing the row data of the current active row.
     * @property {Object} activeselection An object with two properties "left" and "right", each containing an array of row data objects of the current active and all marked rows.
     * @property {Boolean} hidetoolreload If true, the "Reload" toolbar button is hidden.
     * @property {Boolean} hidetoolcopypaste If true, the "Copy & Paste" toolbar button is hidden.
     * @property {Boolean} hidetoolcreatefolder If true, the "Create Folder" toolbar button is hidden.
     * @property {Boolean} hidetooldelete If true, the "Delete" toolbar button is hidden.
     * @property {Boolean} hidetoolrename If true, the "Rename" toolbar button is hidden.
     * @property {Boolean} hideactionmoveselection If true, the "Move selection" toolbar button is hidden.
     * @property {Boolean} hideactioncopyselection If true, the "Copy selection" toolbar button is hidden.
     * @property {Boolean} hideactionfolderup If true, the "Folder up" toolbar button is hidden.
     * @property {Boolean} systemWindowOpened If true, this indicates a system dialog is opened.
     * @property {Boolean} showsystemnodes If true, system nodes are listed in both panes. 
     * @property {Boolean} showhiddennodes If true, hidden nodes are listed in both panes.
     * @property {String} filefilterleft A javascript regular expression to filter the files of the left pane.
     * @property {String} filefilterright A javascript regular expression to filter the files of the right pane. 
     * @property {Boolean} designtimeshowprogress If true, the progress dialog shows up while in design mode.      
     * @property {Boolean} inputfieldshadowactive Obsolete property, may be removed in future development.      
     * @property {Boolean} titlebarshadowactive Obsolete property, may be removed in future development.          
     * @property {Boolean} applybordereffect Obsolete property, may be removed in future development.          
     * @property {String} titletext The text shown on the titlebar.      
     * @property {Boolean} lockstartpathleft If true, the startpath of the left pane is locked.      
     * @property {Boolean} lockstartpathright If true, the startpath of the right pane is locked.      
     * @property {Number} maxnavlevelsleft The number of levels you can navigate deeper into the file tree of the left pane. 
     * @property {Number} maxnavlevelsright The number of levels you can navigate deeper into the file tree of the right pane.
     * @property {String} leftactivepathdata Contains a string with the current path of the left pane.      
     * @property {String} rightactivepathdata Contains a string with the current path of the right pane.
     * @property {String} leftactivefiledata Contains a string with the name of the current selected file or folder of the left pane.
     * @property {String} rightactivefiledata Contains a string with the name of the current selected file or folder of the right pane.
     * @property {String} leftactiveselectiondata Contains a string of all the currently selected and marked files and folders of the left pane, separated by forward slash.        
     * @property {String} rightactiveselectiondata Contains a string of all the currently selected and marked files and folders of the right pane, separated by forward slash.
     * @property {Boolean} unixpathformat If true, leftactivepathdata and rightactivepathdata use unix notation instead of window notation.
     * @property {Boolean} useprefixes If true prefixes are used for folder, file etc.
     * @property {Boolean} hideparentleft If true left parent will be hidden.
     * @property {Boolean} hideparentright If true right parent will be hidden.
     * @property {Boolean} showsymbol If true column symbol will be shown.
     * @property {Boolean} showfilename If true column filename will be shown.
     * @property {Boolean} showmodified If true column modified will be shown.
     * @property {Boolean} showfilesize If true column filesize will be shown.
     * @property {Boolean} showattributes If true column attributes will be shown.
     * @property {String} symbolcolumntitle The text of the symbol column.
     * @property {String} filenamecolumntitle The text of the filename column.
     * @property {String} modifiedcolumntitle The text of the modified column.
     * @property {String} filesizecolumntitle The text of the filesize column.
     * @property {String} attributescolumntitle The text of the attributes column.
     * @property {String} widthsymbol The width of the symbol column.
     * @property {String} widthfilename The width of the filename column.
     * @property {String} widthmodified The width of the modified column.
     * @property {String} widthfilesize The width of the filesize column.
     * @property {String} widthattributes The width of the attributes column.
     * @property {Number} ordersymbol The order of the symbol column.
     * @property {Number} orderfilename The order of the filename column.
     * @property {Number} ordermodified The order of the modified column.
     * @property {Number} orderfilesize The order of the filesize column.
     * @property {Number} orderattributes The order of the attributes column.
     * @property {Boolean} confirmdelete If true the delete-action must be confirmed.
     * @property {Object} deletewindow The window which will be shown for confirmation. If no window is set, system window is used.
     * @property {Boolean} confirmpaste If true the paste-action must be confirmed.
     * @property {Object} pastewindow The window which will be shown for confirmation. If no window is set, system window is used.
     * @property {Boolean} confirmcopy If true the copy-action must be confirmed.
     * @property {Object} copywindow The window which will be shown for confirmation. If no window is set, system window is used.
     * @property {Boolean} confirmmove If true the move-action must be confirmed.
     * @property {Object} movewindow The window which will be shown for confirmation. If no window is set, system window is used. 
     * @property {Object} progresswindow The window which will be shown as progress window. If no window is set, system window is used. 
     * @property {Boolean} progresswindowset Is set to true if custom progress-window is set.
     * @property {Number} leftactiveselectiondatabitmask The active selection in left pane as a bitmask.
     * @property {Number} rightactiveselectiondatabitmask The active selection in right pane as a bitmask.
     * @property {String} folderimageurl The url of the folder image. If no url is set, default symbol is used.
     * @property {String} folderupimageurl The url of the parent image. If no url is set, default symbol is used.
     * @property {String} fileimageurl The url of the file image. If no url is set, default symbol is used.
     * @property {String} driveimageurl The url of the drive image. If no url is set, default symbol is used.
     * @property {String} datetimeformat The format for the date/time.
    ****************************************************************************************************/
    static get properties() {
        // property names should always be lower case so we
        // can use them directly on the element as an attribute
        let props = {
            dualpane: {
                type: Boolean,
                value: false,
                reflectToAttribute: true
            },
            dualpaneview: {
                type: String,
                value: "row",
                reflectToAttribute: true
            },
            hidepathbar: {
                type: Boolean,
                value: false,
                reflectToAttribute: true
            },
            hidetoolbar: {
                type: Boolean,
                value: false,
                reflectToAttribute: true
            },
            hidepanepath: {
                type: Boolean,
                value: false,
                reflectToAttribute: true
            },
            hideactionbar: {
                type: Boolean,
                value: false,
                reflectToAttribute: true
            },
            hidestatusbar: {
                type: Boolean,
                value: false,
                reflectToAttribute: true
            },
            hidetitlebar: {
                type: Boolean,
                value: false,
                reflectToAttribute: true
            },
            hidefilefilters: {
                type: Boolean,
                value: true,
                reflectToAttribute: true
            },
            hidefolders: {
                type: Boolean,
                value: true,
                reflectToAttribute: true
            },
            activepane: {
                type: String,
                value: "",
                notify: true,
                reflectToAttribute: true,
                observer: '_togglePane'
            },
            status: {
                type: String,
                value: '',
                observer: '_autoClearStatus'
            },
            waitingstatus: {
                type: String,
                value: ''
            },
            isactive: {
                type: Boolean,
                value: false,
                reflectToAttribute: true,
                observer: '_toggleIsActive'
            },
            startpathleft: {
                type: String,
                value: '/',
                observer: '_toggleStartPathLeft'
            },
            startpathright: {
                type: String,
                value: '/',
                observer: '_toggleStartPathRight'
            },
            activepathleft: {
                type: String,
                notify: true,
                value: null,
                observer: '_updatePathLeft'
            },
            activepathright: {
                type: String,
                notify: true,
                value: null,
                observer: '_updatePathRight'
            },
            currentpath: {
                type: String,
                value: null,
                observer: '_renderPath'
            },
            iswaiting: {
                type: Boolean,
                value: false,
                reflectToAttribute: true,
                observer: '_toggleIsWaiting'
            },
            clipboard: {
                type: Array,
                value: () => { return [] },
                observer: '_togglePasteButton'
            },
            progress: {
                type: Number,
                value: 0
            },
            progressc: {
                type: String,
                computed: '_computeProgress(progress)'
            },
            texts: {
                type: Object,
                value: () => { return {} }
            },
            queue: {
                type: Array,
                value: () => { return [] }
            },
            queuestats: {
                type: Object,
                value: () => {
                    return {
                        count: 0
                    }
                }
            },
            isonline: {
                type: Boolean,
                value: true,
                reflectToAttribute: true
            },
            showiswaiting: {
                type: Boolean,
                value: false,
                reflectToAttribute: true
            },
            showprogress: {
                type: Boolean,
                value: false,
                reflectToAttribute: true,
                observer: '_toggleShowProgress'
            },
            allowmultiselection: {
                type: Boolean,
                value: false,
                observer: '_toggleDisableMultiselect'
            },
            disablekeymovement: {
                type: Boolean,
                value: false,
                observer: '_toggleDisableKeyMovement'
            },
            disablekeysindialogs: {
                type: Boolean,
                value: false,
                observer: '_toggleDisableKeysInDialogs'
            },
            activerow: {
                type: Object,
                notify: true,
                value: () => {
                    return {
                        left: null,
                        right: null
                    }
                }
            },
            activeselection: {
                type: Object,
                notify: true,
                value: () => {
                    return {
                        left: null,
                        right: null,
                    }
                }
            },
            hidetoolreload: {
                type: Boolean,
                value: false,
                observer: '_updateButtonVisibility'
            },
            hidetoolcopypaste: {
                type: Boolean,
                value: false,
                observer: '_updateButtonVisibility'
            },
            hidetoolcreatefolder: {
                type: Boolean,
                value: false,
                observer: '_updateButtonVisibility'
            },
            hidetooldelete: {
                type: Boolean,
                value: false,
                observer: '_updateButtonVisibility'
            },
            hidetoolrename: {
                type: Boolean,
                value: false,
                observer: '_updateButtonVisibility'
            },
            hideactionmoveselection: {
                type: Boolean,
                value: false,
                observer: '_updateButtonVisibility'
            },
            hideactioncopyselection: {
                type: Boolean,
                value: false,
                observer: '_updateButtonVisibility'
            },
            hideactionfolderup: {
                type: Boolean,
                value: false,
                observer: '_updateButtonVisibility'
            },
            systemWindowOpened: {
                type: Boolean,
                value: false,
                observer: "_toggleSystemWindowOpened"
            },
            showsystemnodes: {
                type: Boolean,
                value: false,
                observer: '_refreshPanes'
            },
            showhiddennodes: {
                type: Boolean,
                value: false,
                observer: '_refreshPanes'
            },
            filefilterleft: {
                type: String,
                value: '',
                observer: '_refreshPanes'
            },
            filefilterright: {
                type: String,
                value: '',
                observer: '_refreshPanes'
            },
            designtimeshowprogress: {
                type: Boolean,
                value: false,
                reflectToAttribute: true,
                observer: '_designtimeshowprogress'
            },
            inputfieldshadowactive: {
                type: Boolean,
                value: false,
                reflectToAttribute: true
            },
            titlebarshadowactive: {
                type: Boolean,
                value: false,
                reflectToAttribute: true
            },
            applybordereffect: {
                type: Boolean,
                value: false,
            },
            titletext: {
                type: String,
                value: '',
                observer: '_switchLang'
            },
            lockstartpathleft: {
                type: Boolean,
                value: false
            },
            lockstartpathright: {
                type: Boolean,
                value: false
            },
            maxnavlevelsleft: {
                type: Number,
                value: -1
            },
            maxnavlevelsright: {
                type: Number,
                value: -1
            },
            leftactivepathdata: {
                type: String,
                value: "",
                notify: true,
                readOnly: true
            },
            rightactivepathdata: {
                type: String,
                value: "",
                notify: true,
                readOnly: true
            },
            leftactivefiledata: {
                type: String,
                value: "//",
                notify: true,
                readOnly: true
            },
            rightactivefiledata: {
                type: String,
                value: "//",
                notify: true,
                readOnly: true
            },
            leftactiveselectiondata: {
                type: String,
                value: "//",
                notify: true,
                readOnly: true
            },
            rightactiveselectiondata: {
                type: String,
                value: "//",
                notify: true,
                readOnly: true
            },
            /* Column Visibility */
            showsymbol: {
                type: Boolean,
                value: true,
                observer: '_updateColumns'
            },
            showfilename: {
                type: Boolean,
                value: true,
                observer: '_updateColumns'
            },
            filenamefilterable: {
                type: Boolean,
                value: false,
                observer: '_updateColumns'
            },            
            showmodified: {
                type: Boolean,
                value: true,
                observer: '_updateColumns'
            },
            showfilesize: {
                type: Boolean,
                value: true,
                observer: '_updateColumns'
            },
            showattributes: {
                type: Boolean,
                value: true,
                observer: '_updateColumns'
            },
            /* Column Titles */
            symbolcolumntitle: {
                type: String,
                value: '',
                observer: '_updateColumns'
            },
            filenamecolumntitle: {
                type: String,
                value: 'Name',
                observer: '_updateColumns'
            },
            modifiedcolumntitle: {
                type: String,
                value: 'Modified',
                observer: '_updateColumns'
            },
            filesizecolumntitle: {
                type: String,
                value: 'Size',
                observer: '_updateColumns'
            },
            attributescolumntitle: {
                type: String,
                value: 'Attributes',
                observer: '_updateColumns'
            },
            /* Column Width */
            widthsymbol: {
                type: String,
                value: '20px',
                observer: '_updateColumns'
            },
            widthfilename: {
                type: String,
                value: '100px',
                observer: '_updateColumns'
            },
            widthmodified: {
                type: String,
                value: '130px',
                observer: '_updateColumns'
            },
            widthfilesize: {
                type: String,
                value: '50px',
                observer: '_updateColumns'
            },
            widthattributes: {
                type: String,
                value: '40px',
                observer: '_updateColumns'
            },
            /* Column Order */
            ordersymbol: {
                type: Number,
                value: 10,
                observer: '_updateColumns'
            },
            orderfilename: {
                type: Number,
                value: 20,
                observer: '_updateColumns'
            },
            ordermodified: {
                type: Number,
                value: 30,
                observer: '_updateColumns'
            },
            orderfilesize: {
                type: Number,
                value: 40,
                observer: '_updateColumns'
            },
            orderattributes: {
                type: Number,
                value: 50,
                observer: '_updateColumns'
            },
            confirmdelete: {
                type: Boolean,
                value: true,
                reflectToAttribute: true 
            },
            deletewindow: {
                type: Object,
                value: () => { return {} }
            },
            confirmpaste: {
                type: Boolean,
                value: true,
                reflectToAttribute: true 
            },
            pastewindow: {
                type: Object,
                value: () => { return {} }
            },
            confirmcopy: {
                type: Boolean,
                value: true,
                reflectToAttribute: true 
            },
            copywindow: {
                type: Object,
                value: () => { return {} }
            },
            confirmmove: {
                type: Boolean,
                value: true,
                reflectToAttribute: true 
            },
            movewindow: {
                type: Object,
                value: () => { return {} }
            },
            progresswindow: {
                type: Object,
                value: () => { return {} },
                observer: '_checkCustomProgressWindow'    
            },
            progresswindowset: {
                type: Boolean,
                value: false,
                reflectToAttribute: true
            },
            leftactiveselectiondatabitmask: { 
                type: Number,
                value: 0,
                notify: true,
                readOnly: true
            },
            rightactiveselectiondatabitmask: { 
                type: Number,
                value: 0,
                notify: true,
                readOnly: true
            },
            folderimageurl: {
                type: String,
                value: '',
                observer: '_updateColumns',
                notify: true
            },
            folderupimageurl: {
                type: String,
                value: '',
                observer: '_updateColumns',
                notify: true
            },
            fileimageurl: {
                type: String,
                value: '',
                observer: '_updateColumns',
                notify: true
            },
            driveimageurl: {
                type: String,
                value: '',
                observer: '_updateColumns',
                notify: true
            },
            datetimeformat: {
                type: String,
                value: "DD.MM.YYYY HH:mm:ss",
                observer: '_updateColumns'
            }
        }
        return props;
    }

    /****************************************************************************************************
     * Returns the defined complex observers used by Polymer.
     * 
     * @readonly
     * @static
     * @returns {Array} An array containing the defined complex observers.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    static get observers() {
        return [
            '_updateQueue(queue.splices)',
            '_checkValidLevelLeft(lockstartpathleft, startpathleft, maxnavlevelsleft)',
            '_checkValidLevelRight(lockstartpathright, startpathright, maxnavlevelsright)',
            '_updateActiveRowProperty(activerow.*)',
            '_updateActiveSelectionProperty(activeselection.*)',
        ]
    }

    /****************************************************************************************************
     * Creates an instance of LasalRuntimeSigControlFilemanager.
     * 
     * @constructor
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    constructor() {
        super();
        this.wmApi = window.sigApi.windowManager;
        this.queueInterval = null;
        this.queueIntervalDelay = 300;
        this.queueActive = true;
        this.queueActiveCommand = null;
        this.queueRunning = false;
        this.fmApi = window.sigApi.fileManager;
        this.utilsApi = window.sigApi.sigUtils;
        this.tmApi = window.sigApi.textManager;
        this.dsApi = (window.sigApi.defaultStyleManager) ? window.sigApi.defaultStyleManager : null;
        this.constApi = (window.sigApi.SIG_CONST) ? window.sigApi.SIG_CONST : null;
        this.gridConfig = {};
        this.iswaitingTimeout = null;
        this.iswaitingDelay = 100;
        this.statusAutoClearTimeout = null;
        this.statusAutoClearDelay = 3000;
        this.defaultStatus = '';
        this.controlTextList = this.getControlTextListName();
        this.refreshCount = 0;
        this.refreshCountMax = 1;
        this.toolbarsFirstRenderDone = false;
        this.validStartPathLeft = '/';
        this.validStartPathRight = '/';

        this.fileFolderSeparator = '//';
        this.itemSeparator = '/';

        this.sigDateTimeFormat = 'DD.MM.YYYY HH:mm:ss';

        this.startpane= "left";
        this.clipboardmode =  '';
        this.allowedvolumes = '';   // Only for safety during development
        this.progress =  0;
        this.disableautodeactivate = false;
        this.disablekeyactions = false;
        this.nofolders = false;
        this.nofiles = false;
        this.unixpathformat = false;
        this.useprefixes = true;
        this.hideparentleft = false;
        this.hideparentright = false;

        this.initialized = false;
        this.visible = false;

        // We need to wait until all the props needed to validate the path lock are set by the runtime
        this.requiredPropertiesReady = false;
        this.sigAddRequiredProperty('startpathleft');
        this.sigAddRequiredProperty('lockstartpathleft');
        this.sigAddRequiredProperty('maxnavlevelsleft');
        this.sigAddRequiredProperty('startpathright');
        this.sigAddRequiredProperty('lockstartpathright');
        this.sigAddRequiredProperty('maxnavlevelsright');

        // Uncomment to turn on debug information
        // this.dbgApi = window.sigApi.debug;
        // if (this.dbgApi) this.dbgApi.setLogLevel(this.dbgApi.DEBUG);

    }


    /****************************************************************************************************
     * This callback runs when the component is connected in the DOM.
     * 
     * @overwritten
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    connectedCallback() {
        super.connectedCallback();

        if (!this.isdesignmode) {
            // Bind the keyboard events 
            this.sigAddEventListener('keyup', e => {
                if (this.isactive && !this.systemWindowOpened && !this.disablekeyactions && this.visible) {
                    // Needed to capture the tab key to switch panes
                    if (e.keyCode === 9) {
                        e.preventDefault();
                    }
                    this._keyup(e);
                }
            }, 'jsEvent', window);

            this.sigAddEventListener('keydown', e => {
                if (this.isactive && !this.systemWindowOpened && this.visible) {
                    // Needed to capture the tab key to switch panes
                    if (e.keyCode === 9) {
                        e.preventDefault();
                    }
                    this._keydown(e);
                }
            }, 'jsEvent', window);

            this.sigAddEventListener('mousedown', e => {
                if (e.target.id !== this.id && this.isactive && !this.systemWindowOpened) {
                    this._deactivateOnTap();
                }
            }, 'jsEvent', window);

            // Bind the event mediator for language switch
            this.sigAddEventListener('LANGUAGE_CHG', (majorId, minorId, msg) => {
                this._switchLang(majorId, minorId, msg);
            }, 'runtimeEvent');

            // Bind the event mediator for ws state change
            this.sigAddEventListener('WS_STATE_CHG', (majorId, minorId, msg) => {
                this._onWSStateChg(majorId, minorId, msg);
            }, 'runtimeEvent');

            // Bind the event mediator for route change
            this.sigAddEventListener('APPROUTE_CHG', (maID, miID, message) => {
                this._deactivateOnRouteChange(maID, miID, message);
            }, 'runtimeEvent');

            // Setup the command queue
            if (this.queueInterval === null) {
                this.queueInterval = this.sigSetInterval(() => {
                    this._queueExecute()
                }, this.queueIntervalDelay);
            }
        } else {
            // In designmode we need to run the init in the connectedCallback,
            // because _onRequiredPropertiesReady() is not called by the DRT
            SigPolymer.afterNextRender(this, function (params) {
                this.requiredPropertiesReady = true;
                this._init();
            });
        }
    }

    /****************************************************************************************************
     * This overrides the method inherited from the sig-element.
     * 
     * @overwritten
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    sigOnRequiredPropertiesReady() {
        super.sigOnRequiredPropertiesReady();
        // In the normal RT we run _init() in the sigOnRequiredPropertiesReady() callback,
        // to make sure all needed properties to check if we have a valid path are set
        if (!this.isdesignmode) {
            SigPolymer.afterNextRender(this, function (params) {
                this.requiredPropertiesReady = true;
                this._init();
            });
        }
    };

     /****************************************************************************************************
     * Called when the runtime shows or hides the component by setting "display" to "block" or "none".
     *
     * @overwritten
     * @param {*} active - false .. control is invisible, true .. control is visible
     * @memberof LasalRuntimeSigControlFilemanager
    ***************************************************************************************************/
     sigOnVisibilityChange(active) {
        super.sigOnVisibilityChange();
        this.visible = active;
    }

    /****************************************************************************************************
     * Initializes the component.
     * 
     * @private
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _init() {
        this.gridConfig = {
            onEnterCallback: (data, pane) => {
                if (data.type) {
                    switch (data.type) {
                        case 'file':
                            break;
                        default:
                            this._actionSwitchPath(data, pane);
                            break;
                    }
                }
            },
            doubleClickCallback: (data, pane) => {
                if (data.row.type) {
                    switch (data.row.type) {
                        case 'file':
                            break;
                        default:
                            this._actionSwitchPath(data.row, pane);
                            break;
                    }
                }
            },
            updateSelectionCallback: (data, pane) => {
                this._updateSelection(data, pane);
            },
            updateActiveRowCallback: (data, pane) => {
                this._updateActiveRow(data, pane);
            },
            self: this
        };
        this._switchLang();
        this._refreshToolbars();
        this._applFontObjects();
        if (this.dualpane) {
            this.activepane = this.startpane;
        } else {
            this.activepane = 'left';
        }

        // Make sure the startpath always have a trailing slash
        const startpathleft = this._makeValidStartPath(this.startpathleft);
        const startpathright = this._makeValidStartPath(this.startpathright);
        this.activepathleft = startpathleft;
        this.activepathright = startpathright;

        this.progressWindowContent = {};

        switch (this.activepane) {
            case 'left':
                this.currentpath = startpathleft;
                break;
            case 'right':
                this.currentpath = startpathright;
                break;
            default:
                break;
        }

        // Make sure we also include the current selected row to the selection
        this.$.filesleft.addactiverowtomultiselect = true;
        this.$.filesright.addactiverowtomultiselect = true;

        this.$.filesleft.selectRowAfterfirstClick = true;
        this.$.filesright.selectRowAfterfirstClick = true;

        this.$.filesleft.alreadyclicked = false;
        this.$.filesright.alreadyclicked = false;

        this.$.filesleft.ignoresetactiverow = true;
        this.$.filesright.ignoresetactiverow = true;


        this._setStatus('defaultStatus');

        if (this.disableautodeactivate) {
            this.isactive = true;
        }

        if (this.isdesignmode) {
            this._renderPreview();
        }

        /* Explicitly empty readOnly props to update datapoints */
        this._setRightactiveselectiondata("");
        this._setRightactivefiledata("");
        this._setLeftactiveselectiondata("");
        this._setLeftactivefiledata("");
        this._setLeftactiveselectiondatabitmask("");
        this._setRightactiveselectiondatabitmask("");

        this.initialized = true;
    }

    /****************************************************************************************************
     * Refreshes all toolbars of the component.
     * 
     * @private
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _refreshToolbars() {
        this._renderToolbar(this.$.toolbar, this._getToolbarData(), 'toolbutton', 'sig-control-button.toolbutton');
        this._renderToolbar(this.$.actionbar, this._getActionbarData(), 'actionbutton', 'sig-control-button.actionbutton');
        this.toolbarsFirstRenderDone = true;
    }

    /****************************************************************************************************
     * This observer regenerates the toolbars, if a toolbar button becomes visible or hidden.
     *
     * @private
     * @param {boolean | undefined} newval The new value of the observed property.
     * @param {boolean | undefined} oldval The old value of the observed property.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _updateButtonVisibility(newval, oldval) {
        if (this.toolbarsFirstRenderDone && oldval !== undefined) {
            this._refreshToolbars();
        }
    }

    /****************************************************************************************************
     * This eventhandler handles the click or tap on a toolbar button.
     *
     * @private
     * @param {Event} evt The raw event fired by polymer.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _handleBarTap(evt) {
        let button;
        //25.11.2022 SchMar2: use directly target instead of sourceEvent.target cause div in button has now a taphandler so the
        //target of the sourceEvent will be the div and not the control itself
        button = evt.target;
        if (button.dataset.action !== undefined) {
            this._handleAction(button.dataset.action, button.dataset.data, button, evt);
        }
    }

    /****************************************************************************************************
     * Handles the action defined for a toolbar button.
     * 
     * @async
     * @private
     * @param {String} action The action name that represents the method to call.
     * @param {Object} data The data attribute bound to the button.
     * @param {HTMLElement} button The domref of the button.
     * @param {Event} evt The raw event fired by Polymer.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    async _handleAction(action, data, button, evt) {
        if (this[action] !== undefined && this[action] instanceof Function) {
            this[action](JSON.parse(data), button, evt);
        } else {
            await this._showAlert(`Action = ${action}, ${data}`).catch((error) => { return; });
            this.systemWindowOpened = false;
        }
    }

    /****************************************************************************************************
     * This eventhandler actives the left pane of the filemanager.
     *
     * @private
     * @param {Event} evt The raw event fired by polymer.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _togglePaneLeft(evt) {
        this.activepane = 'left';
    }

    /****************************************************************************************************
     * This eventhandler activates the right pane of the filemanager.
     *
     * @private
     * @param {Event} evt The raw event fired by polymer.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _togglePaneRight(evt) {
        this.activepane = 'right';
    }

    /****************************************************************************************************
     * This observer toggles between the two panes of the filemanger.
     *
     * @private
     * @param {String | undefined} newval The new value of the observed property.
     * @param {String | undefined} oldval The old value of the observed property.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _togglePane(newval, oldval) {
        if (oldval !== undefined && this.isactive) {
            if (this.dualpane) {
                switch (newval) {
                    case 'left':
                        this.currentpath = this.activepathleft;
                        this.$.filesleft.isactive = true;
                        this.$.filesright.isactive = false;
                        break;
                    case 'right':
                        this.currentpath = this.activepathright;
                        this.$.filesleft.isactive = false;
                        this.$.filesright.isactive = true;
                        break;
                    default:
                        break;
                }
            } else {
                this.currentpath = this.activepathleft;
                this.$.filesleft.isactive = true;
                this.$.filesright.isactive = false;
            }
        }
    }

    /****************************************************************************************************
     * This observer activate or deactivates the dual pane mode.
     *
     * @private
     * @param {Boolean | undefined} newval The new value of the observed property.
     * @param {Boolean | undefined} oldval The old value of the observed property.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _toggleDualPane(newval, oldval) {
        if (oldval !== undefined) {
            if (!newval) {
                this.activepane = 'left';
            }
        }
    }

    /****************************************************************************************************
     * Switches between the two panes in dual pane mode.
     *
     * @private
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _switchPane() {
        if (this.dualpane) {
            switch (this.activepane) {
                case 'left':
                    this.activepane = 'right';
                    break;
                case 'right':
                    this.activepane = 'left';
                    break;
                default:
                    break;
            }
        }
    }

    /****************************************************************************************************
     * This observer sets the paste button in the toolbar inactive
     * or active based on whether the clipboard holds data or not.
     *
     * @private
     * @param {Boolean | undefined} newval The new value of the observed property.
     * @param {Boolean | undefined} oldval The old value of the observed property.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _togglePasteButton(newval, oldval) {
        if (oldval !== undefined) {
            const pastebutton = this.shadowRoot.getElementById('toolpaste');
            if (pastebutton instanceof HTMLElement) {
                if (newval.length > 0) {
                    pastebutton.classList.remove('disabled');
                } else {
                    pastebutton.classList.add('disabled');
                }
            }
        }
    }

    /****************************************************************************************************
     * This observer sets the component active or inactive.
     * 
     * @private
     * @param {Boolean | undefined} newval The old value of the observed property.
     * @param {Boolean | undefined} oldval The old value of the observed property.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _toggleIsActive(newval, oldval) {
        if (newval) {
            this._setActive();
        } else {
            this._setInactive();
        }
    }

    /****************************************************************************************************
     * This event handler handles the click or tap to activate the component.
     *
     * @private
     * @param {Event} evt The raw event fired by polymer.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _activateOnTap(evt) {
        if (!this.isactive) {
            this.isactive = true;
        }
    }

    /****************************************************************************************************
     * This eventhander handles the click or tap to deactivate the component.
     *
     * @private
     * @param {Event} evt The raw event fired by polymer.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _deactivateOnTap(evt) {
        if (this.isactive && !this.disableautodeactivate) {
            this.isactive = false;
        }
    }

    /****************************************************************************************************
     * This eventhander handles the runtime route change event and deactivates the component.
     *
     * @private
     * @param {Number} maID The major id of the event.
     * @param {Number} miID The minor id of the event.
     * @param {Object} message The payload of the event.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _deactivateOnRouteChange(maID, miID, message) {
        if (this.isactive && !this.disableautodeactivate) {
            this.isactive = false;
        }
    }

    /****************************************************************************************************
     * Sets the component active.
     *
     * @private
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _setActive() {
        this.isactive = true;
        if (this.dualpane) {
            switch (this.activepane) {
                case 'left':
                    this.$.filesleft.isactive = true;
                    this.$.filesright.isactive = false;
                    break;
                case 'right':
                    this.$.filesleft.isactive = false;
                    this.$.filesright.isactive = true;
                    break;
                default:
                    break;
            }
        } else {
            this.$.filesleft.isactive = true;
            this.$.filesright.isactive = false;
        }
    }

    /****************************************************************************************************
     * Sets the component inactive.
     *
     * @private
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _setInactive() {
        this.isactive = false;
        this.$.filesleft.isactive = false;
        this.$.filesright.isactive = false;
    }

    /****************************************************************************************************
     * This event handler handles the keyup events of the window.
     *
     * @private
     * @param {Event} e The raw keyup event of the window.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _keyup(e) {
        switch (e.keyCode) {
            default: this._log(`keyup(): Unhandled keycode ${e.keyCode} in keyup`, 'ERROR');
                break;
        }
    }

    /****************************************************************************************************
     * This event handler handles the keydown events of the window.
     *
     * @private
     * @param {Event} e The raw keydown event of the window.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _keydown(e) {
        const key = e.keyCode;
        const ctrlKey = e.ctrlKey;
        const shiftKey = e.shiftKey;
        const altKey = e.shiftKey;
        const metaKey = e.metaKey;
        if (!this.iswaiting && !this.queueRunning && !this.showprogress && !this.disablekeyactions) {
            switch (key) {
                case 9:
                    //Tab
                    if (!shiftKey && !ctrlKey && !altKey && !metaKey) {
                        this._switchPane();
                    }
                    break;
                case 46:
                    //DEL
                    if (!shiftKey && !ctrlKey && !altKey && !metaKey && !this.hidetooldelete) {
                        this._actionDeleteSelection();
                    }
                    break;
                case 67:
                    //CTRL C
                    if (!shiftKey && ctrlKey && !altKey && !metaKey && !this.hidetoolcopypaste) {
                        this._actionClipboardCopy();
                    }
                    //C
                    if (!shiftKey && !ctrlKey && !altKey && !metaKey && this.dualpane && !this.hideactioncopyselection) {
                        this._actionCopySelection();
                    }
                    break;
                case 86:
                    //CTRL V
                    if (!shiftKey && ctrlKey && !altKey && !metaKey && !this.hidetoolcopypaste) {
                        this._actionClipboardPaste();
                    }
                    break;
                case 70:
                    //F
                    if (!shiftKey && !ctrlKey && !altKey && !metaKey && !this.hidetoolcreatefolder) {
                        this._actionCreateFolder();
                    }
                    break;
                case 77:
                    //M
                    if (!shiftKey && !ctrlKey && !altKey && !metaKey && this.dualpane && !this.hideactionmoveselection) {
                        this._actionMoveSelection();
                    }
                    break;
                case 85:
                    //U
                    if (!shiftKey && !ctrlKey && !altKey && !metaKey && !this.hideactionfolderup) {
                        this._actionFolderUp();
                    }
                    break;
                case 82:
                    //R
                    if (!shiftKey && !ctrlKey && !altKey && !metaKey && !this.hidetoolrename) {
                        this._actionRenameActiveItem();
                    }
                    break;
                case 80:
                    //P
                    if (!shiftKey && !ctrlKey && !altKey && !metaKey && !this.hidetoolreload) {
                        this._actionReload();
                    }
                    break;
                default:
                    this._log(`_keydown(): Unhandled keycode ${e.keyCode}`, 'ERROR');
                    break;
            }
        } else if (this.showprogress && !this.disablekeysindialogs) {
            switch (key) {
                case 32: // Spacebar
                    if (!shiftKey && !ctrlKey && !altKey && !metaKey && this.queuestats.count >= 2) {
                        if (this.queueActive) {
                            this._queuePause();
                        } else {
                            this._queueContinue();
                        }
                    }
                    break;
                case 67: // C
                    if (!shiftKey && !ctrlKey && !altKey && !metaKey && this.queueRunning && this.queuestats.count >= 2) {
                        this._queueCancelAllCommand();
                    }
                    break;
                case 27: // ESC
                    if (!shiftKey && !ctrlKey && !altKey && !metaKey && this.queueRunning && this.queuestats.count >= 1) {
                        this._queueCancelCommand();
                    }
                    break;
                default:
                    this._log(`_keydown(): Unhandled keycode ${e.keyCode}`, 'ERROR');
                    break;
            }
        }
    }

    /****************************************************************************************************
     * This observer handles the path update if the left path changes.
     *
     * @private
     * @param {String | undefined} newval  The new value of the observed property.
     * @param {String | undefined} oldval  The old value of the observed property.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _updatePathLeft(newval, oldval) {
        const checkPath = (this.lockstartpathleft) ? this.validStartPathLeft : '/';
        if (this.lockstartpathleft && this._pathIsLocked(newval, this.validStartPathLeft)) {
            if (this.activepane === 'left') this.currentpath = this.validStartPathLeft;
            this.activepathleft = this.validStartPathLeft;
            return;
        } else if (this.maxnavlevelsleft > -1 && this._maxLevelsReached(newval, checkPath, this.maxnavlevelsleft)) {
            this.skipNextPathLeftUpdate = true;
            this.activepathleft = oldval;
            return;
        } else {
            if (!this.skipNextPathLeftUpdate) {
                if (this.activepane === 'left') this.currentpath = newval;
                this._updatePath('left', newval, oldval);
                /* Update left active path data property */
                if (newval) {
                    if (this.unixpathformat) this._setLeftactivepathdata(newval);
                    else this._setLeftactivepathdata(this._convertPath(newval));
                }
            }
            this.skipNextPathLeftUpdate = false;
        }
    }

    /****************************************************************************************************
     * This observer handles the pathupdate if the right path changes.
     *
     * @private
     * @param {String | undefined} newval  The new value of the observed property.
     * @param {String | undefined} oldval  The old value of the observed property.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _updatePathRight(newval, oldval) {
        const checkPath = (this.lockstartpathright) ? this.validStartPathRight : '/';
        if (this.lockstartpathright && this._pathIsLocked(newval, this.validStartPathRight)) {
            if (this.activepane === 'right') this.currentpath = this.validStartPathRight;
            this.activepathright = this.validStartPathRight;
            return;
        }
        if (this.maxnavlevelsright > -1 && this._maxLevelsReached(newval, checkPath, this.maxnavlevelsright)) {
            this.skipNextPathRightUpdate = true;
            this.activepathright = oldval;
            return;
        }
        if (!this.skipNextPathRightUpdate) {
            if (this.activepane === 'right') this.currentpath = newval;
            this._updatePath('right', newval, oldval);
            /* Update right active path data property */
            if (newval) {
                if (this.unixpathformat) this._setRightactivepathdata(newval);
                else this._setRightactivepathdata(this._convertPath(newval));
            }
        }
        this.skipNextPathRightUpdate = false;
    }

    /****************************************************************************************************
     * Generates the _cmdUpdatePath command and adds it to the command queue.
     *
     * @private
     * @param {String} pane The name of the pane to update.
     * @param {String} newval The new path to switch to.
     * @param {String} oldval The old (current) path.
     * @param {Boolean} restorerow Set true if the active selected row of the listview should be restored.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _updatePath(pane, newval, oldval, restorerow) {
        if (!this.isdesignmode) {
            if (oldval !== undefined && newval !== null) {
                const cmd = {
                    command: '_cmdUpdatePath',
                    silent: true,
                    restorerow: restorerow,
                    data: {
                        pane: pane,
                        path: newval,
                        oldpath: oldval
                    }
                };
                this._queueAddCommand(cmd);
            }
        }
    }

    /****************************************************************************************************
     * This observer renders the unordered HTML list of the pathbar and appends it to the template if the current path changes.
     *
     * @private
     * @param {String} newval  The new value of the observed property.
     * @param {String} oldval  The old value of the observed property.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _renderPath(newval, oldval) {
        if (oldval !== undefined && newval !== null) {
            const path = newval.replace(/\/$/, "");
            const elements = path.split('/');
            let folderpath = "";
            const ul = document.createElement('ul');
            ul.classList.add('arrows', 'clearfix');
            for (let index = 0; index < elements.length; index++) {
                const li = document.createElement('li');
                const span = document.createElement('span');
                let data = {};
                let foldername = '';
                if (index === 0) {
                    li.classList.add('first');
                    foldername = this.texts.home;
                    folderpath = "/";
                } else if (index > 0 && index < elements.length - 1) {
                    foldername = elements[index];
                    folderpath = folderpath + foldername + "/";
                } else if (index === elements.length - 1) {
                    li.classList.add('last');
                    foldername = elements[index];
                    folderpath = folderpath + foldername + "/";
                }
                data.path = folderpath;
                li.setAttribute('data-action', '_actionSwitchPath');
                li.setAttribute('data-data', JSON.stringify(data));
                span.setAttribute('data-action', '_actionSwitchPath');
                span.setAttribute('data-data', JSON.stringify(data));
                span.textContent = foldername;
                li.appendChild(span);
                ul.appendChild(li);
            }
            this.$.pathbar.innerHTML = ''
            this.$.pathbar.appendChild(ul);
            if (this.isdesignmode) {
                this.$.pathbar.scrollLeft = 0;
            } else {
                this.$.pathbar.scrollLeft = 100000; // Make sure we scrolled maximal to the right
            }
        }
    }

    /****************************************************************************************************
     * Generates an unordered HTML list of toolbar buttons and adds it to the given toolbar in the template.
     * 
     * @private
     * @param {HTMLElement} [toolbar=null]  The domref of the toolbar div.
     * @param {Array} [data=[]]  An array of objects containing the configuration data for each toolbar button.
     * @param {String} [btnClass=""] The class to apply to the toolbar button.
     * @param {String} selector The shadow dom selector (=publishname) to reapply the default styling class.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _renderToolbar(toolbar = null, data = [], btnClass = "", selector) {
        if (toolbar !== null && data.length > 0) {
            const fragment = document.createDocumentFragment();
            for (const button of data) {
                if (!button.hidden) {
                    const sigBtn = document.createElement('sig-control-button');
                    sigBtn.setAttribute('id', button.id);
                    if (button.title) sigBtn.setAttribute('title', button.title);
                    sigBtn.setAttribute('data-action', button.action);
                    sigBtn.setAttribute('data-data', JSON.stringify(button.data));
                    sigBtn.classList.add(btnClass);
                    sigBtn.sigbtnicon = button.icon;
                    sigBtn.sigbtniconpressed = button.iconpressed;
                    if (button.disabled) {
                        sigBtn.classList.add('disabled');
                    }
                    if (button.icon !== "") {
                        sigBtn.classList.add('hasicon');
                    } else {
                        sigBtn.textContent = button.name;
                    }
                    fragment.appendChild(sigBtn);
                }
            }
            toolbar.innerHTML = '';
            toolbar.appendChild(fragment);
            // After the first render of the toolbars we need to reapply the styling to the buttons 
            if (this.toolbarsFirstRenderDone && selector) {
                //get buttons
                const buttons = this.shadowRoot.querySelectorAll(selector);
                if ((buttons) && (buttons.length > 0)) {
                    let styleClass = this.dsApi.getStyleClassByPropName(this.id, selector);
                    styleClass = (styleClass) ? styleClass : this.constApi.DEFAULT_STYLE_CLASS;
                    if (styleClass) {
                        const applied = this.dsApi.setStylingByClassName(
                            this.id,
                            buttons,
                            styleClass,
                            undefined, // include
                            ['sigbtntype'] // exclude
                        );
                        if (!applied) this._log(`_renderToolbar(): The style class ${styleClass} was not applied to ${selector}`, 'ERROR');
                    }                    
                }
            }
        }
    }

    /****************************************************************************************************
     * Implements the _actionSwitchPath action and switches to the given path.
     *
     * @private
     * @param {Object} data The data attribute object attached to the toolbar button.
     * @param {HTMLElement} button The domref of the toolbar button, which triggered the action.
     * @param {Event} evt The raw event fired by polymer.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _actionSwitchPath(data, button, evt) {
        switch (this.activepane) {
            case 'left':
                this.activepathleft = data.path;
                break;
            case 'right':
                this.activepathright = data.path;
                break;
        }
    }

    /****************************************************************************************************
     * Implements the _actionReload action of a toolbar button and reloads all panes.
     *
     * @async
     * @private
     * @param {Object} data The data attribute object attached to the toolbar button.
     * @param {HTMLElement} button The domref of the toolbar button, which triggered the action.
     * @param {Event} evt The raw event fired by polymer.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    async _actionReload(data, button, evt) {
        this.systemWindowOpened = false;
        this._refreshPanes(true);
        this._setStatus('tryingToReloadAllPanes');
    }

    /****************************************************************************************************
     * gets the child of a window
     *
     * @private
     * @param {*} window
     * @param {*} child
     * @return {*} 
    ****************************************************************************************************/
    _getWindowChild(window, child) {
        return window.getChildByName("sigFilemanager_" + child);
    }

    /****************************************************************************************************
     * sets the value of the element
     * the exception is if the prop is set, then the css style is set directly
     *
     * @private
     * @param {*} element
     * @param {*} [content=null]
     * @param {string} [prop='value']
    ****************************************************************************************************/
    _setWindowChildContent(element, content = null, prop = 'value') {
        if((element) && (content !== null) && prop === 'unittext') {
            element.unitText = content;
        } else if ((element) && (content !== null)) {
            element[prop] = content;
        }
    }

    /****************************************************************************************************
     * This observer updates the state of the progresswindowset variable.
     *
     * @private
     * @param {Object} newval The new value of th observed polymer property.
     * @param {Object} oldval The old value of th observed polymer property.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _checkCustomProgressWindow(newval, oldval){
        if(this.wmApi.getWindow(newval) !== null){
            this.progresswindowset = true;
        }else{
            this.progresswindowset = false;
        }
    }

    /****************************************************************************************************
     * Opens a custom window and executes given function, 
     * if OK or CANCEL is pressed.
     *
     * @async
     * @private
     * @param {Object} windowName
     * @param {*} checkResult
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    async _openCustomConfirmWindow(windowName, checkResult){

        this.systemWindowOpened = true;
        const openwindowResult = await this.wmApi.openWindow(windowName).then(result => {
            return true;
        }).catch(error => {
            this._log('_openCustomConfirmWindow(): ' + error, 'ERROR');
            return false;
        });  

        // window opened successfully
        if(openwindowResult){

            const windowObj = this.wmApi.getWindow(windowName);

            // get buttons of window
            const buttonOk = this._getWindowChild(windowObj, "ok").getDomRef();
            const buttonCancel = this._getWindowChild(windowObj, "cancel").getDomRef();

            // if window has ok and cancel button
            if(buttonOk && buttonCancel){
                // add event listener
                buttonOk.sigAddEventListener("mousedown", () => {
                    buttonOk.sigRemoveAllEventListeners();
                    this.wmApi.closeWindow(windowName);
                    this.systemWindowOpened = false;
                    checkResult(true);
                });
                buttonCancel.sigAddEventListener("mousedown", () => {
                    buttonCancel.sigRemoveAllEventListeners();
                    this.wmApi.closeWindow(windowName);
                    this.systemWindowOpened = false;
                    checkResult(false);
                });

            }else{
                this.wmApi.closeWindow(windowName);
                this.systemWindowOpened = false;
                checkResult(false);
            }
        }else{
            this._log(`_openCustomConfirmWindow(): Window "${windowName}" could not be opened`, 'ERROR');
        }
    }

    /****************************************************************************************************
     * Implements the _actionDeleteSelection action of a toolbar button and builds
     * the _cmdDeletePath command and adds it to the queue.
     *
     * @async
     * @private
     * @param {Object} data The data attribute object attached to the toolbar button.
     * @param {HTMLElement} button The domref of the toolbar button, which triggered the action.
     * @param {Event} evt The raw event fired by polymer
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    async _actionDeleteSelection(data, button, evt) {
        const currentpath = this.currentpath;
        const rows = this._getMarkedRowsOfActivePane();
        if (this.currentpath === '/') {
            await this._showAlert(this._getTextObj('canNotDeleteDriveInRoot'), this._getTextObj('deleteSelection')).catch((error) => { return; });
            this.systemWindowOpened = false;
            this._setStatus('canNotDeleteDriveInRoot');
            return;
        }
        if (rows !== null) {
            if (rows.length > 0) {
                    
                // need confirmation of user 
                if(this.confirmdelete === true){

                    // if custom window is set -> open it
                    if(this.wmApi.getWindow(this.deletewindow) !== null){
                        await this._openCustomConfirmWindow(this.deletewindow, function(deleteSelection){
                            if (deleteSelection) {
                                for (const row of rows) {
                                    const cmd = {
                                        command: '_cmdDeletePath',
                                        data: {
                                            parent: row.parent,
                                            path: row.path,
                                            type: row.type,
                                            backup: false
                                        }
                                    };
                                    this._queueAddCommand(cmd);
                                }
                            } else {
                                this._setStatus('deleteCanceled');
                            }
                        }.bind(this));

                    // otherwise open system window
                    }else{
                        const deleteSelection = await this._showConfirm(this._getTextObj('deleteItemsInPath', [rows.length, currentpath]), this._getTextObj('deleteSelection'), 1).then(result => {
                            return true;
                        }).catch(error => {
                            this._log('_actionDeleteSelection(): ' + error, 'ERROR');
                            return false;
                        });  

                        this.systemWindowOpened = false;
                        if (deleteSelection) {
                            for (const row of rows) {
                                const cmd = {
                                    command: '_cmdDeletePath',
                                    data: {
                                        parent: row.parent,
                                        path: row.path,
                                        type: row.type,
                                        backup: false
                                    }
                                };
                                this._queueAddCommand(cmd);
                            }
                        } else {
                            this._setStatus('deleteCanceled');
                        }
                    }
                // delete without confirmation
                }else{
                    for (const row of rows) {
                        const cmd = {
                            command: '_cmdDeletePath',
                            data: {
                                parent: row.parent,
                                path: row.path,
                                type: row.type,
                                backup: false
                            }
                        };
                        this._queueAddCommand(cmd);
                    }
                }
            } else {
                await this._showAlert(this._getTextObj('pleaseSelectSomeFilesOrFolders'), this._getTextObj('deleteSelection')).catch((error) => { return; });
                this.systemWindowOpened = false;
                this._setStatus('pleaseSelectSomeFilesOrFolders');
            }
        }
    }

    /****************************************************************************************************
     * Implements the _actionCreateFolder action of a toolbar button and builds
     * the _cmdCreateFolder command and adds it to the queue.
     *
     * @async
     * @private
     * @param {Object} data The data attribute object attached to the toolbar button.
     * @param {HTMLElement} button The domref of the toolbar button, which triggered the action.
     * @param {Event} evt The raw event fired by Polymer.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    async _actionCreateFolder(data, button, evt) {
        const currentpath = this.currentpath;
        if (currentpath !== '/') {
            const foldername = await this._showPrompt(this._getTextObj('pleaseEnterNameForNewFolderIn', [currentpath]), this._getTextObj('createFolder'), this._getTextObj('newFolder')).then(result => {
                return result;
            }).catch(error => {
                this._log('_actionCreateFolder(): ' + error, 'ERROR');
                return null;
            });
            this.systemWindowOpened = false;
            if (foldername !== null) {
                if (foldername !== '') {
                    const cmd = {
                        command: '_cmdCreateFolder',
                        data: {
                            path: this.currentpath,
                            name: foldername
                        }
                    }
                    this._queueAddCommand(cmd);
                } else {
                    this._setStatus('pleaseEnterValidFolderName');
                }
            } else {
                this._setStatus('folderCreationCanceled');
            }
        } else {
            await this._showAlert(this._getTextObj('canNotCreateFolderInRoot'), this._getTextObj('createFolder')).catch((error) => { return; });
            this.systemWindowOpened = false;
            this._setStatus('canNotCreateFolderInRoot');
        }
    }

    /****************************************************************************************************
     * Implements the _actionRenameActiveItem action of a toolbar button and builds
     * the _cmdRenamePath command and adds it to the queue.
     *
     * @async
     * @private
     * @param {Object} data The data attribute object attached to the toolbar button.
     * @param {HTMLElement} button The domref of the toolbar button, which triggered the action.
     * @param {Event} evt The raw event fired by polymer.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    async _actionRenameActiveItem(data, button, evt) {
        if (this.currentpath === '/') {
            await this._showAlert(this._getTextObj('canNotRenameDriveInRoot'), this._getTextObj('renameFileOrFolder')).catch((error) => { return; });
            this.systemWindowOpened = false;
            this._setStatus('canNotRenameDriveInRoot');
            return;
        }
        const row = this._getActiveRowOfActivePane();
        if (row != null) {
            const rowdata = JSON.parse(row.dataset.data);
            const newname = await this._showPrompt(this._getTextObj('PleaseEnterNewNameFor', [rowdata.name]), this._getTextObj('renameFileOrFolder'), rowdata.name).then(result => {
                return result;
            }).catch(error => {
                this._log('_actionRenameActiveItem(): ' + error, 'ERROR');
                return null;
            });
            this.systemWindowOpened = false;
            if (newname !== null) {
                if (newname !== '' && newname !== rowdata.name) {
                    const cmd = {
                        command: '_cmdRenamePath',
                        data: {
                            path: this._getParentPath(rowdata.path),
                            oldname: rowdata.name,
                            newname: newname
                        }
                    }
                    this._queueAddCommand(cmd);
                } else {
                    this._setStatus('pleaseEnterValidNewName');
                }
            } else {
                this._setStatus('canceledRenamingOf', [rowdata.name]);
            }
        } else {
            await this._showAlert(this._getTextObj('pleaseSelectFileOrFolderFirst'), this._getTextObj('renameFileOrFolder')).catch((error) => { return; });
            this.systemWindowOpened = false;
            this._setStatus('pleaseSelectFileOrFolderFirst');
        }
    }

    /****************************************************************************************************
     * Implements the _actionClipboardCopy action of a toolbar button and copies the selected (marked) items to the clipboard.
     *
     * @private
     * @param {Object} data The data attribute object attached to the toolbar button.
     * @param {HTMLElement} button The domref of the toolbar button, which triggered the action.
     * @param {Event} evt The raw event fired by polymer.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _actionClipboardCopy(data, button, evt) {
        const rows = this._getMarkedRowsOfActivePane();
        if (rows !== null) {
            if (rows.length > 0) {
                this.clipboardmode = 'copy'
                this.clipboard = rows;
                this._setStatus('copiedItemsToTheClipboard', [rows.length]);
            } else {
                this._setStatus('NothingCopiedToTheClipboard');
            }
        }
    }

    /****************************************************************************************************
     * Implements the _actionClipboardCut action of a toolbar button and cuts the selected (marked) items to the clipboard.
     *
     * @async
     * @private
     * @param {Object} data The data attribute object attached to the toolbar button.
     * @param {HTMLElement} button The domref of the toolbar button, which triggered the action.
     * @param {Event} evt The raw event fired by polymer.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
     * @todo Not used right now. Not possible with the current fmApi. Needs testing and rework after implementation in the api.
    ****************************************************************************************************/
    async _actionClipboardCut(data, button, evt) {
        const currentpath = this.currentpath;
        const rows = this._getMarkedRowsOfActivePane();
        if (rows !== null) {
            if (rows.length > 0) {
                const cutselection = await this._showConfirm(this._getTextObj('doYouWantToCutItemsFrom', [rows.length, currentpath]), this._getTextObj('cutSelection')).then(result => {
                    return true;
                }).catch(error => {
                    this._log('_actionClipboardCut(): ' + error, 'ERROR');
                    return false;
                });
                this.systemWindowOpened = false;
                if (cutselection) {
                    this.clipboardmode = 'cut';
                    this.clipboard = rows;
                    for (const row of rows) {
                        const cmd = {
                            command: '_cmdDeletePath',
                            data: {
                                path: row.path,
                                backup: true
                            }
                        };
                        this._queueAddCommand(cmd);
                    }
                }
            } else {
                this._setStatus('NothingCutToTheClipboard');
            }
        }
    }

    /****************************************************************************************************
     * Implements the _actionClipboardPaste action of a toolbar button and builds
     * the _cmdCopyMovePath command and adds it to the queue.
     *
     * @async
     * @private
     * @param {Object} data The data attribute object attached to the toolbar button.
     * @param {HTMLElement} button The domref of the toolbar button, which triggered the action.
     * @param {Event} evt The raw event fired by polymer.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    async _actionClipboardPaste(data, button, evt) {
        const clipboard = this.clipboard;
        const clipboardmode = this.clipboardmode;
        const currentpath = this.currentpath;
        let restoreFromSource = false;
        if (clipboard.length > 0) {
            if (currentpath !== '/') {

                // need confirmation of user 
                if(this.confirmpaste === true){

                    // if custom window is set -> open it
                    if(this.wmApi.getWindow(this.pastewindow) !== null){
                        await this._openCustomConfirmWindow(this.pastewindow, function(pasteClipboard){
                            if (pasteClipboard) {
                                if (clipboardmode === 'cut') {
                                    restoreFromSource = true;
                                }
                                for (const row of clipboard) {
                                    const cmd = {
                                        command: '_cmdCopyMovePath',
                                        data: {
                                            source: row.path,
                                            destination: (row.type === 'file') ? currentpath + row.name : currentpath,
                                            restoreFromSource: restoreFromSource
                                        }
                                    };
                                    this._queueAddCommand(cmd);
                                }
                            } else {
                                this._setStatus('canceledPasteFromClipboard');
                            }
                        }.bind(this));

                    }else{

                        const pasteClipboard = await this._showConfirm(this._getTextObj('doYouWantToPasteItemsTo', [clipboard.length, currentpath]), this._getTextObj('pasteSelection')).then(result => {
                            return true;
                        }).catch(error => {
                            this._log('_actionClipboardPaste(): ' + error, 'ERROR');
                            return false;
                        });
                        this.systemWindowOpened = false;
                        if (pasteClipboard) {
                            if (clipboardmode === 'cut') {
                                restoreFromSource = true;
                            }
                            for (const row of clipboard) {
                                const cmd = {
                                    command: '_cmdCopyMovePath',
                                    data: {
                                        source: row.path,
                                        destination: (row.type === 'file') ? currentpath + row.name : currentpath,
                                        restoreFromSource: restoreFromSource
                                    }
                                };
                                this._queueAddCommand(cmd);
                            }
                        } else {
                            this._setStatus('canceledPasteFromClipboard');
                        }
                    }
                // paste without confirmation
                }else{
                    if (clipboardmode === 'cut') {
                        restoreFromSource = true;
                    }
                    for (const row of clipboard) {
                        const cmd = {
                            command: '_cmdCopyMovePath',
                            data: {
                                source: row.path,
                                destination: (row.type === 'file') ? currentpath + row.name : currentpath,
                                restoreFromSource: restoreFromSource
                            }
                        };
                        this._queueAddCommand(cmd);
                    }
                }
            } else {
                await this._showAlert(this._getTextObj('canNotPasteItemsToRoot'), this._getTextObj('pasteSelection')).catch((error) => { return; });
                this.systemWindowOpened = false;
                this._setStatus('canNotPasteItemsToRoot');
            }
        } else {
            this._setStatus('canNotPasteItemsCipboardIsEmpty');
        }
    }

    /****************************************************************************************************
     * Implements the _actionCopySelection action of a toolbar button and builds
     * the _cmdCopyMovePath command and adds it to the queue.
     *
     * @async
     * @private
     * @param {Object} data The data attribute object attached to the toolbar button.
     * @param {HTMLElement} button The domref of the toolbar button, which triggered the action.
     * @param {Event} evt The raw event fired by polymer.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    async _actionCopySelection(data, button, evt) {
        if (this.dualpane) {
            const rows = this._getMarkedRowsOfActivePane();
            let source = null;
            let destination = null;
            switch (this.activepane) {
                case 'left':
                    source = this.activepathleft;
                    destination = this.activepathright;
                    break;
                case 'right':
                    source = this.activepathright;
                    destination = this.activepathleft;
                    break;

            }
            if (rows !== null) {
                if (rows.length > 0) {
                    if (destination !== '/') {

                        // need confirmation of user 
                        if(this.confirmcopy === true){

                            // if custom window is set -> open it
                            if(this.wmApi.getWindow(this.copywindow) !== null){
                                await this._openCustomConfirmWindow(this.copywindow, function(copyfiles){
                                    if (copyfiles) {
                                        for (const row of rows) {
                                            const cmd = {
                                                command: '_cmdCopyMovePath',
                                                data: {
                                                    source: row.path,
                                                    destination: (row.type === 'file') ? destination + row.name : destination,
                                                    move: false
                                                }
                                            };
                                            this._queueAddCommand(cmd);
                                        }
                                    } else {
                                        this._setStatus('canceledCopyItems');
                                    }
                                }.bind(this));
                            
                            // otherwise open system window
                            } else {
                                const copyfiles = await this._showConfirm(this._getTextObj('doYouWantToCopyItemsTo', [rows.length, destination]), this._getTextObj('copySelection')).then(result => {
                                    return true;
                                }).catch(error => {
                                    this._log('_actionCopySelection(): ' + error, 'ERROR');
                                    return false;
                                });
                                this.systemWindowOpened = false;
                                if (copyfiles) {
                                    for (const row of rows) {
                                        const cmd = {
                                            command: '_cmdCopyMovePath',
                                            data: {
                                                source: row.path,
                                                destination: (row.type === 'file') ? destination + row.name : destination,
                                                move: false
                                            }
                                        };
                                        this._queueAddCommand(cmd);
                                    }
                                } else {
                                    this._setStatus('canceledCopyItems');
                                }
                            }
                        // copy without confirmation
                        } else{
                            for (const row of rows) {
                                const cmd = {
                                    command: '_cmdCopyMovePath',
                                    data: {
                                        source: row.path,
                                        destination: (row.type === 'file') ? destination + row.name : destination,
                                        move: false
                                    }
                                };
                                this._queueAddCommand(cmd);
                            }
                        }
                    } else {
                        await this._showAlert(this._getTextObj('canNotCopyFilesToRoot'), this._getTextObj('copySelection')).catch((error) => { return; });
                        this.systemWindowOpened = false;
                        this._setStatus('canNotCopyFilesToRoot');
                    }
                } else {
                    await this._showAlert(this._getTextObj('pleaseSelectSomeFilesOrFolders'), this._getTextObj('copySelection')).catch((error) => { return; });
                    this.systemWindowOpened = false;
                    this._setStatus('pleaseSelectSomeFilesOrFolders');
                }
            }
        }
    }

    /****************************************************************************************************
     * Implements the _actionMoveSelection action of a toolbar button and builds
     * the _cmdCopyMovePath command and adds it to the queue.
     *
     * @async
     * @private
     * @param {Object} data The data attribute object attached to the toolbar button.
     * @param {HTMLElement} button The domref of the toolbar button, which triggered the action.
     * @param {Event} evt The raw event fired by polymer.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    async _actionMoveSelection(data, button, evt) {
        if (this.dualpane) {
            const rows = this._getMarkedRowsOfActivePane();
            let source = null;
            let destination = null;
            switch (this.activepane) {
                case 'left':
                    source = this.activepathleft;
                    destination = this.activepathright;
                    break;
                case 'right':
                    source = this.activepathright;
                    destination = this.activepathleft;
                    break;
            }
            if (rows !== null) {
                if (rows.length > 0) {
                    if (destination !== '/') {

                        // need confirmation of user 
                        if(this.confirmmove === true){

                            // if custom window is set -> open it
                            if(this.wmApi.getWindow(this.movewindow) !== null){
                                await this._openCustomConfirmWindow(this.movewindow, function(movefiles){
                                    if (movefiles) {
                                        for (const row of rows) {
                                            const cmd = {
                                                command: '_cmdCopyMovePath',
                                                data: {
                                                    source: row.path,
                                                    destination: (row.type === 'file') ? destination + row.name : destination,
                                                    move: true
                                                }
                                            };
                                            this._queueAddCommand(cmd);
                                        }
                                    } else {
                                        this._setStatus('canceledMoveSelection', 'moveSelection');
                                    }
                                }.bind(this));
                            
                            // otherwise open system window
                            } else {
                                const movefiles = await this._showConfirm(this._getTextObj('doYouWantToMoveItemsTo', [rows.length, destination]), this._getTextObj('moveSelection')).then(result => {
                                    return true;
                                }).catch(error => {
                                    this._log('_actionMoveSelection(): ' + error, 'ERROR');
                                    return false;
                                });
                                this.systemWindowOpened = false;
                                if (movefiles) {
                                    for (const row of rows) {
                                        const cmd = {
                                            command: '_cmdCopyMovePath',
                                            data: {
                                                source: row.path,
                                                destination: (row.type === 'file') ? destination + row.name : destination,
                                                move: true
                                            }
                                        };
                                        this._queueAddCommand(cmd);
                                    }
                                } else {
                                    this._setStatus('canceledMoveSelection', 'moveSelection');
                                }
                            }
                        // move without confirmation
                        } else {
                            for (const row of rows) {
                                const cmd = {
                                    command: '_cmdCopyMovePath',
                                    data: {
                                        source: row.path,
                                        destination: (row.type === 'file') ? destination + row.name : destination,
                                        move: true
                                    }
                                };
                                this._queueAddCommand(cmd);
                            }
                        }
                    } else {
                        await this._showAlert(this._getTextObj('canNotMoveItemsToRoot'), this._getTextObj('moveSelection')).catch((error) => { return; });
                        this.systemWindowOpened = false;
                        this._setStatus('canNotMoveItemsToRoot', 'moveSelection');
                    }
                } else {
                    await this._showAlert(this._getTextObj('pleaseSelectSomeFilesOrFolders'), this._getTextObj('moveSelection')).catch((error) => { return; });
                    this.systemWindowOpened = false;
                    this._setStatus('pleaseSelectSomeFilesOrFolders', 'moveSelection');
                }
            }
        }
    }

    /****************************************************************************************************
     * Implements the _actionFolderUp action of a toolbar button and moves up to the parent level of the active path.
     *
     * @async
     * @private
     * @param {Object} data The data attribute object attached to the toolbar button.
     * @param {HTMLElement} button The domref of the toolbar button, which triggered the action.
     * @param {Event} evt The raw event fired by polymer.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    async _actionFolderUp(data, button, evt) {
        const currentpath = this.currentpath;
        if (currentpath !== '/') {
            const parts = currentpath.replace(/\/$/, "").split('/');
            parts.pop();
            this.currentpath = parts.join("/") + "/";

            switch (this.activepane) {
                case 'left':
                    this.activepathleft = this.currentpath;
                    break;
                case 'right':
                    this.activepathright = this.currentpath;
                    break;
            }
        } else {
            await this._showAlert(this._getTextObj('catNotMoveOutsideRoot'), this._getTextObj('moveToParent')).catch((error) => { return; });
            this.systemWindowOpened = false;
            this._setStatus('catNotMoveOutsideRoot', 'moveToParent');
        }
    }


    /****************************************************************************************************
     * Returns the data of the marked rows of active pane.
     *
     * @private
     * @returns {Array} An arry of objects containing the data of the marked rows.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _getMarkedRowsOfActivePane() {
        let rows = null;
        switch (this.activepane) {
            case 'left':
                rows = this.$.filesleft.getMarkedRows();
                break;
            case 'right':
                rows = this.$.filesright.getMarkedRows();
                break;
        }
        return this._cleanRows(rows);
    }

    /****************************************************************************************************
     * Returns the data of the active selected row of the active pane.
     *
     * @private
     * @returns {Object} The data object of the row.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _getActiveRowOfActivePane() {
        let row = null;
        switch (this.activepane) {
            case 'left':
                row = this.$.filesleft.getActiveRow();
                break;
            case 'right':
                row = this.$.filesright.getActiveRow();
                break;
        }
        return this._cleanRow(row);
    }

    /****************************************************************************************************
     * Removes the data objects of type parent and volumes from the given array of data objects.
     * 
     * @private
     * @param {Array} [rows=null] Array of row data objects which should be cleaned.
     * @returns {Array} An array of cleaned data objects.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _cleanRows(rows = null) {
        let cleanedRows = [];
        if (rows !== null) {
            rows.forEach(row => {
                if (row.type !== 'parent' && row.type !== "volume") {
                    cleanedRows.push(row);
                }
            });
        }
        if (cleanedRows.length < 1) cleanedRows = null;
        return cleanedRows;
    }

    /****************************************************************************************************
     * Cleans the given row. If the row data object is of type parent or volume, it will be set to null.
     *
     * @private
     * @param {Object} [rows=null] Array of row data objects which should be cleaned.
     * @returns {Object | null} The given data object or null.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _cleanRow(row = null) {
        let cleanedRow = null;
        if (row instanceof HTMLElement && row.dataset.data) {
            const data = JSON.parse(row.dataset.data);
            if (data.type !== 'parent' && data.type !== 'volume') {
                cleanedRow = row;
            }
        }
        return cleanedRow;
    }

    /****************************************************************************************************
     * Returns an array of config objects to generate the main toolbar buttons.
     * 
     * @private
     * @returns {Array} An array of config objects.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _getToolbarData() {
        const data = [{
            id: "toolreload",
            name: "Reload",
            class: "reload",
            icon: "\uf021",
            iconpressed: "\uf021",
            action: "_actionReload",
            title: this.texts.tReloadPanes,
            disabled: false,
            hidden: this.hidetoolreload,
            data: {
                toogle: false
            }
        }, {
            id: "tooldelete",
            name: "Delete",
            class: "delete",
            icon: "\uf2ed",
            iconpressed: "\uf2ed",
            action: "_actionDeleteSelection",
            disabled: false,
            hidden: this.hidetooldelete,
            title: this.texts.tDeleteSelection,
            data: {
                toogle: false
            }
        }, {
            id: "toolcreatfolder",
            name: "CreateFolder",
            class: "folder",
            icon: "\uf07b",
            iconpressed: "\uf07b",
            action: "_actionCreateFolder",
            disabled: false,
            hidden: this.hidetoolcreatefolder,
            title: this.texts.tCreateFolder,
            data: {
                toogle: false
            }
        }, {
            id: "toolcopy",
            name: "Copy",
            class: "copy",
            icon: "\uf0c5",
            iconpressed: "\uf0c5",
            action: "_actionClipboardCopy",
            disabled: false,
            hidden: this.hidetoolcopypaste,
            title: this.texts.tCopySelectionToClipboard,
            data: {
                toogle: false
            }
        }, {
            id: "toolpaste",
            name: "Copy",
            class: "paste",
            icon: "\uf0ea",
            iconpressed: "\uf0ea",
            action: "_actionClipboardPaste",
            disabled: true,
            hidden: this.hidetoolcopypaste,
            title: this.texts.tPasteSelectionFromClipboard,
            data: {
                toogle: false
            }
        }, { // Disabled for now, cause API does not support cutting
            id: "toolcut",
            name: "Cut",
            class: "cut",
            icon: "\uf0c4",
            iconpressed: "\uf0c4",
            action: "_actionClipboardCut",
            disabled: true,
            hidden: true,
            title: this.texts.tCutSelectionToClipboard,
            data: {
                toogle: false
            }
        }, {
            id: "toolrename",
            name: "Rename",
            class: "rename",
            icon: "\uf246",
            iconpressed: "\uf246",
            action: "_actionRenameActiveItem",
            disabled: false,
            hidden: this.hidetoolrename,
            title: this.texts.tRenameActiveItem,
            data: {
                toogle: false
            }
        }]
        return data;
    }

    /****************************************************************************************************
     * Returns an array of config objects to generate the action toolbar buttons.
     *
     * @private
     * @returns {Array} An array of config objects.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _getActionbarData() {
        const data = [{
            id: "actionfolderup",
            name: "Up",
            class: "up",
            icon: "\uf3bf",
            iconpressed: "\uf3bf",
            action: "_actionFolderUp",
            disabled: false,
            hidden: this.hideactionfolderup,
            title: this.texts.tFolderUp,
            data: {
                toogle: false
            }
        }, {
            id: "actionactionmoveselection",
            name: "Move",
            class: "move",
            icon: "\uf362",
            iconpressed: "\uf362",
            action: "_actionMoveSelection",
            disabled: false,
            hidden: this.hideactionmoveselection,
            title: this.texts.tMoveSelection,
            data: {
                toogle: false
            }
        }, {
            id: "actioncopyselection",
            name: "Copy",
            class: "duplicate",
            icon: "\uf0ea",
            iconpressed: "\uf0ea",
            action: "_actionCopySelection",
            disabled: false,
            hidden: this.hideactioncopyselection,
            title: this.texts.tCopySelection,
            data: {
                toogle: false
            }
        }];
        return data;
    }

    /****************************************************************************************************
     * Checks the command queue every 100ms and executes the next command stored in the queue.
     * 
     * @async
     * @private
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    async _queueExecute() {

        if (this.queueActive && this.queue.length > 0 && !this.queueRunning) {

            const cmd = this.queue[0];

            if (typeof this[cmd.command] === 'function') {
                if (cmd.fmid === this.id && !cmd.active) {
                    const msg = await this._buildStatusMessage(cmd);
                    this.queueRunning = true;
                    this.iswaiting = true;
                    cmd.id = this.utilsApi.getUID();
                    cmd.active = true;
                    this.queueActiveCommand = cmd;
                    this._runCommand(cmd);
                    if (!cmd.silent) {
                        this._setStatus('executeMessage', [msg]);
                        this.waitingstatus = '';
                    }
                }
            } else {
                this._log(`_queueExecute(): Command "${cmd.command}" not implemented`, 'ERROR')
            }
        }
    }

    /****************************************************************************************************
     * Adds the given command object to the command queue.
     *
     * @private
     * @param {*} [cmd=null] The command object which should be added to the queue.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _queueAddCommand(cmd = null) {
        if (cmd !== null) {
            cmd.fmid = this.id;
            this.push('queue', cmd);
            if (!cmd.silent) {
                this._setStatus('addMessage`', [cmd.command]);
            }
        } else {
            this._log('_queueAddCommand(): Command missing, can not add command to queue.', 'ERROR');
        }
    }

    /****************************************************************************************************
     * Removes the executed command from the command queue.
     * @async
     * @private 
     * @param {Object} status A status object with information about the last command.
     * @param {Object} cmd The command which should be removed from the queue.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    async _queueRemoveCommand(status, cmd) {
        this.shift('queue');
        this.queueRunning = false;
        if (this.isonline) this.iswaiting = false;
        this.queueActiveCommand = null;
        this.progress = 0;
        const msg = await this._buildStatusMessage(cmd);
        if (!status.successful) {
            if (status.code === 26) {
                this._setStatus('canceledMessage', [msg, status.duration, this.queuestats.count]);
            } else {
                const errortxt = (status.errortxt) ? status.errortxt : status.code;
                await this._showAlert(this._getTextObj('finishedWithErrorMessage', [msg, errortxt]), this._getTextObj('errorCode', [status.code]), 2).catch((error) => { return; });
                this.systemWindowOpened = false;
                if (!cmd.silent) this._setStatus('finishedWithErrorMessage', [msg, errortxt]);
                this._log(`_queueRemoveCommand(): ${msg} with id ${cmd.id} ) finished with error code ${status.code}, ${status.errortxt}`, 'WARN');
            }
        } else {
            if (!cmd.silent) {
                this._setStatus('finishedMessage', [msg, status.duration, this.queuestats.count]);
            }
            this.waitingstatus = '';
        }
    }

    /****************************************************************************************************
     * Cancels the active running command and (optionally) all subsequent commands stored in the queue.
     *
     * @async
     * @private
     * @param {Event} evt The raw event fired by polymer by clicking the cancel button.
     * @param {Event} evt2 The raw event fired by polymer by clicking the cancel button.
     * @param {Boolean} [cancelAll=false] If true all subsequent commands in the queue will be canceled.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    async _queueCancelCommand(evt, evt2, cancelAll = false) {
        if (this.queueActiveCommand !== null && this.queueRunning && this.iswaiting) {
            this._setWaitingStatus('tryingToCancelActiveCommand');
            const result = await this.fmApi.cancelCommand(this.queueActiveCommand.id).catch((error) => {
                return error;
            });
            if (!result.status) {
                if (cancelAll) {
                    this._queueStop();
                    this._queueStart(false);
                    this._setStatus('defaultStatus');
                }
                this._refreshPanes();
            }
            return result;
        } else {
            this._setStatus('canNotCancelCommandNoCommandActive');
        }
    }

    /****************************************************************************************************
     * This event handler handles the click / tap on the "remove all" button of the progress dialog.
     *
     * @private
     * @param {Event} evt The raw event fired by polymer by clicking the cancel button.
     * @param {Event} evt2 The raw event fired by polymer by clicking the cancel button.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _queueCancelAllCommand(evt, evt2) {
        this._setWaitingStatus('tryingToCancelAllCommand');
        this._queueCancelCommand(evt, evt2, true);
    }

    /****************************************************************************************************
     * Executes the given command object, builds a status object and removes the command from the command queue.
     *
     * @async
     * @private
     * @param {Object} [cmd=null] The command object which should be executed.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    async _runCommand(cmd = null) {
        if (cmd !== null) {
            if (this[cmd.command] !== undefined && this[cmd.command] instanceof Function) {
                const t0 = performance.now();
                const result = await this[cmd.command](cmd);
                const t1 = performance.now();
                const success = (result.status === undefined || result.status === 0) ? true : false;
                const status = {
                    successful: success,
                    code: result.status,
                    errortxt: result.errortxt,
                    error: result.error,
                    duration: parseInt(t1 - t0, 10)
                }
                this._queueRemoveCommand(status, cmd);
            }
        }
    }

    /****************************************************************************************************
     * Implements the _cmdUpdatePath command.
     *
     * @async
     * @private
     * @param {Object} cmd The command object which contains the data for the command.
     * @returns {Object} A status object or the filesystem object of the current path.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    async _cmdUpdatePath(cmd) {
        let fs = null;
        this._toggleRestoreRow(cmd.restorerow);

        const data = {
            cols: this._getColsConfig(),
            oldpath: cmd.data.oldpath
        };

        if (cmd.data.path === "/") {
            fs = await this.fmApi.getRoot(cmd.id).catch((error) => {
                return error;
            });
        } else {
            const path = this._convertPath(cmd.data.path);
            fs = await this.fmApi.readDir(path, undefined, undefined, undefined, cmd.id).catch((error) => {
                return error;
            });
        }
        if (!fs.status) {
            data.data = this._buildNodeFromFilesystem(fs, cmd.data.pane);
            if (data.data !== null) {
                switch (cmd.data.pane) {
                    case 'left':
                        this.$.filesleft.setactiverow = true;
                        if (!data.oldpath) this.$.filesleft.config = Object.assign({ name: 'left', data: data }, this.gridConfig);
                        else this.$.filesleft.configdata = Object.assign({}, data);
                        break;
                    case 'right':
                        if (!data.oldpath) this.$.filesright.config = Object.assign({ name: 'right', data: data }, this.gridConfig);
                        else this.$.filesright.configdata = Object.assign({}, data);
                        break;
                }
            }
            this.refreshCount = 0;
        } else { // restore old path or fall back to root before ending up in a refresh loop!
            let path;
            if (this.refreshCount < this.refreshCountMax) {
                path = cmd.data.oldpath;
                this.refreshCount += 1;
            } else {
                path = '/';
                this._setStatus('invalidPathDetectedFallingBackToRoot');
                this._log('_cmdUpdatePath(): Invalid Path detected falling back to root!', 'ERROR');
            }
            switch (cmd.data.pane) {
                case 'left':
                    this.activepathleft = path;
                    break;
                case 'right':
                    this.activepathright = path;
                    break;
            }
            this._refreshPath();
        }
        return fs;
    }

    /****************************************************************************************************
     * Implements the _cmdDeletePath command.
     *
     * @async
     * @private
     * @param {Object} cmd The command object which contains the data for the command.
     * @returns {Object} returns a status object.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    async _cmdDeletePath(cmd) {
        const dir = this._convertPath(cmd.data.path);
        const result = await this.fmApi.remove(dir, (progress) => {
            this._updateProgress(progress)
        }, undefined, undefined, cmd.id).catch((error) => {
            return error;
        });

        if (!result.status) {
            if (this.clipboard.length > 0) {
                let newclipboard = [];
                for (const row of this.clipboard) {
                    if (!row.path.startsWith(cmd.data.path)) {
                        newclipboard.push(row);
                    }
                }
                this.clipboard = newclipboard;
            }

            if (cmd.data.type === 'folder') {
                switch (this.activepane) {
                    case 'left':
                        if (this.activepathright.startsWith(cmd.data.path)) {
                            this.activepathright = this.activepathleft;
                        }
                        break;
                    case 'right':
                        if (this.activepathleft.startsWith(cmd.data.path)) {
                            this.activepathleft = this.activepathright;
                        }
                        break;
                }
            }
            this._refreshPanes();
        }
        return result;
    }

    /****************************************************************************************************
     * Implements the _cmdCreateFolder command.
     *
     * @async
     * @private
     * @param {Object} cmd The command object which contains the data for the command.
     * @returns {Object} returns a status object.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    async _cmdCreateFolder(cmd) {
        const dir = this._convertPath(cmd.data.path + cmd.data.name);
        const result = await this.fmApi.makeDir(dir, cmd.id).catch((error) => {
            return error;
        });
        if (!result.status) {
            this._refreshPanes();
        }
        return result;
    }

    /****************************************************************************************************
     * Implements the _cmdCopyMovePath command.
     *
     * @async
     * @private
     * @param {Object} cmd The command object which contains the data for the command.
     * @returns {Object} returns a status object.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    async _cmdCopyMovePath(cmd) {
        const dstname = this._convertPath(cmd.data.destination);
        const srcname = this._convertPath(cmd.data.source);
        let command;

        if (cmd.data.move) {
            command = 'move';
        } else {
            command = 'copy';
        }

        const result = await this.fmApi[command](dstname, srcname, (progress) => {
            this._updateProgress(progress)
        }, undefined, undefined, cmd.id).catch((error) => {
            return error;
        });

        if (!result.status) {
            this._refreshPanes();
        }
        return result;
    }


    /****************************************************************************************************
     * Implements the _cmdRenamePath command.
     *
     * @async
     * @private
     * @param {Object} cmd The command object which contains the data for the command.
     * @returns {Object} returns a status object.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    async _cmdRenamePath(cmd) {
        const path = this._convertPath(cmd.data.path);
        const oldname = path + cmd.data.oldname;
        const newname = path + cmd.data.newname;
        const result = await this.fmApi.rename(newname, oldname, cmd.id).catch((error) => {
            return error;
        });
        if (!result.status) {
            this._refreshPanes();
        }
        return result;
    }

    /****************************************************************************************************
     * Converts the native filesystem object returned by the filemanager API
     * to a format which can be rendered by the listview.
     *
     * @private
     * @param {Object} fs The native filesystem object returned by the filemanager API.
     * @param {String} targetpane The pane for which the filesystem should be build.
     * @returns {Object | null} The converted filesystem object, which can be rendered by the listview or null.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _buildNodeFromFilesystem(fs, targetpane) {
        let allowedDrives = [];
        if (this.allowedvolumes.length > 0) {
            allowedDrives = this.allowedvolumes.split(',');
        }
        if (fs.root instanceof Object) {
            const node = {
                parent: '',
                path: '/',
                name: 'root',
                type: 'root',
                size: '',
                created: '',
                modified: '',
                accessed: '',
                attributes: {},
                nodes: []
            };
            const volumes = [];
            fs.root.nodes.forEach(drive => {
                if (allowedDrives.indexOf(drive.dpne) > -1 || allowedDrives.length === 0) {
                    const volume = {
                        parent: '/',
                        path: '/' + drive.dpne + '/',
                        name: drive.dpne,
                        type: 'volume',
                        attributes: drive.attribute
                    };
                    volumes.push(volume);
                }
            });
            node.nodes = volumes;
            return node;
        }

        if (fs.parent instanceof Object) {
            const node = {
                parent: '/',
                path: '/',
                name: 'root',
                type: '',
                size: 0,
                created: 0,
                modified: 0,
                attributes: {},
                nodes: []
            };
            const childs = [];

            let filter, regex;
            (targetpane === 'right') ? regex = this.filefilterright : regex = this.filefilterleft;
            try {
                filter = new RegExp(regex, 'g');
            } catch (error) {
                filter = new RegExp('', 'g');
                this._log('_buildNodeFromFilesystem(): ' + error.message, 'WARNING');
            }

            fs.parent.nodes.forEach(node => {
                let type, parent, path, push = false;
                const attributes = this.fmApi.getFileAttributesAsArray(node.attribute);
                if (node.dpne !== '.') {
                    if (attributes.directory) {
                        if (node.dpne === '..') {
                            type = 'parent';
                            parent = (fs.parent.root) ? '\\' : this._getParentPath(fs.parent.dpne);
                            path = (fs.parent.root) ? '\\' : this._getParentPath(fs.parent.dpne);
                            if (targetpane === 'left' && this.lockstartpathleft === true && this.hideparentleft === true) {
                                
                                const startpathleft = this._makeValidStartPath(this.startpathleft);
                                if (this.activepathleft === startpathleft) {
                                    push = false;
                                }
                                else {
                                    push = true;
                                }
                            }
                            else {
                                if (targetpane === 'right' && this.lockstartpathright === true && this.hideparentright === true){

                                    const startpathright = this._makeValidStartPath(this.startpathright);
                                    if (this.activepathright === startpathright) {
                                        push = false;
                                    }
                                    else {
                                        push = true;
                                    }
                                }
                                else {
                                    push = true;
                                }
                            }
                            
                        } else if (!this.nofolders) {
                            type = 'folder'
                            parent = fs.parent.dpne;
                            path = fs.parent.dpne + node.dpne + '\\';
                            push = true;
                        }
                    } else if (!this.nofiles && filter.test(node.dpne)) {
                        filter.lastIndex = 0;
                        type = 'file';
                        parent = fs.parent.dpne;
                        path = fs.parent.dpne + node.dpne;
                        push = true;
                    }

                    if (push && ((!attributes.hidden || this.showhiddennodes) && (!attributes.system || this.showsystemnodes))) {
                        const item = {
                            parent: this._convertPath(parent),
                            path: this._convertPath(path),
                            name: node.dpne,
                            type: type,
                            size: (type === 'file' && !isNaN(node.size)) ? this._humanFileSize(node.size) : '',
                            created: (type !== 'parent' && type !== 'volume') ? this._getFulldate(node.cdate, node.ctime, true) : '',
                            modified: (type !== 'parent' && type !== 'volume') ? this._getFulldate(node.mdate, node.mtime, true) : '',
                            accessed: (type !== 'parent' && type !== 'volume') ? this._getFulldate(node.adate, node.atime, true) : '',
                            attributes: attributes
                        };
                        childs.push(item);
                    }
                }
            });
            node.nodes = childs.sort((a, b) => {
                return this._sort(a.type, b.type) || this._sort(a.name, b.name, false);
            });
            return node;
        }
        return null;
    }

    /****************************************************************************************************
     * Converts a given filesystem path to and from windows to unix.
     *
     * @private
     * @param {String} [path=''] The path which should be converted.
     * @returns {String} The converted path.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _convertPath(path = '') {
        let converted = path;
        if (path.startsWith('/')) { // UNIX => WIN
            converted = converted.substring(1).replace(/\//g, '\\');
            converted = converted.substr(0, 1) + ":" + converted.substr(1);
        } else { // WIN => UNIX
            const prefix = (path === '\\') ? '' : '/';
            converted = prefix + converted.replace(/\\/g, '/');
            converted = converted.replace(/:/g, '');
        }
        return converted;
    }

    /****************************************************************************************************
     * Extracts the parent path of a given filesystem path.
     *
     * @private
     * @param {String} path The path to extract the parent from.
     * @returns {Sting} The extracted parent path.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _getParentPath(path) {
        let converted = path;
        let delimiter = '\\';
        if (path.startsWith('/')) {
            delimiter = '/';
        }
        if (converted.substring(converted.length - 1) === delimiter) {
            converted = converted.substring(0, converted.length - 1);
        }

        converted = converted.slice(0, converted.lastIndexOf(delimiter)) + delimiter;

        if (converted.length <= 2) {
            return delimiter;
        } else {
            return converted;
        }
    }

    /****************************************************************************************************
     * Converts a given filesize in bytes to a human readable format.
     *
     * @private
     * @param {Number} bytes The filessize in bytes.
     * @param {Format} si The format ('kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] : ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB') to convert to.
     * @returns {String} The human readable format.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _humanFileSize(bytes, si) {
        let thresh = si ? 1000 : 1024;
        if (Math.abs(bytes) < thresh) {
            return bytes + ' B';
        }
        var units = si ? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] : ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
        var u = -1;
        do {
            bytes /= thresh;
            ++u;
        } while (Math.abs(bytes) >= thresh && u < units.length - 1);
        return bytes.toFixed(1) + ' ' + units[u];
    }

    /****************************************************************************************************
     * Converts a given date & time into a full date/time string.
     *
     * @private
     * @param {Number} date The date timestamp
     * @param {Number} time The time timestamp
     * @param {boolean} [noSeconds=false] If true, the seconds are not returned.
     * @returns {String} The full date and time string 
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _getFulldate(date, time, noSeconds = false) {
        const fulldate = this.utilsApi.getSigDateTimeAsString(date, time, '.', ':');
        if (noSeconds) {
            return fulldate.substring(0, fulldate.length - 3);
        } else {
            return fulldate;
        }
    }

    /****************************************************************************************************
     * Updates the progress of a running command, called by the filemanager API.
     *
     * @private
     * @param {Object} status A status object containing the uid and progress of the command.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _updateProgress(status) {
        if (this.queueRunning) {
            if (status.uid === this.queueActiveCommand.id) {
                const progress = status.progress / 10;
                this.progress = progress;
                this._updateCustomProgressWnd();
            }
        }
    }

    /****************************************************************************************************
     * Refreshes the complete filemanager UI.
     * 
     * @private
     * @returns  {Undefined}
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _refreshGui() {
        this._refreshToolbars();
        this._refreshPath();
        this._refreshPanes();
    }

    /****************************************************************************************************
     * Refreshes the path of the active pane.
     *
     * @private
     * @returns  {Undefined}
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _refreshPath() {
        switch (this.activepane) {
            case 'left':
                this._renderPath(this.activepathleft, null);
                break;
            case 'right':
                this._renderPath(this.activepathright, null);
                break;
        }
    }

    /****************************************************************************************************
     * This event handler handles the LANGUAGE_CHG event of the runtime and switches the language.
     *
     * @private
     * @param {Number} majorId The major id of the runtime event.
     * @param {Number} minorId The minor id of the runtime event.
     * @param {Object} msg The payload of the runtime event.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    async _switchLang(majorId, minorId, msg) {
        if (this.tmApi) {
            try {
                const texts = await this.tmApi.getTextsAsync(this._getTextsObject());
                if (this.titletext !== '') texts[this.controlTextList].caption = this.titletext;
                this.texts = texts[this.controlTextList];
                this.defaultStatus = this.texts.defaultStatus;
                this._setPropertyText('status');
                this._refreshGui();                
            }
            catch(error) {
                this._log('_switchLang(): failed to get texts -> ' + error, 'ERROR');
            }
        }
    }

    /****************************************************************************************************
     * Called by the Designer Runtime when the project language changes.
     * @param {Object} language The definition object of the current language.
     * @return {Undefined} Undefined 
     * @memberof LasalRuntimeSigControlFilemanager
     ****************************************************************************************************/
    designerOnLanguageChanged() {
        this._switchLang();
    }

    /****************************************************************************************************
     * Called by the Designer Runtime if the ObjectStore has been updated.
     * @async
     * @param {Object} data The payload of the ObjectStore command which triggered the update.
     * @return {Promise} Returns a Promise, which is resolved after the Textlist update is complete.
     * @memberof LasalRuntimeSigControlFilemanager
     ****************************************************************************************************/
    async designerOnObjectStoreUpdate(data) {
        try {
            const textListChanged = await this.tmApi.isTextListUpdate(data, this.controlTextList);
            if (textListChanged) this._switchLang();            
        }
        catch(error) {
            this._log('designerOnObjectStoreUpdate(): failed to check for text list update -> ' + error, 'ERROR');
        }
    }

    /****************************************************************************************************
     * Returns a text object with internal fallback values.
     * They are shown if a text could not be resolved by the textmanager API.
     * 
     * @private
     * @returns {Object} The text list object.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _getTextsObject() {
        return {
            [this.controlTextList]: {
                caption: 'Filemanager',
                home: 'Home',
                defaultStatus: 'Ready',
                cancel: 'Cancel',
                cancelAll: 'Cancel all',
                pause: 'Pause',
                continue: 'Continue',
                tReloadPanes: 'Reload Panes (P)',
                tDeleteSelection: 'Delete selection (DEL)',
                tCreateFolder: 'Create folder (F)',
                tCopySelectionToClipboard: 'Copy selection to clipboard (CTRL+C)',
                tCutSelectionToClipboard: 'Cut selection to clipboard (CTRL+X)',
                tPasteSelectionFromClipboard: 'Paste selection from clipboard (CTRL+V)',
                tRenameActiveItem: 'Rename active item (R)',
                tFolderUp: 'Move to parent directory (U)',
                tMoveSelection: 'Move selection (M)',
                tCopySelection: 'Copy selection (C)',
                progressCompleted: 'completed',
                filter: 'Filter',
                filterTitle: 'Please enter a regular expression to filter files'
            }
        }
    }

    /****************************************************************************************************
     * Refreshes both panes and reloads the current path of each pane.
     *
     * @private
     * @param {boolean} [restorerow=false] If true the row curser will be restored to the current active position if possible.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _refreshPanes(restorerow = false) {
        if (this.queue.length <= 2 && (this.queueActiveCommand === null || this.queueActiveCommand.type !== '_cmdUpdatePath')) {
            this._updatePath('left', this.activepathleft, null, restorerow);
            this._updatePath('right', this.activepathright, null, restorerow);
        }
    }

    /****************************************************************************************************
     * Generates a human readable progress message.
     *
     * @private
     * @param {Number} progress Progress in percentage.
     * @returns {String} The progress message or an empty sting.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _computeProgress(progress) {
        this.$.progressbar.style.width = progress + '%';
        if (progress > 0)
            return progress + '% ' + this.texts.progressCompleted;
        else {
            return '';
        }
    }

    /****************************************************************************************************
     * This event handler handles the 'WS_STATE_CHG' runtime event.
     * If the connection is lost, the UI of the filemanager is blocked and the command queue is stopped.
     * After the connection is established again, the UI is released and the command queue is started.
     *
     * @private
     * @param {Number} majorId The major id of the runtime event.
     * @param {Number} minorId The minor id of the runtime event.
     * @param {Object} msg The payload of the runtime event.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _onWSStateChg(majorId, minorId, msg) {
        switch (msg.state) {
            case window.sigApi.SIG_CONST.STAT_WS_OPEN:
                this.isonline = true;
                this.iswaiting = false;
                this._setStatus('connectionEstablished');
                this._queueStart();
                break;
            default:
                this.isonline = false;
                this._queueStop();
                this._setStatus('waitingForConnection');
                this.iswaiting = true;
                break;
        }
    }

    /****************************************************************************************************
     * Starts the processing of the command queue.
     * If the queue is not empty, you will be prompted to clear the queue.
     *
     * @private
     * @param {boolean} [checkQueue=true] Set false if you do not want to show the confirm dialog, the queue is cleared.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    async _queueStart(checkQueue = true) {
        if (checkQueue) {
            const queueCount = this._queueGetLength();
            if (queueCount > 0) {
                const restartQueue = await this._showConfirm(`There are unfinished commands in the queue. Do you want to execute ${queueCount} command(s)?`, 'Unfinished commands found').then(result => {
                    return true;
                }).catch(error => {
                    this._log('_queueStart(): ' + error, 'ERROR');
                    return false;
                });
                this.systemWindowOpened = false;
                if (!restartQueue) {
                    this._queueClear();
                    this._refreshPanes();
                }
            }
        } else {
            this._queueClear();
            this._refreshPanes();
        }
        this.queueActive = true;
    }

    /****************************************************************************************************
     * Stops the processing of the command queue.
     *
     * @private
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _queueStop() {
        this.queueActive = false;
        this.queueRunning = false;
        this.queueActiveCommand = null;
        this.progress = 0;
    }

    /****************************************************************************************************
     * Pauses the processing of the command queue.
     *
     * @private
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _queuePause() {
        this._setWaitingStatus('waitingForActiveCommandToFinish');
        this.queueActive = false;
    }

    /****************************************************************************************************
     * Continues the processing of the command queue.
     *
     * @private
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _queueContinue() {
        this._setWaitingStatus('startingTheQueue');
        this.queueActive = true;
    }

    /****************************************************************************************************
     * Clears all commands in the command queue.
     *
     * @private
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _queueClear() {
        this.queue = [];
    }

    /****************************************************************************************************
     * This observer updates the queue stats object if the command queue is updated.
     *
     * @private
     * @param {Object} newval The new value of th observed polymer property.
     * @param {Object} oldval The old value of th observed polymer property.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _updateQueue(newval, oldval) {
        this.queuestats = {
            count: this._queueGetLength()
        }
    }

    /****************************************************************************************************
     * Returns the current count of commands in the command queue.
     *
     * @private
     * @returns {Number} The count of commands in the command queue.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _queueGetLength() {
        let count = 0;
        this.queue.forEach(cmd => {
            if (!cmd.silent) {
                count += 1;
            }
        });
        return count;
    }

    /****************************************************************************************************
     * Builds a human readable status message based on the given command.
     *
     * @private
     * @param {Object} [cmd=this.queueActiveCommand] The command to build the message for.
     * @returns {String} The humnan readable status message.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    async _buildStatusMessage(cmd = this.queueActiveCommand) {
        if (cmd) {
            if (!cmd.silent) {
                try {
                    switch (cmd.command) {
                        case '_cmdCopyMovePath':
                            if (cmd.data.move) {
                                return await this.tmApi.getTextWithParameterAsync(this._getTextObj('moveSoureToDestination', [cmd.data.source, cmd.data.destination]));
                            } else {
                                return await this.tmApi.getTextWithParameterAsync(this._getTextObj('copySoureToDestination', [cmd.data.source, cmd.data.destination]));
                            }
                        case '_cmdRenamePath':
                            return await this.tmApi.getTextWithParameterAsync(this._getTextObj('renameOldnameToNewname', [cmd.data.oldname, cmd.data.newname]));
                        case '_cmdCreateFolder':
                            return await this.tmApi.getTextWithParameterAsync(this._getTextObj('createFolderInPath', [cmd.data.name, cmd.data.path]));
                        case '_cmdDeletePath':
                            return await this.tmApi.getTextWithParameterAsync(this._getTextObj('deletePath', [cmd.data.path]));
                        default:
                            this._log(`_buildStatusMessage(): Cant build status message! Command ${cmd.data.command} not supported!`, 'ERROR');
                            return '';
                    }                    
                }
                catch(error) {
                    this._log('_buildStatusMessage(): get text with parameter failed -> ' + error, 'ERROR');
                }
            } else {
                return '';
            }
        } else {
            this._log('_buildStatusMessage(): Cant build status message, cmd is undefined', 'ERROR');
            return '';       
        }
    }

    /****************************************************************************************************
     * This observer toggles the waiting layer, which blocks the filemanager UI on long running tasks.
     *
     * @private
     * @param {Boolean} newval The new value of the observed polymer property.
     * @param {Boolean} oldval The old value of the observed polymer property.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _toggleIsWaiting(newval, oldval) {
        if (newval) {
            this.showiswaiting = true;
            if (this.queuestats.count > 0) {
                if (this.queuestats.count > 1) {
                    this.showprogress = true;
                } else {
                    this.iswaitingTimeout = this.sigSetTimeout(() => {
                        this.showprogress = true;
                    }, this.iswaitingDelay);
                }
            }
        } else {
            if (this.iswaitingTimeout !== null) {
                this.sigClearTimeout(this.iswaitingTimeout);
            }
            if (this._queueGetLength() === 0) {
                this.showprogress = false;
                this.showiswaiting = false;
            }
        }
    }

    /****************************************************************************************************
     * This observer clears the message in the status bar after a timeout.
     *
     * @private
     * @param {String} newval The new value of the observed polymer property.
     * @param {String} oldval The old value of the observed polymer property.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _autoClearStatus(newval, oldval) {
        if (newval !== this.defaultStatus && this.queuestats.count === 0 && this.isonline) {
            this.statusAutoClearTimeout = this.sigSetTimeout(() => {
                this._setStatus('defaultStatus');
            }, this.statusAutoClearDelay);
        }
    }

    /****************************************************************************************************
     * Sets the message in the status bar.
     *
     * @private
     * @param {String} [text=''] The message to set - may contain placeholders for parameters.
     * @param {Array} [param=[]] An array of parameters.
     * @param {String} [textList=this.controlTextList] The name of the textlist to use.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _setStatus(text = '', param = [], textList = this.controlTextList) {
        if (!this.isdesignmode) {
            const obj = this._getTextObj(text, param, textList);
            this._setPropertyText('status', obj);
            this._updateCustomProgressWnd();
        }
    }

    /****************************************************************************************************
     * Sets the message in the progress dialog.
     *
     * @private
     * @param {String} [text=''] The message to set - may contain placeholders for parameters.
     * @param {Array} [param=[]] An array of parameters.
     * @param {String} [textList=this.controlTextList] The name of the textlist to use.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _setWaitingStatus(text = '', param = [], textList = this.controlTextList) {
        const obj = this._getTextObj(text, param, textList);
        this._setPropertyText('waitingstatus', obj);
        this._updateCustomProgressWnd();
    }

    /****************************************************************************************************
     * Generates the preview in the designer.
     * 
     * @private
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _renderPreview() {
        this.texts = this._getTextsObject()[this.controlTextList];

        this._refreshPath();

        this.status = 'Design mode';
        this.isactive = true;
        const demodata = {
            cols: this._getColsConfig(),
            data: {
                parent: "/",
                path: "/",
                name: "root",
                type: "",
                size: 0,
                created: 0,
                modified: 0,
                attributes: {},
                nodes: [{
                    parent: "/C/",
                    path: "/C/",
                    name: "..",
                    type: "parent",
                    size: "",
                    created: "",
                    modified: "",
                    accessed: "",
                    attributes: 16,
                    active: false
                }, {
                    parent: "/C/Demodata/",
                    path: "/C/Demodata/demofolder1/",
                    name: "folder1 selected",
                    type: "folder",
                    size: "",
                    created: "11.06.2018 09:06",
                    modified: "11.06.2018 09:06",
                    accessed: "11.06.2018 09:06",
                    attributes: 16,
                    active: true,
                }, {
                    parent: "/C/Demodata/",
                    path: "/C/Demodata/demofolder2/",
                    name: "folder2 selected marked",
                    type: "folder",
                    size: "",
                    created: "11.06.2018 09:06",
                    modified: "11.06.2018 09:06",
                    accessed: "11.06.2018 09:06",
                    attributes: 16,
                    active: true,
                    marked: true,
                }, {
                    parent: "/C/Demodata/",
                    path: "/C/Demodata/demofile1.txt",
                    name: "file1.txt normal (even)",
                    type: "file",
                    size: "57.2 KiB",
                    created: "11.06.2018 09:06",
                    modified: "11.06.2018 09:06",
                    accessed: "11.06.2018 09:06",
                    attributes: 32
                }, {
                    parent: "/C/Demodata/",
                    path: "/C/Demodata/demofile2.txt",
                    name: "file2.txt alternate (odd)",
                    type: "file",
                    size: "57.2 KiB",
                    created: "11.06.2018 09:06",
                    modified: "11.06.2018 09:06",
                    accessed: "11.06.2018 09:06",
                    attributes: 32
                },
                {
                    parent: "/C/Demodata/",
                    path: "/C/Demodata/demofile3.txt",
                    name: "file3.txt marked",
                    type: "file",
                    size: "57.2 KiB",
                    created: "11.06.2018 09:06",
                    modified: "11.06.2018 09:06",
                    accessed: "11.06.2018 09:06",
                    attributes: 32,
                    marked: true
                },
                {
                    parent: "/",
                    path: "/C/",
                    name: "Drive icon preview",
                    type: "volume",
                    size: "",
                    created: "",
                    modified: "",
                    accessed: "",
                    attributes: 32,
                }]
            }
        };

        this.$.filesleft.config = Object.assign({ name: 'left', data: demodata }, this.gridConfig);
        this.$.filesright.config = Object.assign({ name: 'right', data: demodata }, this.gridConfig);

        this.sigSetTimeout(() => {
            this.$.filesleft.activerow = 2;
            this.$.filesright.activerow = 2;
            this.$.filesleft.isactive = true;
            this.$.filesright.isactive = true;
        }, 20);
    }

    /****************************************************************************************************
     * Handles the 'evtHandlerReload' event defined in the JSON description of the component
     * and executes it, if the runtime fires the defined event.
     * 
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    evtHandlerReload() {
        this._actionReload();
    }

    /****************************************************************************************************
     * Handles the 'evtHandlerDeleteSelection' event defined in the JSON description of the component
     * and executes it, if the runtime fires the defined event.
     *
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    evtHandlerDeleteSelection() {
        this._actionDeleteSelection();
    }

    /****************************************************************************************************
     * Handles the 'evtHandlerCopySelection' event defined in the JSON description of the component
     * and executes it, if the runtime fires the defined event.
     *
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    evtHandlerCopySelection() {
        this._actionCopySelection();
    }

    /****************************************************************************************************
     * Handles the 'evtHandlerMoveSelection' event defined in the JSON description of the component
     * and executes it, if the runtime fires the defined event.
     *
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    evtHandlerMoveSelection() {
        this._actionMoveSelection();
    }

    /****************************************************************************************************
     * Handles the 'evtHandlerRename' event defined in the JSON description of the component
     * and executes it, if the runtime fires the defined event.
     *
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    evtHandlerRename() {
        this._actionRenameActiveItem();
    }

    /****************************************************************************************************
     * Handles the 'evtHandlerFolderUp' event defined in the JSON description of the component
     * and executes it, if the runtime fires the defined event.
     *
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    evtHandlerFolderUp() {
        this._actionFolderUp();
    }

    /****************************************************************************************************
     * Handles the 'evtHandlerCreateFolder' event defined in the JSON description of the component
     * and executes it, if the runtime fires the defined event.
     *
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    evtHandlerCreateFolder() {
        this._actionCreateFolder();
    }

    /****************************************************************************************************
     * Handles the 'evtHandlerMarkRow' event defined in the JSON description of the component
     * and executes it, if the runtime fires the defined event.
     *
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    evtHandlerMarkRow() {
        switch (this.activepane) {
            case 'left':
                this.$.filesleft._markRowById();
                break;
            case 'right':
                this.$.filesright._markRowById();
                break;
        }
    }

    /****************************************************************************************************
     * Handles the 'evtHandlerMarkAllRows' event defined in the JSON description of the component
     * and executes it, if the runtime fires the defined event.
     *
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    evtHandlerMarkAllRows() {
        switch (this.activepane) {
            case 'left':
                this.$.filesleft.markAllRows();
                break;
            case 'right':
                this.$.filesright.markAllRows();
                break;
        }
    }

    /****************************************************************************************************
     * Handles the 'evtHandlerClearMarkedRows' event defined in the JSON description of the component
     * and executes it, if the runtime fires the defined event.
     *
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    evtHandlerClearMarkedRows() {
        switch (this.activepane) {
            case 'left':
                this.$.filesleft.clearMarkedRows();
                break;
            case 'right':
                this.$.filesright.clearMarkedRows();
                break;
        }
    }

    /****************************************************************************************************
     * Handles the 'evtHandlerMoveCursorDown' event defined in the JSON description of the component
     * and executes it, if the runtime fires the defined event.
     *
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    evtHandlerMoveCursorDown() {
        switch (this.activepane) {
            case 'left':
                this.$.filesleft.moveCursorDown();
                break;
            case 'right':
                this.$.filesright.moveCursorDown();
                break;
        }
    }

    /****************************************************************************************************
     * Handles the 'evtHandlerMoveCursorUp' event defined in the JSON description of the component
     * and executes it, if the runtime fires the defined event.
     *
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    evtHandlerMoveCursorUp() {
        switch (this.activepane) {
            case 'left':
                this.$.filesleft.moveCursorUp();
                break;
            case 'right':
                this.$.filesright.moveCursorUp();
                break;
        }
    }

    /****************************************************************************************************
     * Handles the 'evtHandlerMoveCursorTop' event defined in the JSON description of the component
     * and executes it, if the runtime fires the defined event.
     *
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    evtHandlerMoveCursorTop() {
        switch (this.activepane) {
            case 'left':
                this.$.filesleft.moveCursorTop();
                break;
            case 'right':
                this.$.filesright.moveCursorTop();
                break;
        }
    }

    /****************************************************************************************************
     * Handles the 'evtHandlerMoveCursorEnd' event defined in the JSON description of the component
     * and executes it, if the runtime fires the defined event.
     *
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    evtHandlerMoveCursorEnd() {
        switch (this.activepane) {
            case 'left':
                this.$.filesleft.moveCursorBottom();
                break;
            case 'right':
                this.$.filesright.moveCursorBottom();
                break;
        }
    }

    /****************************************************************************************************
     * Handles the 'evtHandlerPageUp' event defined in the JSON description of the component
     * and executes it, if the runtime fires the defined event.
     *
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    evtHandlerPageUp() {
        switch (this.activepane) {
            case 'left':
                this.$.filesleft.moveCursorPageUp();
                break;
            case 'right':
                this.$.filesright.moveCursorPageUp();
                break;
        }
    }

    /****************************************************************************************************
     * Handles the 'evtHandlerPageDown' event defined in the JSON description of the component
     * and executes it, if the runtime fires the defined event.
     *
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    evtHandlerPageDown() {
        switch (this.activepane) {
            case 'left':
                this.$.filesleft.moveCursorPageDown();
                break;
            case 'right':
                this.$.filesright.moveCursorPageDown();
                break;
        }
    }

    /****************************************************************************************************
     * Handles the 'evtHandlerSwitchPanes' event defined in the JSON description of the component
     * and executes it, if the runtime fires the defined event.
     *
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    evtHandlerSwitchPanes() {
        this._switchPane();
    }

    /****************************************************************************************************
     * Handles the 'evtHandlerClipboardCopy' event defined in the JSON description of the component
     * and executes it, if the runtime fires the defined event.
     *
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    evtHandlerClipboardCopy() {
        this._actionClipboardCopy();
    }

    /****************************************************************************************************
     * Handles the 'evtHandlerClipboardPaste' event defined in the JSON description of the component
     * and executes it, if the runtime fires the defined event.
     *
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    evtHandlerClipboardPaste() {
        this._actionClipboardPaste();
    }

    /****************************************************************************************************
     * Handles the 'evtHandlerDblClickRow' event defined in the JSON description of the component
     * and executes it, if the runtime fires the defined event.
     *
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    evtHandlerDblClickRow() {
        switch (this.activepane) {
            case 'left':
                this.$.filesleft._handleActionOnEnter();
                break;
            case 'right':
                this.$.filesright._handleActionOnEnter();
                break;
        }
    }

    /****************************************************************************************************
     * Handles the 'evtHandlerGoHome' event defined in the JSON description of the component
     * and executes it, if the runtime fires the defined event.
     *
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    evtHandlerGoHome() {
        switch (this.activepane) {
            case 'left':
                this.activepathleft = "/";
                break;
            case 'right':
                this.activepathright = "/";
                break;
        }
    }

    /****************************************************************************************************
     * This observer toggles if the row cursor can be moved using the keyboard.
     *
     * @private
     * @param {Boolean} newval The new value of the observer polymer property.
     * @param {Boolean} oldval The old value of the observer polymer property.
     * @returns {Undefined} Undefined 
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _toggleDisableKeyMovement(newval, oldval) {
        if (!this.disablekeymovement) {
            this.$.filesleft.disablekeys = newval;
            this.$.filesright.disablekeys = newval;
        } else {
            this.$.filesleft.disablekeys = true;
            this.$.filesright.disablekeys = true;
        }
    }

    /****************************************************************************************************
     * This observer toggles if multiple rows can be selected (marked).
     *
     * @private
     * @param {Boolean} newval The new value of the observer polymer property.
     * @param {Boolean} oldval The old value of the observer polymer property.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _toggleDisableMultiselect(newval, oldval) {
        this.$.filesleft.allowmultiselection = !newval;
        this.$.filesright.allowmultiselection = !newval;
    }

    /****************************************************************************************************
     * This observer toggles if the system dialogs support keyboard control.
     *
     * @private
     * @param {Boolean} newval The new value of the observer polymer property.
     * @param {Boolean} oldval The old value of the observer polymer property.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
     * @todo Needs implementation
    ****************************************************************************************************/
    _toggleDisableKeysInDialogs(newval, oldval) {
        // Needs implementation after system windows support keyboard shortcuts
    }

    /****************************************************************************************************
     * This observer opens the custom progress window, if defined and deactivates the keyboard support of the listview if the progress dialog is opened.
     *
     * @private
     * @param {Boolean} newval The new value of the observer polymer property.
     * @param {Boolean} oldval The old value of the observer polymer property.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _toggleShowProgress(newval, oldval) {
        const windowObj = this.wmApi.getWindow(this.progresswindow);

        if(windowObj !== null){
            if (newval) {
                this.wmApi.openWindow(this.progresswindow);

                this.progressWindowContent = { 
                    buttoncontinue: this._getWindowChild(windowObj, "continue").getDomRef(),
                    buttonpause: this._getWindowChild(windowObj, "pause").getDomRef(),
                    buttoncancel: this._getWindowChild(windowObj, "cancel").getDomRef(),
                    buttoncancelall: this._getWindowChild(windowObj, "cancelAll").getDomRef(),
                    barprogress: this._getWindowChild(windowObj, "progress").getDomRef(),
                    textwaitingstatus: this._getWindowChild(windowObj, "waitingStatus").getDomRef(),
                    textstatus: this._getWindowChild(windowObj, "status").getDomRef()
                };     

                if(this.progressWindowContent.barProgress){ 
                    this._setWindowChildContent(this.progressWindowContent.barprogress, this.progress); 
                    this._setWindowChildContent(this.progressWindowContent.barprogress, '%', 'unittext'); 
                }

                if(this.progressWindowContent.textwaitingstatus){ this._setWindowChildContent(this.progressWindowContent.textwaitingstatus, this.waitingstatus, 'sigtext'); }

                if(this.progressWindowContent.textStatus){ this._setWindowChildContent(this.progressWindowContent.textstatus, this.status, 'sigtext'); }
        
                if(this.progressWindowContent.buttoncontinue){        
                    this.progressWindowContent.buttoncontinue.sigAddEventListener("mousedown", () => {
                        if(this._canContinue(this.queueActive, this.queuestats.count, this.queueRunning) === true){
                            this._queueContinue();
                        }
                    });
                }
                if(this.progressWindowContent.buttonpause){        
                    this.progressWindowContent.buttonpause.sigAddEventListener("mousedown", () => {
                        if(this._canPause(this.queueActive, this.queuestats.count) === true){
                            this._queuePause();
                        }
                    });
                }
                if(this.progressWindowContent.buttoncancelall){        
                    this.progressWindowContent.buttoncancelall.sigAddEventListener("mousedown", () => {
                        if(this._canCancelAll(this.queueActive, this.queuestats.count) === true){
                            this._queueCancelAllCommand();
                        }
                    });
                }
                if(this.progressWindowContent.buttoncancel){        
                    this.progressWindowContent.buttoncancel.sigAddEventListener("mousedown", () => {
                        if(this._canCancel(this.queueActive, this.queuestats.count) === true){
                            this._queueCancelCommand();
                        }
                    });
                }
            } else {
                if (this.progressWindowContent) {
                    if(this.progressWindowContent.buttoncontinue){ this.progressWindowContent.buttoncontinue.sigRemoveAllEventListeners() }
                    if(this.progressWindowContent.buttonpause){ this.progressWindowContent.buttonpause.sigRemoveAllEventListeners() }
                    if(this.progressWindowContent.buttoncancel){ this.progressWindowContent.buttoncancel.sigRemoveAllEventListeners() }
                    if(this.progressWindowContent.buttoncancelall){ this.progressWindowContent.buttoncancelall.sigRemoveAllEventListeners() }

                    this.wmApi.closeWindow(this.progresswindow);                    
                }
            }
        }

        if (!this.disablekeyactions) {
            if (newval) {
                this._toggleDisableKeyMovement(true);
            } else {
                this._toggleDisableKeyMovement(false);
            }
        }
    }

    /****************************************************************************************************
     * Updates the values and states inside the custom progress window.
     *
     * @private
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _updateCustomProgressWnd(){
        this.debouncerProgress = SigPolymer.debouncer.debounce(
            this.debouncerProgress,
            SigPolymer.timeOut.after(50),
            () => {

                if(this.progresswindowset && this.showprogress){   

                    if(this.progressWindowContent.buttoncancel){
                        if(this._canCancel(this.queueActive, this.queuestats.count) === false){
                            this._setWindowChildContent(this.progressWindowContent.buttoncancel, 0, 'value');
                            this._setComponentDisabled(this.progressWindowContent.buttoncancel);
                        }else{
                            this._setComponentEnabled(this.progressWindowContent.buttoncancel);
                        }
                    }

                    if(this.progressWindowContent.buttoncancelall){
                        if(this._canCancelAll(this.queueActive, this.queuestats.count) === false){
                            this._setWindowChildContent(this.progressWindowContent.buttoncancelall, 0, 'value');
                            this._setComponentDisabled(this.progressWindowContent.buttoncancelall);
                        }else{
                            this._setComponentEnabled(this.progressWindowContent.buttoncancelall);
                        }
                    }
        
                    if(this.progressWindowContent.buttonpause){
                        if(this._canPause(this.queueActive, this.queuestats.count) === false){
                            this._setWindowChildContent(this.progressWindowContent.buttonpause, 0, 'value');
                            this._setComponentDisabled(this.progressWindowContent.buttonpause);
                        }else{
                            this._setComponentEnabled(this.progressWindowContent.buttonpause);
                        }
                    }

                    if(this.progressWindowContent.buttoncontinue){
                        if(this._canContinue(this.queueActive, this.queuestats.count, this.queueRunning) === false){
                            this._setWindowChildContent(this.progressWindowContent.buttoncontinue, 0, 'value');
                            this._setComponentDisabled(this.progressWindowContent.buttoncontinue);
                        }else{
                            this._setComponentEnabled(this.progressWindowContent.buttoncontinue);
                        }
                    }

                    if(this.progressWindowContent.barprogress){ 
                        this._setWindowChildContent(this.progressWindowContent.barprogress, this.progress); 
                        this._setWindowChildContent(this.progressWindowContent.barprogress, '%', 'unittext'); 
                    }
        
                    if(this.progressWindowContent.textwaitingstatus){ this._setWindowChildContent(this.progressWindowContent.textwaitingstatus, this.waitingstatus, 'sigtext'); }
        
                    if(this.progressWindowContent.textstatus){ this._setWindowChildContent(this.progressWindowContent.textstatus, this.status, 'sigtext'); }
                }
            }   
        );
    }

    /****************************************************************************************************
     * Sets the state of a component to disabled.
     *
     * @private
     * @param {*} component
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _setComponentDisabled(component) {
        //set button state to inactive
        component.state = 2;
        //check if the opacity property of inactive state is lower 1 otherwise set to 0.5
        //to be compatible to former versions
        let inactiveOpacity = getComputedStyle(component).getPropertyValue('opacity');
        if ((inactiveOpacity === '') || (inactiveOpacity === "1")) {
            inactiveOpacity = 0.5;
            component.style.setProperty("opacity", String(inactiveOpacity));
        }    
    }

    /****************************************************************************************************
     * Sets the state of a component to enabled.
     *
     * @private
     * @param {*} component
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _setComponentEnabled(component) {
        //set state to active again
        component.state = 1;
        //remove opacity style property cause opacity of sig-element is set via class
        component.style.removeProperty("opacity");
    }

    /****************************************************************************************************
     * This observer deactivates the keyboard support of the listview if a system dialog is opened.
     *
     * @private
     * @param {Boolean} newval The new value of the observer polymer property.
     * @param {Boolean} oldval The old value of the observer polymer property.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _toggleSystemWindowOpened(newval, oldval) {
        if (!this.disablekeyactions) {
            if (newval) {
                this._toggleDisableKeyMovement(true);
            } else {
                this._toggleDisableKeyMovement(false);
            }
        }
    }

    /****************************************************************************************************
     * Updates the activerow property of a specific pane with the row data of the selected row.
     * 
     * @private
     * @param {Object} data The row data object.
     * @param {String} pane The name of the pane.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _updateActiveRow(data, pane) {
        this.activerow[pane] = data;
        this.notifyPath('activerow.' + pane);
    }

    /****************************************************************************************************
     * Updates the activeselection property of a specific pane with the row data objects of the current selection.
     *
     * @private
     * @param {Array} data Array of row data objects.
     * @param {String} pane The name of the pane.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _updateSelection(data, pane) {
        this.activeselection[pane] = data;
        this.notifyPath('activeselection.' + pane);
        
        ///////////////////////////////////////////////////////////////////////////////
        // ESYS Patch start
        if (data !== null) {
            if (data.length >= 1) {
                sigApi.datapointManager.readDataPoint('10:SelectedAssistant1.AssistantAktiv', 0).then((resolve) => {
                    const AssistantAktiv = resolve.value;
                    sigApi.datapointManager.readDataPoint('10:SelectedAssistant1.LoadToolActive', 0).then((resolve) => {
                        const LoadToolActive = resolve.value;
                        if (AssistantAktiv === 1 || LoadToolActive === 1) {
                            sigApi.datapointManager.writeDataPoint('10:ToolsName1.Tools_Name_Unsaved', data[0].name);
                        } else {
                            sigApi.datapointManager.writeDataPoint('10:ToolsName1.FileName', data[0].name);
                        }
                    });
                });
            }
        }
        // ESYS Patch end
        ///////////////////////////////////////////////////////////////////////////////


    }


    /****************************************************************************************************
     * Returns a valid path, which can be used as a startpath.
     *
     * @private
     * @param {String} [path=''] The path to convert.
     * @returns {String} The converted valid path.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _makeValidStartPath(path = '') {
        let validpath = path;
        if (path !== '/') {
            validpath = path.replace(/\/+$/, "") + '/';
        }
        return validpath;
    }

    /****************************************************************************************************
     * This callback formats the row symbols of the listview.
     *
     * @private
     * @param {Boolean} marked If true, the row is marked.
     * @param {Object} row The row data object of the row.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _formatSymbol(marked, row) {
        let defaultStyle = 'text-shadow: 1px 1px rgba(0, 0, 0, .4);'
        switch (row.type) {
            case 'parent':
                if(this.folderupimageurl !== '' && this.folderupimageurl !== undefined){
                    return `<img src="${this.folderupimageurl}" width="25px" height="auto">`;
                }else{
                    return `<span style="${defaultStyle} color:var(--theme-sig-control-list-view-folder-up-icon-color,black);">\uf3bf</span>`;
                }

                break;
            case 'volume':
                if(this.driveimageurl !== '' && this.driveimageurl !== undefined){
                    return `<img src="${this.driveimageurl}" width="25px" height="auto">`;
                }else{
                    return `<span style="${defaultStyle} color:var(--theme-sig-control-list-view-volume-icon-color, darkgrey);">\uf0a0</span>`;
                }

                break;
            case 'folder':
                if(this.folderimageurl !== '' && this.folderimageurl !== undefined){
                    return `<img src="${this.folderimageurl}" width="25px" height="auto">`;
                }else{
                    return `<span style="${defaultStyle} color:var(--theme-sig-control-list-view-folder-icon-color,orange);">\uf07b</span>`;
                }
                
                break;
            case 'file':
                if(this.fileimageurl !== '' && this.fileimageurl !== undefined){
                    return `<img src="${this.fileimageurl}" width="25px" height="auto">`;
                }else{
                    return `<span style="${defaultStyle} color:var(--theme-sig-control-list-view-file-icon-color,lightgrey);">\uf15b</span>`;
                }

                break;
            default:
                return '';
        }
    }

    /****************************************************************************************************
     * This callback formats file attributes of the listview.
     *
     * @private
     * @param {Boolead} marked If true the row is marked.
     * @param {Object} row The row data object of the row.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _formatAttributes(marked, row) {
        let html = '';
        const attributes = row.attributes;
        if (attributes instanceof Object) {
            (attributes.readonly) ? html += ' R ' : html += ' W ';
            (attributes.hidden) ? html += ' H ' : html += ' - ';
            (attributes.system) ? html += ' S ' : html += ' - ';
            (attributes.archive) ? html += ' A ' : html += ' - ';
        }
        return html;
    }

    /****************************************************************************************************
     * Returns the configuration of the cols rendered by the listview.
     *
     * @private
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _getColsConfig() {
        return [
            {
                id: 'symbol',
                name: this.symbolcolumntitle,
                type: 'symbol',
                css: { 
                    "background-size": "contain",
                    "background-position": "center",
                    'width': parseFloat(this.widthsymbol) + 'px',
                    "overflow": "hidden"
                },
                default: '&nbsp;',
                visible: this.showsymbol,
                sortable: false,
                formatDataCallback: this._formatSymbol.bind(this),
                order: this.ordersymbol
            },
            {
                id: 'name',
                name: this.filenamecolumntitle,
                type: 'text',
                css: {
                    'width': parseFloat(this.widthfilename) + 'px',
                    "overflow": "hidden"
                },
                default: '&nbsp;',
                visible: this.showfilename,
                sortable: false,
                filterable: this.filenamefilterable,
                order: this.orderfilename
            }, {
                id: 'modified',
                name: this.modifiedcolumntitle,
                type: 'text',
                css: { 
                    'width': parseFloat(this.widthmodified) + 'px',
                    "overflow": "hidden"
                },
                default: '&nbsp;',
                visible: this.showmodified,
                sortable: false,
                formatDataCallback: (dateTimeString, row, col) => this._formatDateTimeString(dateTimeString),
                order: this.ordermodified,
            }, {
                id: 'size',
                name: this.filesizecolumntitle,
                type: 'text',
                css: { 
                    'width': parseFloat(this.widthfilesize) + 'px',
                    "overflow": "hidden" 
                },
                default: '&nbsp;',
                visible: this.showfilesize,
                sortable: false,
                order: this.orderfilesize
            },
            {
                id: 'attributes',
                name: this.attributescolumntitle,
                type: 'text',
                css: { 
                    'width': parseFloat(this.widthattributes) + 'px',
                    "overflow": "hidden"
                },
                default: '&nbsp;',
                visible: this.showattributes,
                sortable: false,
                formatDataCallback: this._formatAttributes,
                order: this.orderattributes
            }].sort((c1, c2) => {
                return c1.order - c2.order;
            });
    }

    /****************************************************************************************************
     * Formats the given date/time into the correct format.
     *
     * @private
     * @param {*} dateTimeString
     * @returns {*}  
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _formatDateTimeString(dateTimeString) {
        const datetime = moment(dateTimeString, this.sigDateTimeFormat);
        return datetime.isValid() ? datetime.format(this.datetimeformat) : '';
    }

    /****************************************************************************************************
     * Observer to update columns if settings have changed.
     * 
     * @private
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _updateColumns() {
        if (this.initialized === true) {
            this.debouncer = SigPolymer.debouncer.debounce(
                this.debouncer,
                SigPolymer.timeOut.after(50),
                () => {

                    if(this.dualpane === true) {
                        
                        this.$.filesleft.config = Object.assign({}, this.$.filesleft.config, {
                            data: {
                                cols: this._getColsConfig(),
                                data: Object.assign([], this.$.filesleft.config.data.data)                            
                            }
                        });

                        this.$.filesright.config = Object.assign({}, this.$.filesright.config, {
                            data: {
                                cols: this._getColsConfig(),
                                data: Object.assign([], this.$.filesright.config.data.data)                            
                            }
                        });

                    }else{
                        this.$.filesleft.config = Object.assign({}, this.$.filesleft.config, {
                            data: {
                                cols: this._getColsConfig(),
                                data: Object.assign([], this.$.filesleft.config.data.data)                            
                            }
                        });    
                    }        

                }
            );
        }
    }

    /****************************************************************************************************
     * This observer sets the restore row on the listview of a pane.
     *
     * @private
     * @param {Boolean} newval The new value of the observer polymer property.
     * @param {Boolean} oldval The old value of the observer polymer property.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _toggleRestoreRow(restorerow = false) {
        this.$.filesleft.restorerow = restorerow;
        this.$.filesright.restorerow = restorerow;
    }

    /****************************************************************************************************
     * This observer toggles the preview of the progress dialog in designmode. 
     *
     * @private
     * @param {Boolean} newval The new value of the observer polymer property.
     * @param {Boolean} oldval The old value of the observer polymer property.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _designtimeshowprogress(newval, oldval) {
        if (this.isdesignmode) {
            if (newval) {
                this.showprogress = true;
                this.iswaiting = true;
                this.queuestats.count = 50;
                this.progress = 50;
            } else {
                this.showprogress = false;
                this.iswaiting = false
                this.queuestats.count = 50;
                this.progress = 0;
            }
        }
    }

    /****************************************************************************************************
     * This observer is executed when the left start path is updated.
     *
     * @private
     * @param {String} newval The new path.
     * @param {String} oldval The old path.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _toggleStartPathLeft(newval, oldval) {
        if (newval) {
            this.validStartPathLeft = this._makeValidStartPath(newval);
            if (this.isdesignmode) {
                this.activepathleft = this.validStartPathLeft;
                this.currentpath = this.validStartPathLeft;
            }
        }
    }

    /****************************************************************************************************
     * This observer is executed when the right start path is updated.
     *
     * @private
     * @param {String} newval The new path.
     * @param {String} oldval The old path.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _toggleStartPathRight(newval, oldval) {
        if (newval) {
            this.validStartPathRight = this._makeValidStartPath(newval);
            if (this.isdesignmode) {
                this.activepathright = this.validStartPathRight;
            }
        }
    }

    /****************************************************************************************************
     * Returns the count of the levels of a given path.
     *
     * @private
     * @param {String} [path='']  The path to check.
     * @param {String} [delimiter='/'] The level delimiter of the path.
     * @returns {Number} The count of the levels
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _getPathLevelsCount(path = '', delimiter = '/') {
        return path.split(delimiter).length - 1;
    }

    /****************************************************************************************************
     * Checks if the given new path is locked (outside) the given start path.
     *
     * @private
     * @param {String} [newPath='']  The path to check.
     * @param {String} [startPath=''] The start path to check against.
     * @returns {Boolean} Returns true if the given new path is locked.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _pathIsLocked(newPath = '', startPath = '') {
        if (typeof newPath !== 'string') {
            this._log('_pathIsLocked(): parameter "newPath" is not of type string!', 'WARN');
            return;
        } else if (typeof startPath !== 'string') {
            this._log('_pathIsLocked(): The parameter "startPath" is not of type string!', 'WARN');
            return;
        }
        if (this._getPathLevelsCount(newPath) < this._getPathLevelsCount(startPath)) {
            this._setStatus('theStartPathOfThePaneIsLocked');
            return true;
        };
        return false;
    }

    /****************************************************************************************************
     * Checks if a given new path has reached the configured maximum levels.
     *
     * @private
     * @param {String} [newPath=''] The path to check.
     * @param {String} [oldPath=''] The path to check against.
     * @param {Number} [maxLevels=-1] The maximum limit of allowed levels.
     * @returns {Boolean} Returns true, if the path has reached the given limit.
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _maxLevelsReached(newPath = '', oldPath = '', maxLevels = -1) {
        if (typeof newPath !== 'string') {
            this._log('_maxLevelsReached(): The parameter "newPath" is not of type string!', 'WARN');
            return;
        } else if (typeof oldPath !== 'string') {
            this._log('_maxLevelsReached(): The parameter "oldPath" is not of type string!', 'WARN');
            return;
        } else if (Number.isInteger(maxLevels) && maxLevels < -1) {
            this._log('_maxLevelsReached(): The parameter "mavLevels" is not a of type integer or < -1!', 'WARN');
            return;
        }
        if (this._getPathLevelsCount(newPath) > this._getPathLevelsCount(oldPath) + maxLevels) {
            this._setStatus('youCanNotNavigateFurther');
            return true;
        };
        return false;
    }

    /****************************************************************************************************
     * This complex observer is executed, if either startpathleftislocked, startpathleft or maxnavlevelsleft is updated. 
     * If a limit applies, it redirects the pane to a valid path or keeps the current path.
     *
     * @private
     * @param {Boolean} isLocked If true, the startpath is locked.
     * @param {String} startPath The new start path in unix notation.
     * @param {Number} maxLevels The number of levels.
     * @returns {Undefined} Undefined 
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _checkValidLevelLeft(isLocked, startPath, maxLevels) {
        if (this.requiredPropertiesReady) {
            const checkPath = (isLocked) ? startPath : '/';
            const redirectPath = (isLocked) ? this.validStartPathLeft : '/';
            if (isLocked && !this.activepathleft.startsWith(startPath)) {
                this.activepathleft = this.validStartPathLeft;
                return;
            }
            if (maxLevels > -1 && this._maxLevelsReached(this.activepathleft, checkPath, maxLevels)) {
                this.activepathleft = redirectPath;
                return;
            }
        }
    }

    /****************************************************************************************************
     * This complex observer is executed, if either startpathrightislocked, startpathright or maxnavlevelsright is updated. 
     * If a limit applies it redirects the pane to a valid path or keeps the current path.
     *
     * @private
     * @param {Boolean} isLocked If true, the startpath is locked.
     * @param {String} startPath The new start path in unix notation.
     * @param {Number} maxLevels The number of levels.
     * @returns {Undefined} Undefined
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _checkValidLevelRight(isLocked, startPath, maxLevels) {
        if (this.requiredPropertiesReady) {
            const checkPath = (isLocked) ? startPath : '/';
            const redirectPath = (isLocked) ? this.validStartPathRight : '/';
            if (isLocked && !this.activepathright.startsWith(startPath)) {
                this.activepathright = this.validStartPathRight;
                return;
            }
            if (maxLevels > -1 && this._maxLevelsReached(this.activepathright, checkPath, maxLevels)) {
                this.activepathright = redirectPath;
                return;
            }
        }
    }

    /****************************************************************************************************
     * An observer method that is executed every time the property activerow changes.
     * 
     * @private
     * @param {Object} data Object of active row.
     * @returns {Undefined} Undefined 
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _updateActiveRowProperty(data) {
        let item = 0;
        if (this.useprefixes === false) { 
			item = (data && data.value) ? data.value.name : ''; 
		}
        else { 
			item = (data && data.value) ? data.value.type + "//" + data.value.name : ''; 
		}

        if (this.activepane === 'left') this._setLeftactivefiledata(item); 
        else this._setRightactivefiledata(item); 
    }

    /****************************************************************************************************
     * An observer method that is executed every time the property activeselection changes.
     * 
     * @private
     * @param {Object} data Selection data.
     * @returns {Undefined} Undefined 
     * @memberof LasalRuntimeSigControlFilemanager
    ****************************************************************************************************/
    _updateActiveSelectionProperty(data) {
        SigPolymer.afterNextRender(this, function () {
            let files = [], folders = [];
            let selectionMask = 0;

            if (data && data.value instanceof Array) {
                data.value.forEach(row => {
                    if (row.type === 'file'){
                        files.push(row.name);
                        selectionMask |= 1; 
                    } 
                    else if (row.type === 'folder'){
                        folders.push(row.name);
                        selectionMask |= 2;
                    }
                    else if (row.type === 'parent'){
                        selectionMask |= 4;
                    }
                    else if (row.type === 'volume'){
                        selectionMask |= 8;
                    }else{
                        selectionMask = 0;
                    }
                });
            }

            const separator = (folders.length > 0 || files.length > 0) ? this.fileFolderSeparator : '';
            const filesAndFolders = folders.join(this.itemSeparator) + separator + files.join(this.itemSeparator);
            if (this.activepane === 'left') {
                this._setLeftactiveselectiondata(filesAndFolders);
                this._setLeftactiveselectiondatabitmask(selectionMask);

            } else {
                this._setRightactiveselectiondata(filesAndFolders);
                this._setRightactiveselectiondatabitmask(selectionMask);
            }
        });
    }
}
customElements.define(LasalRuntimeSigControlFilemanager.is, LasalRuntimeSigControlFilemanager);