summaryrefslogtreecommitdiff
path: root/lib/dialogues/fsd.tcl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dialogues/fsd.tcl')
-rw-r--r--lib/dialogues/fsd.tcl2871
1 files changed, 2871 insertions, 0 deletions
diff --git a/lib/dialogues/fsd.tcl b/lib/dialogues/fsd.tcl
new file mode 100644
index 0000000..fce7e24
--- /dev/null
+++ b/lib/dialogues/fsd.tcl
@@ -0,0 +1,2871 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# This program is free software; you can redistribute it and#or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation; either version 2 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program; if not, write to the #
+# Free Software Foundation, Inc., #
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
+############################################################################
+
+# >>> File inclusion guard
+if { ! [ info exists _FSD_TCL ] } {
+set _FSD_TCL _
+# <<< File inclusion guard
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# This class provides file selection dialog
+# Usage:
+# KIFSD::FSD <fsd_object> ;# Create dialog object
+# <fsd_object> setokcmd {set filename [<fsd_object> get]} ;# Set command for Ok button
+# <fsd_object> activate <some_command> ;# Show up the dialog
+#
+# Constructor options:
+# -title String = {} ;# Dialog title
+# -initialfile String = {} ;# Initial file
+# -directory String = {~} ;# Initiali directory
+# -multiple Bool = 0 ;# Allow selection of multiple files (get will return list instead of string)
+# -filetypes List = {{All} {*}} ;# { {{Some string} {GLOB}} ... }
+# -defaultmask Int = 0 ;# Number of detault mask (see -filetypes) (1st is zero)
+# -modal Bool = 1 ;# Create as modal window
+# -doubleclick Bool = 0 ;# Use double click to open folder instead of single click
+# -autoclose Bool = 1 ;# Close dialog after pressure of Ok button
+# -master Widget = . ;# Master window (wm transient $master)
+# -fileson Bool = 1 ;# 1 == Select file(s); 0 == Select directory/ies
+#
+# Other public methods:
+# set_bookmark_change_command Command ;# Set command to invoke when bookmarks changes
+# deactivate ;# Deactivate the dialog
+# close_dialog ;# Close dialog window but keep object alive
+# get_config_array -> List ;# Get dialog configuration array for proc. load_config_array
+# load_config_array List ;# Load dialog configuration array
+# get_window_name -> Widget ;# Get path to dialog window
+# --------------------------------------------------------------------------
+
+itcl::class KIFSD::FSD {
+
+ common bookmark_change_command {} ;# Command to invoke on bokmark change
+ # Font for quick navigation panel
+ common quick_nav_panel_font [font create \
+ -family {helvetica} \
+ -size [expr {int(-12 * $::font_size_factor)}] \
+ -weight bold \
+ ]
+ # Font for files listbox in mode (Short view)
+ common listbox_font_short [font create \
+ -family {helvetica} \
+ -size [expr {int(-14 * $::font_size_factor)}] \
+ -weight normal \
+ ]
+ # Font for files listbox in mode (Detailed view) and directories listbox
+ common listbox_font_detailed [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size [expr {int(-12 * $::font_size_factor)}] \
+ -weight normal \
+ ]
+ # Font for listbox header
+ common listbox_header_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size [expr {int(-12 * $::font_size_factor)}] \
+ -weight bold \
+ ]
+
+ ## Values given by constructor arguments
+ private variable option_title {Select file} ;# Dialog title
+ private variable option_filetypes {{All} {*}} ;# File types
+ if {!$::MICROSOFT_WINDOWS} {
+ variable option_directory ${::env(HOME)} ;# Initial directory
+ } else {
+ variable option_directory ${::env(USERPROFILE)} ;# Initial directory
+ }
+ private variable option_master {.} ;# Window master
+ private variable option_fileson {1} ;# 1 == Files on (select file); 0 == Files off (select directory)
+ private variable option_doubleclick {0} ;# Use doble click instead of single clicks
+ private variable option_modal {1} ;# Open dialog windown as modal window
+ private variable option_initialfile {} ;# Initial file
+ private variable option_multiple {0} ;# Allow mulstiple selection
+ private variable option_defaultmask {0} ;# Index of default mask in $option_filetypes
+ private variable option_autoclose {1} ;# 1 == Close dialog after press of Ok button
+
+ private variable bookmark_edit_listbox {} ;# Widget: ListBox in bookmarks editor
+ private variable bookmark_menu {} ;# Widget: Bookmarks menu
+ private variable config_menu {} ;# Widget: Configuration menu
+ private variable listbox_font {} ;# Font: Current font for files listbox
+ private variable current_directory {} ;# String: Current directory
+ private variable back_history {} ;# List: Backward history
+ private variable forward_history {} ;# List: Forward hitory
+ private variable ok_command {} ;# String: Ok command
+ private variable current_mask {*} ;# GLOB: Current fileter mask
+ private variable item_menu_request 0 ;# Bool: Item popup menu request
+ private variable current_item {} ;# String: ID of currenly selected item
+ private variable current_item_index 0 ;# Int: Index of currently selected item
+ private variable cur_listbox {} ;# String currently selected listbox {dir} or {file}
+
+ private variable dialog_loaded 0 ;# Bool: Dialog is completely loaded
+ private variable win ;# Widget: Dialog window
+ private variable ok_button ;# Widget: Button "Ok"
+ private variable location_cb ;# Widget: Location ComboBox
+ private variable filter_cb ;# Widget: Filter ComboBox
+ private variable dir_combobox ;# Widget: Directory ComboBox
+ private variable toolbar ;# Widget: Frame containing toolbar
+ private variable quick_access_bar ;# Widget: Quick access bar ListBox
+ private variable dir_listbox_scrollbar {} ;# Widget: Directory ListBox scrollbar
+ private variable dir_listbox {} ;# Widget: Directory ListBox
+ private variable main_paned_window ;# Widget: Paned window for quick access bar and other LBs
+ private variable leftframe ;# Widget: Frame contaning quick access bar and its scrollbar
+ private variable rightframe ;# Widget: Frame containing directory & file ListBoxes
+ private variable right_top_right_frame ;# Widget: files ListBox
+ private variable right_top_left_frame ;# Widget: Frame for files ListBox
+ private variable right_top_frame ;# Widget: Frame for $right_paned_window
+ private variable right_paned_window ;# Widget: Paned window for directories ListBox and files ListBox
+ private variable file_listbox ;# Widget: Files ListBox
+ private variable file_listbox_header ;# Widget: Header for files ListBox
+ private variable file_listbox_frame ;# Widget: Frame for $file_listbox_header and $file_listbox
+ private variable file_listbox_vscrollbar {} ;# Widget: Vertical scollbar for files ListBox
+ private variable file_listbox_hscrollbar {} ;# Widget: Hotizontal scollbar for files ListBox
+ private variable right_top_right_top_frame ;# Widget: Frame for $file_listbox_frame and scrollbars
+
+ proc static_reload {object args} {
+ catch [list $object reload]
+ }
+
+ ## Dialog constructor
+ # For complite list of possible arguments see desctiption above
+ constructor args {
+
+ # Configure local ttk styles
+ ttk::style configure FSD_RedBg.TCombobox -fieldbackground {#FFDDDD}
+ ttk::style configure FSD_RedBg.TEntry -fieldbackground {#FFDDDD}
+
+ ## Parse given arguments and set appropriate object variables
+ set arglen [llength $args]
+ set arg {}
+ for {set i 0} {$i < $arglen} {incr i} {
+ set arg [lindex $args $i]
+ switch -- $arg {
+ -modal {
+ incr i
+ set option_modal [lindex $args $i]
+ if {![string is boolean -strict $option_modal]} {
+ error "-modal must have value either 0 or 1"
+ }
+ }
+ -doubleclick {
+ incr i
+ set option_doubleclick [lindex $args $i]
+ if {![string is boolean -strict $option_doubleclick]} {
+ error "-doubleclick must have value either 0 or 1"
+ }
+ }
+ -autoclose {
+ incr i
+ set option_autoclose [lindex $args $i]
+ if {![string is boolean -strict $option_autoclose]} {
+ error "-autoclose must have value either 0 or 1"
+ }
+ }
+ -initialfile {
+ incr i
+ set option_initialfile [lindex $args $i]
+ }
+ -multiple {
+ incr i
+ set option_multiple [lindex $args $i]
+ if {![string is boolean -strict $option_multiple]} {
+ error "-multiple must have value either 0 or 1"
+ }
+ }
+ -defaultmask {
+ incr i
+ set option_defaultmask [lindex $args $i]
+ if {![string is integer -strict $option_defaultmask]} {
+ error "-defaultmask must be an integer"
+ }
+ }
+ -title {
+ incr i
+ set option_title [lindex $args $i]
+ }
+ -filetypes {
+ incr i
+ set option_filetypes [lindex $args $i]
+ }
+ -directory {
+ incr i
+ set option_directory [lindex $args $i]
+ }
+ -master {
+ incr i
+ set option_master [lindex $args $i]
+ }
+ -fileson {
+ incr i
+ set option_fileson [lindex $args $i]
+ if {![string is boolean -strict $option_modal]} {
+ error "-fileson must have value either 0 or 1"
+ }
+ }
+ default {
+ error "Option '$arg' is not valid"
+ }
+ }
+ }
+ set args {}
+ set current_directory [file normalize $option_directory]
+
+ # Cretate dialog window
+ create_dialog
+
+ # Initalize window key shortcuts
+ create_shortcuts
+
+ # Finalize
+ set dialog_loaded 1
+ }
+
+ ## Destrurtor
+ destructor {
+ catch {
+ # Save position of right paned window sash
+ if {[winfo ismapped $right_paned_window]} {
+ set ::KIFSD::FSD::config(right_PW_size) \
+ [lindex [$right_paned_window sash coord 0] 0]
+ }
+ # Save position of main paned window sash
+ if {[winfo ismapped $main_paned_window]} {
+ set ::KIFSD::FSD::config(main_PW_size) \
+ [lindex [$main_paned_window sash coord 0] 0]
+ }
+ # Save window geometry
+ set ::KIFSD::FSD::config(win_geometry) [wm geometry $win]
+ }
+
+ # Destroy dialog window
+ grab release $win
+ destroy $win
+ }
+
+ ## Create dialog GUI elements
+ # @return void
+ private method create_dialog {} {
+ # Determinate window name (path)
+ set win_base {}
+ if {$option_master != {.}} {
+ set win_base $option_master
+ }
+ append win_base .[string tolower [regsub -all {:} $this {}]]
+ set win $win_base
+ set i 0
+ while [winfo exists $win] {
+ set win $win_base
+ append win $i
+ incr i
+ }
+
+ # Create and configure dialog window
+ toplevel $win -bg ${::COMMON_BG_COLOR}
+ wm iconphoto $win ::ICONS::16::fileopen
+ wm withdraw $win
+ wm title $win $option_title
+ wm minsize $win 540 290
+ wm protocol $win WM_DELETE_WINDOW "catch {itcl::delete object $this}"
+ wm transient $win $option_master
+ wm geometry $win ${::KIFSD::FSD::config(win_geometry)}
+ wm resizable $win 0 0
+ raise $win
+ update
+ if {$option_modal} {
+ catch {
+ grab $win
+ }
+ }
+
+
+ create_popup_menus ;# Create popup menus
+ set topframe [frame $win.topframe] ;# Create frame above ListBoxes
+ set toolbar [frame $topframe.toobar] ;# Create toolbar frame
+ create_tool_bar ;# Create toolbar
+
+ # Create directory ComboBox
+ set dir_combobox [ttk::combobox $topframe.dir_cb \
+ -values {} \
+ -exportselection 0 \
+ -validate all \
+ -validatecommand "::KIFSD::FSD::dir_validate $topframe.dir_cb %W %P" \
+ ]
+ bind $dir_combobox <<ComboboxSelected>> [list $this dir_cb_modify]
+ bind $dir_combobox <KP_Enter> [list $this dir_cb_modify]
+ bind $dir_combobox <Return> [list $this dir_cb_modify]
+
+ DynamicHelp::add $dir_combobox -text [mc "Current directory"]
+ pack $dir_combobox -side right -expand 1 -fill x -padx 5
+
+ # Create main paned window and some frames
+ set mainframe [frame $win.mainframe]
+ set main_paned_window [panedwindow $mainframe.main_paned_window \
+ -orient horizontal -opaqueresize 1 -sashwidth 2 \
+ -showhandle 0 -sashrelief flat \
+ ]
+ set leftframe [frame $mainframe.leftframe]
+ set rightframe [frame $mainframe.rightframe]
+
+ # Create quick access bar
+ set quick_access_bar [ListBox $leftframe.quick_access_bar \
+ -selectfill 1 -selectbackground white -bd 1 -padx 30 -width 15 \
+ -selectmode single -highlightthickness 0 -bg white -deltay 30 \
+ -selectforeground black -highlightcolor {#BBBBFF} \
+ ]
+ refresh_quick_access_bar
+ $quick_access_bar bindText <ButtonRelease-3> [list $this quick_access_bar_item_menu %X %Y ]
+ $quick_access_bar bindImage <ButtonRelease-3> [list $this quick_access_bar_item_menu %X %Y ]
+ $quick_access_bar bindText <Double-Button-1> [list $this quick_access_bar_doubleclick ]
+ $quick_access_bar bindImage <Double-Button-1> [list $this quick_access_bar_doubleclick ]
+ bind $quick_access_bar <<ListboxSelect>> [list $this quick_access_bar_select ]
+ if {[winfo exists $quick_access_bar.c]} {
+ bind $quick_access_bar.c <Button-5> {%W yview scroll +5 units; break}
+ bind $quick_access_bar.c <Button-4> {%W yview scroll -5 units; break}
+ bind $quick_access_bar.c <ButtonRelease-3> [list $this quick_access_bar_menu %X %Y ]
+ }
+ pack $quick_access_bar -fill both -expand 1
+
+ # Create right paned window
+ set right_top_frame [frame $rightframe.topframe]
+ set right_bottom_frame [frame $rightframe.bottomframe]
+ set right_paned_window [panedwindow $right_top_frame.right_paned_window \
+ -orient horizontal -opaqueresize 1 -sashwidth 2 \
+ -showhandle 0 -sashrelief flat \
+ ]
+ set right_top_left_frame [frame $win.left_frame]
+ set right_top_right_frame [frame $win.right_frame]
+
+ # Create directories ListBox
+ if {$option_fileson} {
+ set dir_listbox [ListBox $right_top_left_frame.dir_listbox \
+ -bd 1 -padx 19 -selectfill 1 -width 1 -highlightcolor {#BBBBFF} \
+ -selectmode single -highlightthickness 0 -bg white -deltay 18 \
+ -yscrollcommand "$this dir_listbox_scroll" \
+ ]
+ set dir_listbox_scrollbar [ttk::scrollbar \
+ $right_top_left_frame.scrollbar \
+ -orient vertical -command "$dir_listbox yview" \
+ ]
+ $dir_listbox bindText <Double-Button-1> [list $this dir_listbox_doubleclick ]
+ $dir_listbox bindImage <Double-Button-1> [list $this dir_listbox_doubleclick ]
+ $dir_listbox bindText <ButtonRelease-3> [list $this dir_listbox_item_menu %X %Y ]
+ $dir_listbox bindImage <ButtonRelease-3> [list $this dir_listbox_item_menu %X %Y ]
+ bind $dir_listbox <<ListboxSelect>> [list $this dir_listbox_select ]
+ if {[winfo exists $dir_listbox.c]} {
+ bind $dir_listbox.c <Button-5> {%W yview scroll +5 units; break}
+ bind $dir_listbox.c <Button-4> {%W yview scroll -5 units; break}
+ bind $dir_listbox.c <ButtonRelease-3> [list $this dir_listbox_menu %X %Y ]
+ }
+ pack $dir_listbox -side left -fill both -expand 1
+ }
+
+ # Create files ListBox
+ if {$option_multiple} {
+ set selmode {multiple}
+ } else {
+ set selmode {single}
+ }
+ set right_top_right_top_frame [frame $right_top_right_frame.right_top_right_top_frame]
+ set file_listbox_frame [frame $right_top_right_top_frame.file_listbox_frame]
+ set file_listbox_header [text $file_listbox_frame.text \
+ -width 1 -height 1 -takefocus 0 -bg white \
+ -font $listbox_header_font -bd 1 -relief sunken \
+ -cursor left_ptr -wrap none \
+ ]
+ $file_listbox_header delete 1.0 end
+ if {!$::MICROSOFT_WINDOWS} {
+ $file_listbox_header insert end \
+ [mc " Name Size Rights Date "]
+ } else {
+ $file_listbox_header insert end \
+ [mc " Name Size Date "]
+ }
+ bindtags $file_listbox_header $file_listbox_header
+ $file_listbox_header configure -state disabled
+ set file_listbox [ListBox $file_listbox_frame.file_listbox \
+ -bd 1 \
+ -padx 17 \
+ -width 1 \
+ -height 1 \
+ -bg white \
+ -deltay 18 \
+ -selectfill 1 \
+ -selectmode $selmode \
+ -highlightthickness 0 \
+ -selectbackground {#88AAFF} \
+ -highlightcolor {#BBBBFF} \
+ -yscrollcommand "$this file_listbox_vscroll" \
+ -xscrollcommand "$this file_listbox_hscroll" \
+ ]
+ pack $file_listbox -fill both -expand 1
+ if {${::KIFSD::FSD::config(detailed_view)}} {
+ $file_listbox configure -multicolumn 0
+ set listbox_font $listbox_font_detailed
+ pack $file_listbox_header -before $file_listbox -fill x -expand 0
+ } else {
+ $file_listbox configure -multicolumn 1
+ set listbox_font $listbox_font_short
+ }
+ set file_listbox_vscrollbar [ttk::scrollbar \
+ $right_top_right_top_frame.vscrollbar \
+ -orient vertical -command "$file_listbox yview" \
+ ]
+ set file_listbox_hscrollbar [ttk::scrollbar \
+ $right_top_right_frame.hscrollbar \
+ -orient horizontal \
+ -command "$this file_listbox_hscrollbar_cmd" \
+ ]
+ $file_listbox bindText <Double-Button-1> [list $this file_listbox_doubleclick]
+ $file_listbox bindImage <Double-Button-1> [list $this file_listbox_doubleclick]
+ $file_listbox bindText <ButtonRelease-3> [list $this file_listbox_item_menu %X %Y]
+ $file_listbox bindImage <ButtonRelease-3> [list $this file_listbox_item_menu %X %Y]
+ bind $file_listbox <<ListboxSelect>> [list $this file_listbox_select]
+ if {[winfo exists $file_listbox.c]} {
+ bind $file_listbox.c <Button-5> [list $this file_listbox_scroll +5 units]
+ bind $file_listbox.c <Button-4> [list $this file_listbox_scroll -5 units]
+ bind $file_listbox.c <ButtonRelease-3> [list $this file_listbox_menu %X %Y]
+ }
+ pack $file_listbox_frame -fill both -expand 1 -side left
+ pack $right_top_right_top_frame -fill both -expand 1 -side top
+ pack $right_top_frame -side top -fill both -expand 1
+
+ # Create Location Label+ComboBox and Filter Label+ComboBox
+ grid [label $right_bottom_frame.location_label \
+ -text [mc "Location:"] \
+ ] -sticky w -column 0 -row 0
+ grid [label $right_bottom_frame.filter_label \
+ -text [mc "Filter:"] \
+ ] -sticky w -column 0 -row 1
+
+ set location_cb [ttk::combobox $right_bottom_frame.location_cb \
+ -values {} \
+ -exportselection 0 \
+ ]
+ bind $location_cb <<ComboboxSelected>> "$file_listbox selection clear"
+ DynamicHelp::add $location_cb -text [mc "Selected file(s)"]
+ bind $location_cb <Key> "$file_listbox selection clear"
+ bind $location_cb <KP_Enter> [list $this ok]
+ bind $location_cb <Return> [list $this ok]
+
+ set tmp_option_filetypes {}
+ foreach type $option_filetypes {
+ set glob_masks [lindex $type 1]
+ if {[regexp {^\*\.\{\w+(,\w+)*\}$} $glob_masks]} {
+ set glob_masks [split $glob_masks {{,}}]
+ set glob_masks [lreplace $glob_masks 0 0]
+ set glob_masks [lreplace $glob_masks end end]
+ set glob_masks_new [list]
+ foreach ext $glob_masks {
+ lappend glob_masks_new [format "*.%s" $ext]
+ }
+ set glob_masks [join $glob_masks_new {, }]
+ }
+ lappend tmp_option_filetypes "[lindex $type 0] ($glob_masks)"
+ }
+ set filter_cb [ttk::combobox $right_bottom_frame.filter_cb \
+ -state readonly \
+ -values $tmp_option_filetypes \
+ -exportselection 0 \
+ ]
+ DynamicHelp::add $right_bottom_frame.filter_cb -text [mc "Filter"]
+ set tmp_option_filetypes {}
+ foreach type $option_filetypes {
+ lappend tmp_option_filetypes [lindex $type 1]
+ }
+ set option_filetypes $tmp_option_filetypes
+ $filter_cb current $option_defaultmask
+ set current_mask [lindex $option_filetypes $option_defaultmask]
+ bind $filter_cb <<ComboboxSelected>> [list $this filter_cb_modify]
+ grid $location_cb -sticky ew -column 1 -row 0
+ grid $filter_cb -sticky ew -column 1 -row 1
+
+ if {!$option_fileson} {
+ $filter_cb configure -state disabled
+ }
+
+ # Create buttons "Ok" and "Cancel"
+ set ok_button [ttk::button $right_bottom_frame.ok_button\
+ -text [mc "Ok"] \
+ -compound left \
+ -width 8 \
+ -image ::ICONS::16::ok \
+ -command [list $this ok] \
+ ]
+ grid $ok_button -sticky w -column 2 -row 0 -padx 7 -pady 2
+ grid [ttk::button $right_bottom_frame.cancel_button \
+ -text [mc "Cancel"] \
+ -compound left \
+ -width 8 \
+ -image ::ICONS::16::button_cancel \
+ -command "itcl::delete object $this" \
+ ] -sticky w -column 2 -row 1 -padx 7 -pady 2
+
+ grid columnconfigure $right_bottom_frame 1 -weight 1
+
+ pack $right_bottom_frame -side bottom -fill x -expand 0 -anchor w
+
+ pack $topframe -side top -fill x -padx 12 -pady 10
+ pack $mainframe -side bottom -fill both -expand 1 -padx 12
+
+ # Adjust paned windows to current configuration
+ quick_access_panel_onoff
+ separate_folders_onoff
+
+ # Finalize
+ $location_cb set $option_initialfile
+ focus -force $location_cb
+ catch {
+ $location_cb.e selection range 0 end
+ }
+ }
+
+ ## Create dialog toolbar
+ # @return void
+ private method create_tool_bar {} {
+ set si 0
+ foreach item {
+ {up "Parent folder" {1uparrow}
+ {up}}
+ {back "Back" {1leftarrow}
+ {back}}
+ {forward "Forward" {1rightarrow}
+ {forward}}
+ {reload "Reload" {reload}
+ {reload}}
+ {separator}
+ {newdir "New folder" {folder_new}
+ {newdir}}
+ {separator}
+ {short "Short view" {view_icon}
+ {short_view}}
+ {detail "Detailed view" {view_detailed}
+ {detail_view}}
+ {separator}
+ {bookmark "Bookmarks" {bookmark}
+ {bookmark_menu}}
+ {configure "Configure" {configure}
+ {config_menu}}
+ } \
+ {
+ # Create separator
+ if {$item == {separator}} {
+ pack [ttk::separator $toolbar.sep$si \
+ -orient vertical \
+ ] -side left -padx 4 -fill both -expand 1
+ incr si
+ continue
+ }
+
+ # Create button
+ if {[lindex $item 0] == {bookmark}} {
+ set buttonWidget [ttk::menubutton $toolbar.[lindex $item 0] \
+ -image ::ICONS::22::[lindex $item 2] \
+ -menu $bookmark_menu \
+ -style Flat.TMenubutton \
+ ]
+ } elseif {[lindex $item 0] == {configure}} {
+ set buttonWidget [ttk::menubutton $toolbar.[lindex $item 0] \
+ -image ::ICONS::22::[lindex $item 2] \
+ -menu $config_menu \
+ -style Flat.TMenubutton \
+ ]
+ } else {
+ set buttonWidget [ttk::button $toolbar.[lindex $item 0] \
+ -command "$this [lindex $item 3]" \
+ -style Flat.TButton \
+ -image ::ICONS::22::[lindex $item 2] \
+ ]
+ }
+ DynamicHelp::add $buttonWidget -text [mc [lindex $item 1]]
+
+ # Pack it
+ pack $buttonWidget -side left -padx 2
+ }
+
+ # Disable button for manipulating history
+ $toolbar.back configure -state disabled
+ $toolbar.forward configure -state disabled
+
+ # Pack toolbar frame
+ pack $toolbar -side left -expand 0 -fill none
+ }
+
+
+ ## Create dialog popup menus
+ # @return void
+ private method create_popup_menus {} {
+ # Create configuration menu
+ set config_menu [menu $win.config_menu -tearoff 0]
+
+ ## Create menu: Configuration -> Sorting
+ set sorting_menu [menu $win.config_menu.sorting_menu -tearoff 0]
+ # Entry: "By name"
+ $sorting_menu add radiobutton -label [mc "By name"] \
+ -variable ::KIFSD::FSD::config(sorting) \
+ -indicatoron 0 -compound left -image ::ICONS::raoff -selectimage ::ICONS::raon \
+ -value {name} -underline 3 -command [list $this reload]
+ # Entry: "By date"
+ $sorting_menu add radiobutton -label [mc "By date"] \
+ -variable ::KIFSD::FSD::config(sorting) \
+ -indicatoron 0 -compound left -image ::ICONS::raoff -selectimage ::ICONS::raon \
+ -value {date} -underline 3 -command [list $this reload]
+ # Entry: "By size"
+ $sorting_menu add radiobutton -label [mc "By size"] \
+ -variable ::KIFSD::FSD::config(sorting) \
+ -indicatoron 0 -compound left -image ::ICONS::raoff -selectimage ::ICONS::raon \
+ -value {size} -underline 3 -command [list $this reload]
+ $sorting_menu add separator
+ # Entry: "Reverse"
+ $sorting_menu add checkbutton -label [mc "Reverse"] \
+ -variable ::KIFSD::FSD::config(reverse_sorting) \
+ -indicatoron 0 -compound left -image ::ICONS::choff -selectimage ::ICONS::chon \
+ -command "$this reload" -underline 0
+ # Entry: "Folders first"
+ $sorting_menu add checkbutton -label [mc "Folders first"] \
+ -variable ::KIFSD::FSD::config(folders_first) \
+ -indicatoron 0 -compound left -image ::ICONS::choff -selectimage ::ICONS::chon \
+ -command "$this reload" -underline 0
+ # Entry: "Case insensitive"
+ $sorting_menu add checkbutton -label [mc "Case insensitive"] \
+ -variable ::KIFSD::FSD::config(case_insensitive) \
+ -indicatoron 0 -compound left -image ::ICONS::choff -selectimage ::ICONS::chon \
+ -command "$this reload" -underline 0
+
+ ## Create entries for configuraion menu (accessable from toolbar)
+ # Entry: "Sorting"
+ $win.config_menu add cascade -label [mc "Sorting"] -underline 1 -menu $sorting_menu -image ::ICONS::16::sort_incr -compound left
+ $win.config_menu add separator
+ # Entry: "Short view"
+ $win.config_menu add command -label [mc "Short view"] -compound left \
+ -accelerator "F6" -command "$this short_view" -underline 0 \
+ -image ::ICONS::16::view_icon
+ # Entry: "Detailed view"
+ $win.config_menu add command -label [mc "Detailed view"] -compound left \
+ -accelerator "F7" -command "$this detail_view" -underline 0 \
+ -image ::ICONS::16::view_detailed
+ $win.config_menu add separator
+ # Entry: "Show hidden files"
+ $win.config_menu add checkbutton -label [mc "Show hidden files"] \
+ -accelerator "F8" -variable ::KIFSD::FSD::config(show_hidden_files) \
+ -indicatoron 0 -compound left -image ::ICONS::choff -selectimage ::ICONS::chon \
+ -command "$this reload" -underline 5
+ # Entry: "Quick access navigation panel"
+ $win.config_menu add checkbutton -label [mc "Quick access navigation panel"] \
+ -accelerator "F9" -variable ::KIFSD::FSD::config(quick_access_panel) \
+ -indicatoron 0 -compound left -image ::ICONS::choff -selectimage ::ICONS::chon \
+ -command "$this quick_access_panel_onoff" -underline 0
+ # Entry: "Separate folders"
+ $win.config_menu add checkbutton -label [mc "Separate folders"] \
+ -accelerator "F12" -variable ::KIFSD::FSD::config(separate_folders) \
+ -indicatoron 0 -compound left -image ::ICONS::choff -selectimage ::ICONS::chon \
+ -command "$this separate_folders_onoff" -underline 9
+ if {!$option_fileson} {
+ $win.config_menu entryconfigure [mc "Separate folders"] -state disabled
+ $sorting_menu entryconfigure [mc "Folders first"] -state disabled
+ $sorting_menu entryconfigure [mc "By size"] -state disabled
+ }
+
+ ## Create bookmarks menu (accessable from toolbar)
+ set bookmark_menu [menu $win.bookmark_menu -tearoff 0]
+ # Entry: "Add bookmark"
+ $bookmark_menu add command -label [mc "Add bookmark"] \
+ -command "$this add_bookmark" \
+ -underline 0 -image ::ICONS::16::bookmark_add -compound left
+ # Entry: "Edit bookmarks"
+ $bookmark_menu add command -label [mc "Edit bookmarks"] -compound left \
+ -command "$this edit_bookmarks" -underline 0 -image ::ICONS::16::bookmark
+ $bookmark_menu add separator
+ refresh_bookmarks
+
+ ## Create ListBox item menu
+ menu $win.listbox_menu -tearoff 0
+ # Entry: "Up"
+ $win.listbox_menu add command -label [mc "Up"] -compound left \
+ -underline 0 -command [list $this up] \
+ -image ::ICONS::16::up
+ # Entry: "Back"
+ $win.listbox_menu add command -label [mc "Back"] -compound left \
+ -underline 0 -command [list $this back] \
+ -image ::ICONS::16::left -state disabled
+ # Entry: "Forward"
+ $win.listbox_menu add command -label [mc "Forward"] -compound left \
+ -underline 0 -command [list $this forward] \
+ -image ::ICONS::16::right -state disabled
+ $win.listbox_menu add separator
+ # Entry: "Rename"
+ $win.listbox_menu add command -label [mc "Rename"] \
+ -underline 0 -command [list $this rename_item_command] \
+ -compound left -image ::ICONS::16::edit
+ # Entry: "Delete"
+ $win.listbox_menu add command -label [mc "Delete"] \
+ -underline 0 -command [list $this delete_item_command] \
+ -compound left -image ::ICONS::16::editdelete
+ # Entry: "New folder"
+ $win.listbox_menu add command -label [mc "New folder"] \
+ -accelerator "F10" \
+ -underline 0 -command [list $this newdir] \
+ -compound left -image ::ICONS::16::folder_new
+ # Entry: "Bookmark folder"
+ $win.listbox_menu add command -label [mc "Bookmark folder"] \
+ -underline 0 -command [list $this item_bookmark_add] \
+ -compound left -image ::ICONS::16::bookmark_add
+ $win.listbox_menu add separator
+ # Entry: "Properties"
+ $win.listbox_menu add command -label [mc "Properties"] \
+ -underline 0 -command [list $this properties_item_command]
+
+ ## Create quick access bar popup menu
+ menu $win.quick_access_panel_menu -tearoff 0
+ # Entry: "Add entry"
+ $win.quick_access_panel_menu add command -label [mc "Add entry"] \
+ -underline 0 -image ::ICONS::16::filenew -compound left \
+ -command "$this quick_access_panel_add_entry"
+ $win.quick_access_panel_menu add separator
+ # Entry: "Hide panel"
+ $win.quick_access_panel_menu add command -label [mc "Hide panel"] \
+ -underline 0 -image ::ICONS::16::2leftarrow -compound left \
+ -accelerator "F9" -command "
+ set ::KIFSD::FSD::config(quick_access_panel) \
+ \[expr {!\${::KIFSD::FSD::config(quick_access_panel)}}\]
+ $this quick_access_panel_onoff"
+
+ ## Create quick access bar ITEM popup menu
+ menu $win.quick_access_panel_item_menu -tearoff 0
+ # Entry: "Move up"
+ $win.quick_access_panel_item_menu add command -label [mc "Move up"] \
+ -underline 0 -image ::ICONS::16::1uparrow -compound left \
+ -command "$this quick_access_panel_up"
+ # Entry: "Move down"
+ $win.quick_access_panel_item_menu add command -label [mc "Move down"] \
+ -underline 0 -image ::ICONS::16::1downarrow -compound left \
+ -command "$this quick_access_panel_down"
+ $win.quick_access_panel_item_menu add separator
+ # Entry: "Edit entry"
+ $win.quick_access_panel_item_menu add command -label [mc "Edit entry"] \
+ -underline 0 -image ::ICONS::16::edit -compound left \
+ -command "$this quick_access_panel_edit_entry"
+ $win.quick_access_panel_item_menu add separator
+ # Entry: "Add entry"
+ $win.quick_access_panel_item_menu add command -label [mc "Add entry"] \
+ -underline 0 -image ::ICONS::16::filenew -compound left \
+ -command "$this quick_access_panel_add_entry"
+ # Entry: "Remove entry"
+ $win.quick_access_panel_item_menu add command -label [mc "Remove entry"]\
+ -underline 0 -image ::ICONS::16::editdelete -compound left \
+ -command "$this quick_access_panel_remove_entry"
+ $win.quick_access_panel_item_menu add separator
+ # Entry: "Hide panel"
+ $win.quick_access_panel_item_menu add command -label [mc "Hide panel"] \
+ -underline 0 -image ::ICONS::16::2leftarrow -compound left \
+ -accelerator "F9" \
+ -command "
+ set ::KIFSD::FSD::config(quick_access_panel) \
+ \[expr {!\${::KIFSD::FSD::config(quick_access_panel)}}\]
+ $this quick_access_panel_onoff"
+ }
+
+ ## Define key shortcuts for the dialog
+ # @return void
+ private method create_shortcuts {} {
+ bind $win <Key-F5> "$this reload; break"
+ bind $win <Key-F6> "$this short_view; break"
+ bind $win <Key-F7> "$this detail_view; break"
+ bind $win <Key-F8> "
+ set ::KIFSD::FSD::config(show_hidden_files) \
+ \[expr {!\${::KIFSD::FSD::config(show_hidden_files)}}\]
+ $this reload
+ break
+ "
+ bind $win <Key-F9> "
+ set ::KIFSD::FSD::config(quick_access_panel) \
+ \[expr {!\${::KIFSD::FSD::config(quick_access_panel)}}\]
+ $this quick_access_panel_onoff
+ break
+ "
+ bind $win <Key-F10> "$this newdir; break"
+ if {$option_fileson} {
+ bind $win <Key-F12> "
+ set ::KIFSD::FSD::config(separate_folders) \
+ \[expr {!\${::KIFSD::FSD::config(separate_folders)}}\]
+ $this separate_folders_onoff
+ break
+ "
+ }
+ }
+
+ ## Change current directory
+ # This function checks for directory validity
+ # @parm String dir - New directory
+ # @return void
+ public method change_directory {dir} {
+ if {$::MICROSOFT_WINDOWS} {
+ # Transform for instance "C:" to "C:/"
+ if {[regexp {^\w+:$} $dir]} {
+ append dir {/}
+ }
+ }
+
+ # Check if the specified directory is valid
+ if {![file exists $dir] || ![file isdirectory $dir]} {
+ tk_messageBox \
+ -parent $win \
+ -type ok \
+ -icon warning \
+ -title [mc "Invalid folder"] \
+ -message [mc "The specified folder does not exist:\n%s" $dir]
+ return
+ }
+ set dir [file normalize $dir]
+
+ # Adjust history
+ if {$dir != $current_directory} {
+ lappend back_history $current_directory
+ set forward_history {}
+ $win.listbox_menu entryconfigure [mc "Forward"] -state disabled
+ $win.listbox_menu entryconfigure [mc "Back"] -state normal
+ $toolbar.forward configure -state disabled
+ $toolbar.back configure -state normal
+ }
+
+ # Option separate_folders ON
+ FSnotifications::forget $current_directory
+ FSnotifications::watch $dir [list KIFSD::FSD::static_reload $this]
+ set current_directory $dir
+ if {${::KIFSD::FSD::config(separate_folders)} && $option_fileson} {
+ # Fill up directory ListBox with directories
+ $dir_listbox delete [$dir_listbox items]
+ foreach folder [dir_cmd $dir 1] {
+ if {$folder == {..}} {
+ set image {up}
+ } else {
+ set image {fileopen}
+ }
+ $dir_listbox insert end #auto \
+ -text $folder \
+ -image ::ICONS::16::$image \
+ -font $listbox_font_short
+ }
+
+ # Fill up file ListBox with files
+ $file_listbox delete [$file_listbox items]
+ foreach file [file_cmd $dir $current_mask] {
+ if {${::KIFSD::FSD::config(detailed_view)}} {
+ set filename [lindex $file 1]
+ set file [lindex $file 0]
+ } else {
+ set filename $file
+ }
+ $file_listbox insert end #auto \
+ -text $file \
+ -image ::ICONS::16::ascii \
+ -font $listbox_font \
+ -data [list $filename {}]
+ }
+ # Option separate_folders OFF
+ } else {
+ # Option folders_first ON or option_fileson OFF
+ $file_listbox delete [$file_listbox items]
+ if {!$option_fileson || ${::KIFSD::FSD::config(folders_first)}} {
+ # Fill up files ListBox with directories
+ foreach folder [dir_cmd $dir] {
+ if {${::KIFSD::FSD::config(detailed_view)}} {
+ set fullname [lindex $folder 1]
+ set folder [lindex $folder 0]
+ } else {
+ set fullname $folder
+ }
+
+ if {$folder == {..}} {
+ set image {up}
+ set fullname $folder
+ } else {
+ set image {fileopen}
+ }
+
+ $file_listbox insert end #auto \
+ -text $folder \
+ -image ::ICONS::16::$image \
+ -font $listbox_font \
+ -data [list {} $fullname]
+ }
+ # Option: option_fileson ON
+ if {$option_fileson} {
+ # Fill up files ListBox with files
+ foreach file [file_cmd $dir $current_mask] {
+ if {${::KIFSD::FSD::config(detailed_view)}} {
+ set filename [lindex $file 1]
+ set file [lindex $file 0]
+ } else {
+ set filename $file
+ }
+
+ $file_listbox insert end #auto \
+ -text $file \
+ -image ::ICONS::16::ascii \
+ -font $listbox_font \
+ -data [list $filename {}]
+ }
+ }
+ # Option NOT ( folders_first ON or option_fileson OFF )
+ } else {
+ # Fill up files ListBox with files and directories
+ foreach file [dir_file_cmd $dir $current_mask] {
+ set filename {}
+ set folder {}
+ if {${::KIFSD::FSD::config(detailed_view)}} {
+ set fullname [lindex $file {0 1}]
+ set text [lindex $file {0 0}]
+ } else {
+ set fullname [lindex $file 0]
+ set text $fullname
+ }
+
+ switch -- [lindex $file 1] {
+ u {
+ set image {up}
+ set folder {..}
+ }
+ d {
+ set image {fileopen}
+ set folder $fullname
+ }
+ f {
+ set image {ascii}
+ set filename $fullname
+ }
+ }
+
+ $file_listbox insert end #auto \
+ -text $text \
+ -image ::ICONS::16::$image \
+ -font $listbox_font \
+ -data [list $filename $folder]
+ }
+ }
+ }
+
+ # Fill up location ComboBox with available files or directories
+ if {$option_fileson} {
+ $location_cb configure -values [file_cmd $dir $current_mask 1]
+ } else {
+ $location_cb configure -values [dir_cmd $dir 1]
+ }
+ $location_cb set {}
+
+ # Fill up directory ComboBox
+ set values {}
+ set folder $dir
+ while {1} {
+ lappend values $folder
+ if {$folder == [file separator]} {break}
+ if {$::MICROSOFT_WINDOWS} {
+ if {[regexp {^\w+:[\\\/]?$} $folder]} {break}
+ }
+ set folder [file normalize [file join $folder {..}]]
+ }
+ foreach folder [dir_cmd $dir 1] {
+ if {$folder == {..}} {continue}
+ lappend values [file join $dir $folder]
+ }
+ if {$::MICROSOFT_WINDOWS} { ;# Include drive letters on Microsoft Windows
+ foreach drive_letter {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z} {
+ if {[file exists "${drive_letter}:/"]} {
+ lappend values "${drive_letter}:/"
+ }
+ }
+ }
+
+ $dir_combobox configure -values $values
+ $dir_combobox current 0
+ $dir_combobox icursor end
+
+ # Enable / Disable button "Up (Parent folder)"
+ if {$dir == {/} || $dir == "\\"} {
+ $toolbar.up configure -state disabled
+ $win.listbox_menu entryconfigure [mc "Up"] -state disabled
+ } else {
+ $toolbar.up configure -state normal
+ $win.listbox_menu entryconfigure [mc "Up"] -state normal
+ }
+ }
+
+ ## This function shoul be called after Filter ComboBox change
+ # @return void
+ public method filter_cb_modify {} {
+ set current_mask [lindex $option_filetypes [$filter_cb current]]
+ reload
+ }
+
+ ## Show / Hide quick access bar according to configuration variable quick_access_panel
+ # @return void
+ public method quick_access_panel_onoff {} {
+ # Show the panel
+ if {${::KIFSD::FSD::config(quick_access_panel)}} {
+ pack $main_paned_window -fill both -expand 1
+ $main_paned_window add $leftframe
+ $main_paned_window add $rightframe
+ $main_paned_window paneconfigure $leftframe -minsize 100
+ $main_paned_window paneconfigure $rightframe -minsize 300
+ if {$dialog_loaded} {update}
+ $main_paned_window sash place 0 ${::KIFSD::FSD::config(main_PW_size)} 0
+ if {$dialog_loaded} {update}
+ # Hide the panel
+ } else {
+ if {[winfo ismapped $main_paned_window]} {
+ set ::KIFSD::FSD::config(main_PW_size) \
+ [lindex [$main_paned_window sash coord 0] {0 0}]
+ $main_paned_window forget $leftframe
+ $main_paned_window forget $rightframe
+ pack forget $main_paned_window
+ }
+ pack $rightframe -fill both -expand 1 -padx 5
+ }
+ }
+
+ ## Show / Hide folders ListBox according to configuration variable separate_folders
+ # This function will show folders ListBox only if option_fileson == 1
+ # @return void
+ public method separate_folders_onoff {} {
+ # Show folders ListBox
+ if {${::KIFSD::FSD::config(separate_folders)} && $option_fileson} {
+ pack $right_paned_window -fill both -expand 1
+ $right_paned_window add $right_top_left_frame
+ $right_paned_window add $right_top_right_frame
+ $right_paned_window paneconfigure $right_top_left_frame -minsize 150
+ $right_paned_window paneconfigure $right_top_right_frame -minsize 200
+ if {$dialog_loaded} {update}
+ $right_paned_window sash place 0 ${::KIFSD::FSD::config(right_PW_size)} 0
+ if {$dialog_loaded} {update}
+
+ # Hide folders ListBox
+ } else {
+ if {[winfo ismapped $right_paned_window]} {
+ set ::KIFSD::FSD::config(right_PW_size) \
+ [lindex [$right_paned_window sash coord 0] {0 0}]
+ $right_paned_window forget $right_top_left_frame
+ $right_paned_window forget $right_top_right_frame
+ pack forget $right_paned_window
+ }
+ pack $right_top_right_frame -expand 1 -fill both -in $right_top_frame
+ }
+
+ # Refresh files and folders ListBoxes
+ change_directory $current_directory
+ }
+
+ ## Invoke bookmark menu
+ # @return void
+ public method bookmark_menu {} {
+ set x [winfo rootx $toolbar.bookmark]
+ set y [winfo rooty $toolbar.bookmark]
+ incr y [winfo height $toolbar.bookmark]
+ tk_popup $win.bookmark_menu $x $y
+ }
+
+ ## Invoke configuration menu
+ # @return void
+ public method config_menu {} {
+ set x [winfo rootx $toolbar.configure]
+ set y [winfo rooty $toolbar.configure]
+ incr y [winfo height $toolbar.configure]
+ tk_popup $win.config_menu $x $y
+ }
+
+ ## Scroll folders ListBox and (Un)Map its scrollbar
+ # @parm Float frac0 - 1st fraction
+ # @parm Float frac0 - 2nd fraction
+ # @return void
+ public method dir_listbox_scroll {frac0 frac1} {
+ # Hide scrollbar
+ if {$frac0 == 0 && $frac1 == 1} {
+ if {[winfo ismapped $dir_listbox_scrollbar]} {
+ pack forget $dir_listbox_scrollbar
+ }
+ # Show scrollbar
+ } else {
+ if {![winfo ismapped $dir_listbox_scrollbar]} {
+ pack $dir_listbox_scrollbar -fill y -expand 1 -after $dir_listbox
+ }
+ $dir_listbox_scrollbar set $frac0 $frac1
+ }
+ }
+
+ ## Switch to mode "Short View"
+ # @return void
+ public method short_view {} {
+ if {!${::KIFSD::FSD::config(detailed_view)}} {return}
+ set ::KIFSD::FSD::config(detailed_view) 0
+ $file_listbox configure -multicolumn 1
+ set listbox_font $listbox_font_short
+ pack forget $file_listbox_header
+ reload
+ }
+
+ ## Switch to mode "Detailed View"
+ # @return void
+ public method detail_view {} {
+ if {${::KIFSD::FSD::config(detailed_view)}} {return}
+ set ::KIFSD::FSD::config(detailed_view) 1
+ $file_listbox configure -multicolumn 0
+ set listbox_font $listbox_font_detailed
+ pack $file_listbox_header -before $file_listbox -fill x -expand 0
+ reload
+ }
+
+ ## Bookmark current folder
+ # @return void
+ public method add_bookmark {} {
+ lappend ::KIFSD::FSD::config(bookmarks) $current_directory
+ $bookmark_menu add command \
+ -label $current_directory -compound left \
+ -image ::ICONS::16::fileopen \
+ -command "$this change_directory {$current_directory}"
+ uplevel #0 $bookmark_change_command
+ }
+
+ ## Invoke bookmark editor
+ # @return void
+ public method edit_bookmarks {} {
+ # Create dialog window
+ set dialog [toplevel $win.edit_bookmarks -class {Edit bookmarks} -bg ${::COMMON_BG_COLOR}]
+
+ # Create top frame (ListBox containing bookmarks and its scrollbar)
+ set top_frame [frame $dialog.top_frame]
+ set bookmark_edit_listbox [ListBox $top_frame.listbox \
+ -yscrollcommand "$top_frame.scrollbar set" \
+ -bg white -selectfill 1 -selectmode single \
+ -highlightcolor {#BBBBFF} \
+ ]
+ $bookmark_edit_listbox bindText <Double-1> "$this edit_bookmarks_edit"
+ pack $bookmark_edit_listbox -side left -fill both -expand 1
+ pack [ttk::scrollbar $top_frame.scrollbar \
+ -orient vertical \
+ -command "$bookmark_edit_listbox yview" \
+ ] -fill y -expand 1
+
+ # Fill up ListBox with defined bookmarks
+ foreach item ${::KIFSD::FSD::config(bookmarks)} {
+ $bookmark_edit_listbox insert end #auto -text $item
+ }
+
+ ## Create bottom frame (buttons)
+ set bottom_frame [frame $dialog.bottom_frame]
+ # Button: "Remove"
+ pack [ttk::button $bottom_frame.remove \
+ -text [::mc "Remove"] \
+ -compound left \
+ -image ::ICONS::16::editdelete \
+ -command "$this edit_bookmarks_remove" \
+ -width 8 \
+ ] -side left -padx 2
+ # Button: "Edit"
+ pack [ttk::button $bottom_frame.edit \
+ -text [::mc "Edit"] \
+ -compound left \
+ -image ::ICONS::16::edit \
+ -command "$this edit_bookmarks_edit" \
+ -width 8 \
+ ] -side left -padx 2
+ # Button: "Up"
+ pack [ttk::button $bottom_frame.up \
+ -text [::mc "Up"] \
+ -compound left \
+ -image ::ICONS::16::up \
+ -command "$this edit_bookmarks_up" \
+ -width 8 \
+ ] -side left -padx 2
+ # Button: "Down"
+ pack [ttk::button $bottom_frame.down \
+ -text [::mc "Down"] \
+ -compound left \
+ -image ::ICONS::16::down \
+ -command "$this edit_bookmarks_down" \
+ -width 8 \
+ ] -side left -padx 2
+ # Button: "Ok"
+ pack [ttk::button $bottom_frame.ok \
+ -text [::mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -width 8 \
+ -command "
+ $this bookmark_edit_ok
+ grab release $dialog
+ destroy $dialog
+ " \
+ ] -side right -padx 2
+ # Button: "Cancel"
+ pack [ttk::button $bottom_frame.cancel \
+ -text [::mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -width 8 \
+ -command "
+ grab release $dialog
+ destroy $dialog
+ " \
+ ] -side right -padx 2
+
+ # Pack dialog frames (top and bottom)
+ pack $top_frame -side top -fill both -expand 1 -pady 5 -padx 5
+ pack $bottom_frame -side top -after $top_frame -fill x -expand 0 -pady 5 -padx 5
+
+ # Configure dialog window
+ wm iconphoto $dialog ::ICONS::16::bookmark
+ wm title $dialog "Edit bookmarks"
+ wm minsize $dialog 550 240
+ wm geometry $dialog 550x340
+ wm protocol $dialog WM_DELETE_WINDOW "
+ grab release $dialog
+ destroy $dialog
+ "
+ if {[winfo ismapped $win]} {
+ wm transient $dialog $win
+ } else {
+ wm transient $dialog .
+ }
+ grab $dialog
+ raise $dialog
+ tkwait window $dialog
+ }
+
+ ## Auxiliary procedure for bookmark editor
+ # Remove current bookmark
+ # @return void
+ public method edit_bookmarks_remove {} {
+ set item [$bookmark_edit_listbox selection get]
+ if {$item == {}} {return}
+ $bookmark_edit_listbox delete $item
+ }
+
+ ## Auxiliary procedure for bookmark editor
+ # Edit current bookmark
+ # @return void
+ public method edit_bookmarks_edit args {
+ set item [$bookmark_edit_listbox selection get]
+ if {$item == {}} {return}
+ set text [$bookmark_edit_listbox edit $item \
+ [$bookmark_edit_listbox itemcget $item -text]]
+ if {$text == {}} {return}
+ $bookmark_edit_listbox itemconfigure $item -text $text
+ }
+
+ ## Auxiliary procedure for bookmark editor
+ # Move current bookmark up
+ # @return void
+ public method edit_bookmarks_up {} {
+ set item [$bookmark_edit_listbox selection get]
+ if {$item == {}} {return}
+ if {
+ ![$bookmark_edit_listbox index $item]
+ ||
+ ([llength [$bookmark_edit_listbox items]] < 2)
+ } then {
+ return
+ }
+ $bookmark_edit_listbox move $item [expr {[$bookmark_edit_listbox index $item] - 1}]
+ }
+
+ ## Auxiliary procedure for bookmark editor
+ # Move current bookmark down
+ # @return void
+ public method edit_bookmarks_down {} {
+ set item [$bookmark_edit_listbox selection get]
+ if {$item == {}} {return}
+ if {
+ [$bookmark_edit_listbox index $item]
+ >=
+ ([llength [$quick_access_bar items]] - 1)
+ } then {
+ return
+ }
+ $bookmark_edit_listbox move $item [expr {[$bookmark_edit_listbox index $item] + 1}]
+ }
+
+ ## Auxiliary procedure for bookmark editor
+ # Confirm bookmark edit dialog
+ # @return void
+ public method bookmark_edit_ok {} {
+ set ::KIFSD::FSD::config(bookmarks) {}
+ foreach item [$bookmark_edit_listbox items] {
+ lappend ::KIFSD::FSD::config(bookmarks) \
+ [$bookmark_edit_listbox itemcget $item -text]
+ }
+ refresh_bookmarks
+ uplevel #0 $bookmark_change_command
+ }
+
+ ## Reload items to bookmarks menu
+ # @return void
+ private method refresh_bookmarks {} {
+ if {[$bookmark_menu index end] > 2} {
+ $bookmark_menu delete 3 end
+ }
+ foreach dir ${::KIFSD::FSD::config(bookmarks)} {
+ $bookmark_menu add command \
+ -label $dir -compound left \
+ -image ::ICONS::16::fileopen \
+ -command "$this change_directory {$dir}"
+ }
+ }
+
+ ## Set command to execute when bookmark list changes
+ # @parm String command - Command to invoke from root namespace
+ # @return void
+ proc set_bookmark_change_command {command} {
+ set bookmark_change_command $command
+ }
+
+ ## Unmap dialog window (but keep object alive)
+ # @return void
+ public method deactivate {} {
+ wm withdraw $win
+ }
+
+ ## Activate (map) dialog window
+ # And wait until window is unmapped
+ # @return void
+ public method activate {} {
+ wm resizable $win 1 1
+ wm deiconify $win
+ update idletasks
+ if {[winfo ismapped $right_paned_window]} {
+ $right_paned_window sash place 0 ${::KIFSD::FSD::config(right_PW_size)} 0
+ }
+ if {[winfo ismapped $main_paned_window]} {
+ $main_paned_window sash place 0 ${::KIFSD::FSD::config(main_PW_size)} 0
+ }
+ tkwait window $win
+ }
+
+ ## Get selected item(s)
+ # @return String/List - Full path(s) to selected item(s)
+ public method get {} {
+ # Return List
+ if {$option_multiple} {
+ set result {}
+ foreach item [$file_listbox selection get] {
+ lappend result [file join $current_directory \
+ [lindex [$file_listbox itemcget $item -data] 0]]
+ }
+ if {$result == {}} {
+ lappend result [file join $current_directory [$location_cb get]]
+ }
+ return $result
+ # Return String
+ } else {
+ return [file join $current_directory [$location_cb get]]
+ }
+ }
+
+ ## Destroy dialog object
+ # @return void
+ public method close_dialog {} {
+ catch {
+ itcl::delete object $this
+ }
+ }
+
+ ## Set command to invoke from root namespace on action "Ok"
+ # @parm String command - Command (with arguments)
+ # @return void
+ public method setokcmd {cmd} {
+ set ok_command $cmd
+ }
+
+ ## Ok action - command for button "Ok"
+ # @return void
+ public method ok {} {
+ if {$option_autoclose} {
+ wm withdraw $win
+ set ok_command_tmp $ok_command
+ set ok_command {}
+ uplevel #0 $ok_command_tmp
+ close_dialog
+ } else {
+ uplevel #0 $ok_command
+ }
+ }
+
+ ## Command for files ListBox horizontal scrollbar
+ # Takes any list of arguments (see code)
+ # @return void
+ public method file_listbox_hscrollbar_cmd args {
+ eval "$file_listbox xview $args"
+ eval "$file_listbox_header xview $args"
+ }
+
+ ## Scroll files ListBox vertically
+ # This function manages scrollbar visibility
+ # @parm Float frac0 - 1st fraction (see Tk manual)
+ # @parm Float frac1 - 2nd fraction (see Tk manual)
+ # @return void
+ public method file_listbox_vscroll {frac0 frac1} {
+ # Hide scrollbar
+ if {$frac0 == 0 && $frac1 == 1} {
+ if {[winfo ismapped $file_listbox_vscrollbar]} {
+ pack forget $file_listbox_vscrollbar
+ update
+ }
+
+ # Show scrollbar
+ } else {
+ if {![winfo ismapped $file_listbox_vscrollbar]} {
+ pack $file_listbox_vscrollbar \
+ -after $file_listbox_frame \
+ -fill y -expand 1
+ update
+ }
+ $file_listbox_vscrollbar set $frac0 $frac1
+ }
+ }
+
+ ## Scroll files ListBox horizontaly
+ # This function manages scrollbar visibility
+ # @parm Float frac0 - 1st fraction (see Tk manual)
+ # @parm Float frac1 - 2nd fraction (see Tk manual)
+ # @return void
+ public method file_listbox_hscroll {frac0 frac1} {
+
+ # Hide scrollbar
+ if {$frac0 == 0 && $frac1 == 1} {
+ if {[winfo ismapped $file_listbox_hscrollbar]} {
+ pack forget $file_listbox_hscrollbar
+ update
+ }
+
+ # Show scrollbar
+ } else {
+ if {![winfo ismapped $file_listbox_hscrollbar]} {
+ pack $file_listbox_hscrollbar \
+ -after $right_top_right_top_frame \
+ -side bottom -fill x -expand 0
+ update
+ }
+ catch {
+ $file_listbox_hscrollbar set $frac0 $frac1
+ }
+ }
+ }
+
+ ## Event handler for quick access bar ListBox, event <<ListboxSelect>>
+ # @return void
+ public method quick_access_bar_select {} {
+ if {$option_doubleclick} {return}
+ catch {
+ change_directory \
+ [$quick_access_bar itemcget \
+ [$quick_access_bar selection get] -data]
+ }
+ }
+
+ ## Event handler for quick access bar ListBox, item event <Double-1>
+ # @parm String item - Item identifier
+ # @return void
+ public method quick_access_bar_doubleclick {item} {
+ if {!$option_doubleclick} {return}
+ catch {
+ change_directory \
+ [$quick_access_bar itemcget \
+ [$quick_access_bar selection get] -data]
+ }
+ }
+
+ ## Event handler for directories ListBox, item event <Double-1>
+ # @parm String item - Item identifier
+ # @return void
+ public method dir_listbox_doubleclick {item} {
+ # Abort if dirs ListBox widget is no longer available
+ if {![winfo exists $dir_listbox]} {
+ return
+ }
+ if {!$option_doubleclick} {return}
+ catch {
+ change_directory [file join $current_directory \
+ [$dir_listbox itemcget $item -text]]
+ }
+ }
+
+ ## Event handler for directories ListBox, event <<ListboxSelect>>
+ # @return void
+ public method dir_listbox_select {} {
+ # Abort if dirs ListBox widget is no longer available
+ if {![winfo exists $dir_listbox]} {
+ return
+ }
+ if {$option_doubleclick} {return}
+ catch {
+ change_directory [file normalize [file join $current_directory \
+ [$dir_listbox itemcget [$dir_listbox selection get] -text]]]
+ }
+ }
+
+ ## Event handler for files ListBox, item event <Double-1>
+ # @parm String item - Item identifier
+ # @return void
+ public method file_listbox_doubleclick {item} {
+ # Abort if files ListBox widget is no longer available
+ if {![winfo exists $file_listbox]} {
+ return
+ }
+
+ # Item directory or {} if it's a file
+ if {[catch {
+ set folder [lindex [$file_listbox itemcget $item -data] 1]
+ }]} then {
+ return
+ }
+
+ if {!$option_fileson} {
+ if {$folder != {}} {
+ change_directory [file join $current_directory $folder]
+ }
+ return
+ }
+
+ if {$option_doubleclick && !${::KIFSD::FSD::config(separate_folders)}} {
+ if {$folder != {}} {
+ change_directory [file join $current_directory $folder]
+ }
+ }
+
+ if {!$option_doubleclick && ($folder == {})} {
+ ok
+ }
+ }
+
+ ## Scroll files listbox
+ # Arguments are passed to yview or xview command
+ # @return void
+ public method file_listbox_scroll args {
+ if {${::KIFSD::FSD::config(detailed_view)}} {
+ set cmd {yview}
+ } else {
+ set cmd {xview}
+ }
+ eval "$file_listbox.c $cmd scroll $args"
+ }
+
+ ## Event handler for files ListBox, event <<ListboxSelect>>
+ # @return void
+ public method file_listbox_select {} {
+ set selection [$file_listbox selection get]
+
+ # Change directory if the item represents a directory
+ if {$option_fileson && !${::KIFSD::FSD::config(separate_folders)}} {
+ set folder [$file_listbox itemcget [lindex $selection end] -data]
+ set folder [lindex $folder 1]
+ if {$folder != {}} {
+ if {!$option_doubleclick} {
+ change_directory [file join $current_directory $folder]
+ }
+ return
+ }
+ }
+
+ # Change content of location ComboBox if item is a file
+ if {[llength $selection] == 1} {
+ set index [lindex [$file_listbox itemcget $selection -data] [expr {$option_fileson ? 0 : 1}]]
+ if {$index != {..}} {
+ set index [lsearch -ascii [$location_cb cget -values] $index]
+ if {$index != -1} {
+ $location_cb current $index
+ }
+ }
+ } elseif {[llength $selection] > 1} {
+ set text {}
+ foreach item $selection {
+ append text "\""
+ append text [lindex [$file_listbox itemcget $item -data] [expr {$option_fileson ? 0 : 1}]]
+ append text "\" "
+ }
+ $location_cb set $text
+ }
+ }
+
+ ## Reload content of quick access bar ListBox
+ # @return void
+ private method refresh_quick_access_bar {} {
+ # Remove existing items
+ $quick_access_bar delete [$quick_access_bar items]
+
+ # Create new items
+ foreach item ${::KIFSD::FSD::config(quick_access_bar_data)} {
+ # Determinate item icon
+ switch -- [lindex $item 0] {
+ 0 {set image hdd_unmount}
+ 1 {set image folder_home}
+ 2 {set image desktop}
+ 3 {set image bookmark_folder}
+ }
+ # Insert item
+ $quick_access_bar insert end #auto \
+ -font $quick_nav_panel_font \
+ -image ::ICONS::22::$image \
+ -text [lindex $item 1] \
+ -data [lindex $item 2] \
+ }
+ }
+
+ ## Invoke popup menu for ListBox of Quick access bar
+ # @parm Int x - Relative position of mouse pointer
+ # @parm Int y - Relative position of mouse pointer
+ # @return void
+ public method quick_access_bar_menu {x y} {
+ if {$item_menu_request} {
+ set item_menu_request 0
+ return
+ }
+ catch {
+ tk_popup $win.quick_access_panel_menu $x $y
+ }
+ }
+
+ ## Invoke popup menu for particular item in ListBox of Quick access bar
+ # @parm Int x - Relative position of mouse pointer
+ # @parm Int y - Relative position of mouse pointer
+ # @parm String item - Item identifier
+ # @return void
+ public method quick_access_bar_item_menu {x y item} {
+ set item_menu_request 1
+ set current_item $item
+ set current_item_index [$quick_access_bar index $item]
+ set len [llength [$quick_access_bar items]]
+
+ # Enable / Disabled entry "Move down"
+ if {$current_item_index >= ($len - 1)} {
+ $win.quick_access_panel_item_menu entryconfigure [mc "Move down"] -state disabled
+ } else {
+ $win.quick_access_panel_item_menu entryconfigure [mc "Move down"] -state normal
+ }
+
+ # Enable / Disabled entry "Move up"
+ if {!$current_item_index || ($len < 2)} {
+ $win.quick_access_panel_item_menu entryconfigure [mc "Move up"] -state disabled
+ } else {
+ $win.quick_access_panel_item_menu entryconfigure [mc "Move up"] -state normal
+ }
+
+ # Invoke the menu
+ tk_popup $win.quick_access_panel_item_menu $x $y
+ }
+
+ ## Move current item in quick access bar down
+ # @return void
+ public method quick_access_panel_down {} {
+ # Check if the item is not the topmost one
+ if {$current_item_index >= ([llength [$quick_access_bar items]] - 1)} {
+ return
+ }
+
+ set ::KIFSD::FSD::config(quick_access_bar_data) [lreplace \
+ ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ $current_item_index [expr {$current_item_index + 1}] \
+ [lindex ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ [expr {$current_item_index + 1}]] \
+ [lindex ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ $current_item_index]
+ ]
+ refresh_quick_access_bar
+ }
+
+ ## Move current item in quick access bar up
+ # @return void
+ public method quick_access_panel_up {} {
+ # Check if the item is not the bottommost one
+ if {!$current_item_index || ([llength [$quick_access_bar items]] < 2)} {
+ return
+ }
+
+ set ::KIFSD::FSD::config(quick_access_bar_data) [lreplace \
+ ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ [expr {$current_item_index - 1}] $current_item_index \
+ [lindex ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ $current_item_index] \
+ [lindex ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ [expr {$current_item_index - 1}]]
+ ]
+ refresh_quick_access_bar
+ }
+
+ ## Invoke dialog to add entry to quick access bar
+ # @return void
+ public method quick_access_panel_add_entry {} {
+ set data [qa_panel_dialog "Add entry" {3} [::mc "New entry"] {~}]
+ if {![string length [lindex $data 1]]} {return}
+ if {![string length [lindex $data 2]]} {return}
+ lappend ::KIFSD::FSD::config(quick_access_bar_data) $data
+ refresh_quick_access_bar
+ }
+
+ ## Invoke dialog to edit current entry in quick access bar
+ # @return void
+ public method quick_access_panel_edit_entry {} {
+ set data [lindex ${::KIFSD::FSD::config(quick_access_bar_data)} $current_item_index]
+ set data [qa_panel_dialog "Edit entry" [lindex $data 0] [lindex $data 1] [lindex $data 2]]
+ if {![string length [lindex $data 1]]} {return}
+ if {![string length [lindex $data 2]]} {return}
+ set ::KIFSD::FSD::config(quick_access_bar_data) [lreplace \
+ ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ $current_item_index $current_item_index $data \
+ ]
+ refresh_quick_access_bar
+ }
+
+ ## Select icon in quick access bar edit dialog
+ # @parm Int index - Icon index [0; 4]
+ # @return void
+ public method qa_panel_dialog_icon {index} {
+ for {set i 0} {$i < 4} {incr i} {
+ ${win}.qa_panel_dialog.labelframe.button_$i configure -style Flat.TButton
+ }
+ ${win}.qa_panel_dialog.labelframe.button_$index configure -style TButton
+ set ::KIFSD::FSD::qa_panel_dialog_icon $index
+ }
+
+ ## EntryBox validator
+ # If the content was an empty string then set entry background color to red
+ # @parm Widget widget - EntryBox widget
+ # @parm String content - EntryBox content
+ # @return Bool - Always 1
+ proc not_empty_entry_validator {widget content} {
+ if {![string length $content]} {
+ $widget configure -style StringNotFound.TEntry
+ } else {
+ $widget configure -style TEntry
+ }
+ return 1
+ }
+
+ ## Invoke dialog for editing entries in the quick access bar
+ # Auxiliary procedure for:
+ # * quick_access_panel_add_entry
+ # * quick_access_panel_edit_entry
+ # @parm String title - Dialog title
+ # @parm Int icon - Icon number [0;3]
+ # @parm String name - Item name
+ # @parm String url - Target URL
+ # @return List - {new_icon_number new_name new_url}
+ private method qa_panel_dialog {title icon name url} {
+ # Create dialog window
+ set dialog [toplevel ${win}.qa_panel_dialog -class {Configuration dialog} -bg ${::COMMON_BG_COLOR}]
+
+ # Set dialog variables
+ set ::KIFSD::FSD::qa_panel_dialog_icon $icon
+ set ::KIFSD::FSD::qa_panel_dialog_name_entry $name
+ set ::KIFSD::FSD::qa_panel_dialog_url_entry $url
+
+ ## Create main frame (Name: and URL:)
+ set mid_frame [frame $dialog.middle]
+ # Label: "Name"
+ grid [label $mid_frame.name_lbl \
+ -text [::mc "Name"] \
+ ] -row 0 -column 0 -sticky w
+ # Label: "URL"
+ grid [label $mid_frame.url_lbl \
+ -text [::mc "URL"] \
+ ] -row 1 -column 0 -sticky w
+ # EntryBox: "Name"
+ grid [ttk::entry $mid_frame.name_entry \
+ -width 1 \
+ -validate all \
+ -validatecommand "::KIFSD::FSD::not_empty_entry_validator %W %P" \
+ -textvariable ::KIFSD::FSD::qa_panel_dialog_name_entry \
+ ] -row 0 -column 1 -sticky we
+ # EntryBox: "URL"
+ grid [ttk::entry $mid_frame.url_entry \
+ -width 1 \
+ -validate all \
+ -textvariable ::KIFSD::FSD::qa_panel_dialog_url_entry \
+ -validatecommand "::KIFSD::FSD::dir_validate {} %W %P" \
+ ] -row 1 -column 1 -sticky we
+ grid columnconfigure $mid_frame 1 -weight 1
+ pack $mid_frame -padx 10 -pady 5 -fill x -expand 1
+
+ # Create frame for selecting icon
+ pack [ttk::labelframe $dialog.labelframe \
+ -text [::mc "Icon"] \
+ ] -fill none -expand 1 -anchor w -padx 10
+ foreach icon {hdd_unmount folder_home desktop bookmark_folder} index {0 1 2 3} {
+ pack [ttk::button $dialog.labelframe.button_$index \
+ -image ::ICONS::22::$icon \
+ -command "$this qa_panel_dialog_icon $index" \
+ -width 6 \
+ -style Flat.TButton \
+ ] -side left -padx 5 -pady 5
+ }
+ $dialog.labelframe.button_${::KIFSD::FSD::qa_panel_dialog_icon} \
+ configure -style TButton
+
+ ## Create bottom frame (Buttons "Ok" and "Cancel")
+ set bot_frame [frame $dialog.bot]
+ # Button: "Ok"
+ pack [ttk::button $bot_frame.ok \
+ -text [::mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command "
+ if \[string length \${::KIFSD::FSD::qa_panel_dialog_name_entry}\] {
+ if \[string length \${::KIFSD::FSD::qa_panel_dialog_url_entry}\] {
+ grab release $dialog
+ destroy $dialog
+ }
+ }" \
+ ] -side left -fill none -expand 0 -padx 2
+ # Button: "Cancel"
+ pack [ttk::button $bot_frame.cancel \
+ -text [::mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command "
+ set ::KIFSD::FSD::qa_panel_dialog_url_entry {}
+ set ::KIFSD::FSD::qa_panel_dialog_name_entry {}
+ set ::KIFSD::FSD::qa_panel_dialog_icon {}
+ grab release $dialog
+ destroy $dialog" \
+ ] -side left -fill none -expand 0 -padx 2
+ pack $bot_frame -anchor e -padx 10 -pady 5
+
+ # Configure dialog window
+ wm title $dialog $title
+ wm resizable $dialog 0 0
+ wm geometry $dialog 380x160
+ wm protocol $dialog WM_DELETE_WINDOW "
+ set ::KIFSD::FSD::qa_panel_dialog_url_entry {}
+ set ::KIFSD::FSD::qa_panel_dialog_name_entry {}
+ set ::KIFSD::FSD::qa_panel_dialog_icon {}
+ grab release $dialog
+ destroy $dialog
+ "
+ wm transient $dialog $win
+ grab $dialog
+ raise $dialog
+ focus -force $mid_frame.name_entry
+ tkwait window $dialog
+
+ # Return results
+ return [list \
+ ${::KIFSD::FSD::qa_panel_dialog_icon} \
+ ${::KIFSD::FSD::qa_panel_dialog_name_entry} \
+ ${::KIFSD::FSD::qa_panel_dialog_url_entry} \
+ ]
+ }
+
+ ## Remove entry from quick access bar (popup menu action)
+ # @return void
+ public method quick_access_panel_remove_entry {} {
+ set ::KIFSD::FSD::config(quick_access_bar_data) \
+ [lreplace ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ $current_item_index $current_item_index]
+ refresh_quick_access_bar
+ }
+
+ ## Invoke popup menu for directories ListBox
+ # @parm Int x - Relative position of mouse pointer
+ # @parm Int y - Relative position of mouse pointer
+ # @return void
+ public method dir_listbox_menu {x y} {
+ if {$item_menu_request} {
+ set item_menu_request 0
+ return
+ }
+ foreach entry {Rename Delete Properties {Bookmark folder}} {
+ $win.listbox_menu entryconfigure [mc $entry] -state disabled
+ }
+ tk_popup $win.listbox_menu $x $y
+ }
+
+ ## Invoke popup menu for item in directories ListBox
+ # @parm Int x - Relative position of mouse pointer
+ # @parm Int y - Relative position of mouse pointer
+ # @parm String item - Item identifier
+ # @return void
+ public method dir_listbox_item_menu {x y item} {
+ set item_menu_request 1
+ foreach entry {Rename Delete Properties {Bookmark folder}} {
+ $win.listbox_menu entryconfigure [mc $entry] -state normal
+ }
+ set cur_listbox {dir}
+ set current_item $item
+ set current_item_index [$dir_listbox index $item]
+ tk_popup $win.listbox_menu $x $y
+ }
+
+ ## Invoke popup menu for files ListBox
+ # @parm Int x - Relative position of mouse pointer
+ # @parm Int y - Relative position of mouse pointer
+ # @return void
+ public method file_listbox_menu {x y} {
+ if {$item_menu_request} {
+ set item_menu_request 0
+ return
+ }
+ foreach entry {Rename Delete Properties} {
+ $win.listbox_menu entryconfigure [mc $entry] -state disabled
+ }
+ $win.listbox_menu entryconfigure [mc {Bookmark folder}] -state normal
+ tk_popup $win.listbox_menu $x $y
+ }
+
+ ## Invoke popup menu for item in files ListBox
+ # @parm Int x - Relative position of mouse pointer
+ # @parm Int y - Relative position of mouse pointer
+ # @parm String item - Item identifier
+ # @return void
+ public method file_listbox_item_menu {x y item} {
+ set item_menu_request 1
+ set current_item $item
+ set current_item_index [$dir_listbox index $item]
+ foreach entry {Rename Delete Properties {Bookmark folder}} {
+ $win.listbox_menu entryconfigure [mc $entry] -state normal
+ }
+ set cur_listbox {file}
+ set current_item $item
+ set current_item_index [$dir_listbox index $item]
+ tk_popup $win.listbox_menu $x $y
+ }
+
+ ## Remove selected file or directory
+ # @return void
+ public method delete_item_command {} {
+ # Determinate URL to delete
+ if {$cur_listbox == {dir}} {
+ set filename [$dir_listbox itemcget $current_item -text]
+ } else {
+ set data [$file_listbox itemcget $current_item -data]
+ if {[lindex $data 0] == {}} {
+ set filename [lindex $data 1]
+ } else {
+ set filename [lindex $data 0]
+ }
+ }
+ if {$filename == {}} {return}
+
+ # Invoke confirmation dialog
+ if {[tk_messageBox \
+ -parent $win \
+ -type yesno \
+ -icon question \
+ -title [::mc "Delete file"] \
+ -message [::mc "Do you really want to delete file:\n%s" $filename]]
+ ==
+ {yes}
+ } then {
+ # Delete file/directory (+ invoke error dialog)
+ if {[catch {file delete -force -- [file join $current_directory $filename]}]} {
+ tk_messageBox \
+ -parent $win \
+ -type ok \
+ -icon warning \
+ -title [::mc "Permission denied"] \
+ -message [::mc "Unable to remove file:\n%s" $filename]
+ }
+ }
+ reload
+ }
+
+ ## Bookmark selected folder
+ # @return void
+ public method item_bookmark_add {} {
+ set tmp $current_directory
+ if {$cur_listbox == {dir}} {
+ set current_directory [file join $current_directory \
+ [$dir_listbox itemcget $current_item -text]]
+ }
+ add_bookmark
+ set current_directory $tmp
+ }
+
+ ## Rename selected file or directory
+ # @return void
+ public method rename_item_command {} {
+ if {$cur_listbox == {dir}} {
+ set listbox $dir_listbox
+ } else {
+ set listbox $file_listbox
+ }
+
+ # Determinate old and new name
+ set original [$listbox itemcget $current_item -text]
+ set newname [$listbox edit $current_item \
+ [$listbox itemcget $current_item -text]]
+ if {$newname == {}} {
+ return
+ }
+
+ # Adjust old and new name
+ set original [file join $current_directory $original]
+ set newname [file join $current_directory $newname]
+
+ # Rename file
+ if {[catch {file rename -force $original $newname}]} {
+ tk_messageBox \
+ -parent $win \
+ -type ok \
+ -icon warning \
+ -title [::mc "Permission denied"] \
+ -message [::mc "Unable to rename file:\n%s" $original]
+ }
+ reload
+ }
+
+ ## Invoke item properties dialog
+ # @return void
+ public method properties_item_command {} {
+ # Determinate item name, type (File or Directory)
+ if {$cur_listbox == {dir}} {
+ set name [$dir_listbox itemcget $current_item -text]
+ set type "Directory"
+ } else {
+ set name [$file_listbox itemcget $current_item -data]
+ if {[lindex $name 0] == {}} {
+ set name [lindex $name 1]
+ set type "Directory"
+ } else {
+ set name [lindex $name 0]
+ set type "File"
+ }
+ }
+
+ # Determinate full name
+ set fullname [file join $current_directory $name]
+ if {![file exists $fullname]} {
+ tk_messageBox \
+ -parent $win \
+ -type ok \
+ -icon warning \
+ -title [::mc "Unknown Error"] \
+ -message [::mc "This file apparently does not exist"]
+ return
+ }
+ # Determinate size
+ set size [file size $fullname]
+ append size { B}
+ # Determinate time of the last mofication
+ set modified [clock format [file mtime $fullname] -format {%D %R}]
+ # Determinate time of the last access
+ set accessed [clock format [file atime $fullname] -format {%D %R}]
+ # Determinate group, owner and permissions
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights)
+ set perms [file attributes $fullname]
+ set group [lindex $perms 1]
+ set owner [lindex $perms 3]
+ set perms [lindex $perms 5]
+ set perms [string range $perms {end-3} end]
+ foreach var {ur uw ux gr gw gx or ow ox} \
+ mask {0400 0200 0100 040 020 010 04 02 01} \
+ {
+ set ::KIFSD::FSD::item_properties($var) [expr {($perms & $mask) > 0}]
+ }
+ }
+
+ # Create dialog window and Notebook
+ set dialog [toplevel $win.properties_dialog -class {Configuration dialog} -bg ${::COMMON_BG_COLOR}]
+ set nb [NoteBook $dialog.nb -bg ${::COMMON_BG_COLOR}]
+ $nb insert end general -text "General"
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights)
+ $nb insert end permission -text "Permissions"
+ }
+ $nb raise general
+
+ ## Create GUI elements for tag "General"
+ set frame [frame [$nb getframe general].frame]
+ pack $frame -side top -anchor n -fill x -expand 1
+ # Name:
+ set row 0
+ grid [label $frame.lbl_$row \
+ -text [::mc "Name:"] -anchor w \
+ -font $listbox_font_short \
+ ] -column 0 -row $row -sticky w -pady 3
+ set ::KIFSD::FSD::item_properties(name) $name
+ grid [ttk::entry $frame.val_lbl_$row \
+ -validate all \
+ -textvariable ::KIFSD::FSD::item_properties(name) \
+ -validatecommand "::KIFSD::FSD::not_empty_entry_validator %W %P" \
+ ] -column 1 -row $row -sticky w -pady 3
+ # Type, Location, Size, Modified, Accessed
+ incr row
+ foreach lbl [list "Type" "Location" "Size" "Modified" "Accessed"] \
+ value [list $type $current_directory $size $modified $accessed] \
+ {
+ grid [label $frame.lbl_$row \
+ -text "[::mc $lbl]:" -anchor w \
+ -font $listbox_font_short \
+ ] -column 0 -row $row -sticky w -pady 3
+ grid [label $frame.val_lbl_$row \
+ -text $value -anchor w \
+ ] -column 1 -row $row -sticky w -pady 3
+ incr row
+ }
+ grid columnconfigure $frame 0 -minsize 100
+
+ ## Create GUI elements for tag "Permissions"
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights)
+ set frame [$nb getframe permission]
+ set ap_frame [ttk::labelframe $frame.ap_frame \
+ -text [::mc "Access permissions"] \
+ ]
+ set i 0
+ foreach text [list "Class" "Read" "Write" "Exec" "Owner" "Group" "Others"] \
+ row {0 0 0 0 1 2 3} \
+ col {0 1 2 3 0 0 0} \
+ {
+ grid [label $ap_frame.lbl_$i \
+ -text [::mc $text] \
+ -justify center \
+ ] -row $row -column $col -sticky w -padx 4 -pady 4
+ incr i
+ }
+ foreach var {ur uw ux gr gw gx or ow ox} \
+ row {1 1 1 2 2 2 3 3 3} \
+ col {1 2 3 1 2 3 1 2 3} \
+ {
+ grid [checkbutton $ap_frame.check_$i \
+ -variable ::KIFSD::FSD::item_properties($var)
+ ] -row $row -column $col
+ incr i
+ }
+
+ grid columnconfigure $ap_frame 0 -minsize 70
+ grid columnconfigure $ap_frame 0 -weight 1
+ pack $ap_frame -side top -fill x -expand 1 -padx 5 -pady 5 -anchor nw
+
+ set own_frame [ttk::labelframe $frame.own_frame \
+ -text [::mc "Ownership"] \
+ ]
+ grid [label $own_frame.owner_lbl \
+ -text [::mc "Owner"] -font $listbox_font_short \
+ ] -row 0 -column 0 -padx 10 -pady 3 -sticky w
+ grid [label $own_frame.owner_val_lbl \
+ -text $owner -anchor w \
+ ] -row 0 -column 1 -padx 10 -pady 3 -sticky we
+ grid [label $own_frame.group_lbl \
+ -text [::mc "Group"] -font $listbox_font_short \
+ ] -row 1 -column 0 -padx 10 -pady 3 -sticky w
+ grid [label $own_frame.group_val_lbl \
+ -text $group -anchor w \
+ ] -row 1 -column 1 -padx 10 -pady 3 -sticky we
+ grid columnconfigure $own_frame 0 -minsize 70
+ grid columnconfigure $own_frame 1 -weight 1
+ pack $own_frame -side top -fill x -expand 1 -padx 5 -pady 5
+ }
+
+ # Create bottom frame (buttons: "Ok" and "Cancel")
+ set bottom_frame [frame $dialog.bottom_frame]
+ pack [ttk::button $bottom_frame.ok \
+ -text [::mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command "$this properties_ok $dialog $fullname" \
+ ] -side left -padx 2
+ pack [ttk::button $bottom_frame.cancel \
+ -text [::mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command "
+ grab release $dialog
+ destroy $dialog
+ " \
+ ] -side left -padx 2
+
+ # Pack notebook and bottom frame
+ pack $nb -fill both -expand 1 -padx 10 -pady 5
+ pack $bottom_frame -anchor e -after $nb -padx 10 -pady 5
+
+ # Configure dialog window
+ wm title $dialog [::mc "Item properties"]
+ wm minsize $dialog 280 320
+ wm protocol $dialog WM_DELETE_WINDOW "
+ grab release $dialog
+ destroy $dialog"
+ wm transient $dialog $win
+ grab $dialog
+ raise $dialog
+ tkwait window $dialog
+ }
+
+ ## Confirm item properties dialog
+ # @parm Widget dialog - Dialog window
+ # @parm String file - File URL
+ # @return void
+ public method properties_ok {dialog file} {
+ set error 0
+ set perm 0
+
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights)
+ foreach var {ur uw ux gr gw gx or ow ox} \
+ val {256 128 64 32 16 8 4 2 1} {
+ if {$::KIFSD::FSD::item_properties($var)} {
+ incr perm $val
+ }
+ }
+ if {[catch {file attributes $file -permissions "0[format {%o} $perm]"}]} {
+ set error 1
+ tk_messageBox \
+ -type ok \
+ -icon warning \
+ -parent $dialog \
+ -title [::mc "Permission denied"] \
+ -message [::mc "Unable to change permissions for file:\n%s" [file tail $file]]
+ }
+ }
+ set dir [file dirname $file]
+
+ if {${::KIFSD::FSD::item_properties(name)} != [file tail $file]} {
+ if {[catch {
+ file rename -force -- \
+ $file [file join $dir \
+ ${::KIFSD::FSD::item_properties(name)}]}]
+ } then {
+ set error 1
+ tk_messageBox \
+ -type ok \
+ -icon warning \
+ -parent $dialog \
+ -title [::mc "Permission denied"] \
+ -message [::mc "Unable to rename file:%s" "\n[file tail $file]\n\t=>\n${::KIFSD::FSD::item_properties(name)}"]
+ }
+ reload
+ }
+
+ if {!$error} {
+ grab release $dialog
+ destroy $dialog
+ }
+ }
+
+ ## Validate EntryBox containing directory location (set background color: red/white)
+ # @parm widget combobox - ComboBox widget or {}
+ # @parm Widget widget - EntryBox widget
+ # @parm String content - EntryBox content
+ # @return Bool - Always 1
+ proc dir_validate {combobox widget content} {
+ if {![file exists $content] || ![file isdirectory $content]} {
+ if {$combobox != {}} {
+ $combobox configure -style FSD_RedBg.TCombobox
+ } else {
+ $widget configure -style FSD_RedBg.TEntry
+ }
+ } else {
+ if {$combobox != {}} {
+ $combobox configure -style TCombobox
+ } else {
+ $widget configure -style TEntry
+ }
+
+ # Fill directory location combobox
+ if {$combobox != {}} {
+ set folder $content
+ set values {}
+ while {1} {
+ lappend values $folder
+ if {$folder == [file separator]} {break}
+ if {$::MICROSOFT_WINDOWS} {
+ if {[regexp {^\w+:[\\\/]?$} $folder]} {break}
+ }
+ set folder [file normalize [file join $folder {..}]]
+ }
+ foreach folder [::KIFSD::FSD::dir_cmd $content 1] {
+ if {$folder == {..}} {continue}
+ lappend values [file join $content $folder]
+ }
+ if {$::MICROSOFT_WINDOWS} { ;# Include drive letters on Microsoft Windows
+ foreach drive_letter {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z} {
+ if {[file exists "${drive_letter}:/"]} {
+ lappend values "${drive_letter}:/"
+ }
+ }
+ }
+ $combobox configure -values $values
+ }
+ }
+ return 1
+ }
+
+ ## Reload content of directories ListBox and files ListBox
+ # @param List args - all arguments are ignored
+ # @return void
+ public method reload {args} {
+ update idletasks
+ change_directory $current_directory
+ }
+
+ ## Modify command for directory ComboBox
+ # @return void
+ public method dir_cb_modify {} {
+ change_directory [$dir_combobox get]
+ }
+
+ ## Go to parrent folder
+ # @return void
+ public method up {} {
+ change_directory [file normalize [file join $current_directory {..}]]
+ }
+
+ ## Go back in history
+ # @return void
+ public method back {} {
+ # Determinate new folder
+ set folder [lindex $back_history end]
+ if {$folder == {}} {return}
+
+ # Adjust backward and forward history
+ set back_history [lreplace $back_history end end]
+ lappend forward_history $current_directory
+
+ # Make backup copy of backward and forward history
+ set tmp_forw_hist $forward_history
+ set tmp_back_hist $back_history
+
+ # Change current directory
+ change_directory $folder
+
+ # Restore backward and forward history
+ set forward_history $tmp_forw_hist
+ set back_history $tmp_back_hist
+
+ # Enable / Disable buttons "Back" and "Forward"
+ if {![llength $back_history]} {
+ $toolbar.back configure -state disabled
+ $win.listbox_menu entryconfigure [mc "Back"] -state disabled
+ } else {
+ $toolbar.back configure -state normal
+ $win.listbox_menu entryconfigure [mc "Back"] -state normal
+ }
+ $win.listbox_menu entryconfigure [mc "Forward"] -state normal
+ $toolbar.forward configure -state normal
+ }
+
+ ## Go forward in history
+ # @return void
+ public method forward {} {
+ # Determinate new folder
+ set folder [lindex $forward_history end]
+ if {$folder == {}} {return}
+
+ # Adjust backward and forward history
+ set forward_history [lreplace $forward_history end end]
+ lappend back_history $current_directory
+
+ # Make backup copy of backward and forward history
+ set tmp_forw_hist $forward_history
+ set tmp_back_hist $back_history
+
+ # Change current directory
+ change_directory $folder
+
+ # Restore backward and forward history
+ set forward_history $tmp_forw_hist
+ set back_history $tmp_back_hist
+
+ # Enable / Disable buttons "Back" and "Forward"
+ if {![llength $forward_history]} {
+ $toolbar.forward configure -state disabled
+ $win.listbox_menu entryconfigure [mc "Forward"] -state disabled
+ } else {
+ $toolbar.forward configure -state normal
+ $win.listbox_menu entryconfigure [mc "Forward"] -state normal
+ }
+ $toolbar.back configure -state normal
+ $win.listbox_menu entryconfigure [mc "Back"] -state normal
+ }
+
+ ## Invoke dialog to create a new directory
+ # @return void
+ public method newdir {} {
+ # Create dialog window
+ set dialog [toplevel $win.new_dir -class {New directory} -bg ${::COMMON_BG_COLOR}]
+
+ # Create dialog header and EntryBox
+ pack [label $dialog.header -justify left -text [mc "Create new folder in:\n%s" $current_directory]] \
+ -side top -anchor w -padx 15 -pady 5
+ pack [ttk::entry $dialog.entry \
+ ] -side top -fill x -expand 1 -padx 5 -pady 5
+
+ # Bind button enter to confirmation action
+ bind $dialog.entry <Return> "[list $this create_new_folder]; break"
+ bind $dialog.entry <KP_Enter> "[list $this create_new_folder]; break"
+
+ # Create bottom frame (Buttons: "Clear", "Ok" and "Cancel")
+ set button_frame [frame $dialog.bottom]
+ pack [ttk::button $button_frame.clear \
+ -text [mc "Clear"] \
+ -compound left \
+ -image ::ICONS::16::clear_left \
+ -command "$dialog.entry delete 0 end" \
+ ] -side left -expand 0 -padx 2
+ pack [ttk::button $button_frame.ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command [list $this create_new_folder] \
+ ] -side left -expand 0 -padx 2
+ pack [ttk::button $button_frame.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command "
+ grab release $dialog
+ destroy $dialog
+ " \
+ ] -side left -expand 0 -padx 2
+ pack $button_frame -side bottom -anchor e -expand 0 -padx 5 -pady 5
+
+ # Configure dialog window
+ wm iconphoto $dialog ::ICONS::16::folder_new
+ wm title $dialog [mc "New folder"]
+ wm resizable $dialog 1 0
+ wm minsize $dialog 340 120
+ wm geometry $dialog 340x120
+ wm protocol $dialog WM_DELETE_WINDOW "
+ grab release $dialog
+ destroy $dialog
+ "
+ wm transient $dialog $win
+ grab $dialog
+ raise $dialog
+ focus -force $dialog.entry
+ tkwait window $dialog
+ }
+
+ ## Confirm dialog "Create new folder"
+ # @return void
+ public method create_new_folder {} {
+ set dialog ${win}.new_dir
+ set folder [$dialog.entry get]
+ set error 0
+
+ if {$folder == {}} {
+ set error 1
+ }
+ if {$error || [catch {file mkdir [file join $current_directory $folder]}]} {
+ tk_messageBox \
+ -parent $dialog \
+ -icon warning \
+ -type ok \
+ -title [mc "Unable to create folder"] \
+ -message [mc "Unable to create the specified folder"]
+ } else {
+ grab release $dialog
+ destroy $dialog
+ reload
+ }
+ }
+
+ ## Sort the given list of strings
+ # This procedure is closely related to inner logic of this
+ #+ class and it is difficult to properly explain its function
+ # @parm List items - List to sort
+ # @return void
+ proc sort_items {items} {
+ # Determinate sorting order
+ if {${::KIFSD::FSD::config(reverse_sorting)}} {
+ set order "-decreasing"
+ } else {
+ set order "-increasing"
+ }
+
+ if {${::KIFSD::FSD::config(sorting)} == {name}} {
+ if {${::KIFSD::FSD::config(case_insensitive)}} {
+ set method "-dictionary"
+ } else {
+ set method "-ascii"
+ }
+ return [lsort $method $order $items]
+ } else {
+ if {${::KIFSD::FSD::config(sorting)} == {size}} {
+ # Sort by size
+ set index 2
+ } else {
+ # Sort by date
+ set index 1
+ }
+ set items [lsort -index $index $order $items]
+
+ set result {}
+ foreach file $items {
+ lappend result [lindex $file 0]
+ }
+ return $result
+ }
+ }
+
+ ## Get unsorted list of subdirectories in the given directory
+ # @parm String dir - Directory
+ # @return List - List of relative URLs
+ proc get_dirs_simple {dir} {
+ # Search for directories
+ set result [list]
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ set result [glob -nocomplain -tails -directory $dir -types d *]
+ }
+
+ # Include hidden directories
+ if {${::KIFSD::FSD::config(show_hidden_files)}} {
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ set result [concat $result [glob -nocomplain -tails -directory $dir -types {d hidden} *]]
+ }
+
+ # Filter "." and ".."
+ set foo_idx [lsearch $result {..}]
+ if {$foo_idx != -1} {
+ set result [lreplace $result $foo_idx $foo_idx]
+ set foo_idx [lsearch $result {.}]
+ if {$foo_idx != -1} {
+ set result [lreplace $result $foo_idx $foo_idx]
+ }
+ }
+ }
+
+ return $result
+ }
+
+ ## Get unsorted list of subdirectories in the given directory
+ # @parm String dir - Directory
+ # @return List - {{relative_URL mtime size_in_B} ... }
+ proc get_dirs_extended {dir} {
+ set result {}
+
+ # Search for directories
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ foreach file [glob -nocomplain -tails -directory $dir -types d *] {
+ lappend result [list $file [file mtime [file join $dir $file]] 0]
+ }
+ }
+
+ # Include hidden directories
+ if {${::KIFSD::FSD::config(show_hidden_files)}} {
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ foreach file [glob -nocomplain -tails -directory $dir -types {d hidden} *] {
+ # Filter "." and ".."
+ if {$file == {.} || $file == {..}} {
+ continue
+ }
+ # Translate to full URL
+ lappend result [list $file [file mtime [file join $dir $file]] 0]
+ }
+ }
+ }
+
+ return $result
+ }
+
+ ## Get unsorted list of files in the given directory matching the given GLOB
+ # @parm String dir - Directory
+ # @parm GLOB mask - Glob expression
+ # @return List - List of relative URLs
+ proc get_files_simple {dir mask} {
+ set result [list]
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ set result [glob -nocomplain -tails -directory $dir -types f $mask]
+ }
+ if {${::KIFSD::FSD::config(show_hidden_files)}} {
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ set result [concat $result \
+ [glob -nocomplain -tails -directory $dir -types {f hidden} $mask]]
+ }
+ }
+ return $result
+ }
+
+ ## Get unsorted list of files in the given directory matching the given GLOB
+ # @parm String dir - Directory
+ # @parm GLOB mask - Glob expression
+ # @return List - {{relative_URL mtime size_in_B} ... }
+ proc get_files_extended {dir mask} {
+ set result {}
+
+ # Search for files matching the given GLOB
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ foreach file [glob -nocomplain -tails -directory $dir -types f $mask] {
+ if {[catch {
+ lappend result [list \
+ $file \
+ [file mtime [file join $dir $file]] \
+ [file size [file join $dir $file]] \
+ ]
+ }]} then {
+ lappend result [list $file 0 0]
+ }
+ }
+ }
+
+ # Include hidden files
+ if {${::KIFSD::FSD::config(show_hidden_files)}} {
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ foreach file [glob -nocomplain -tails -directory $dir -types {f hidden} $mask] {
+ if {[catch {
+ lappend result [list \
+ $file \
+ [file mtime [file join $dir $file]] \
+ [file size [file join $dir $file]] \
+ ]
+ }]} then {
+ lappend result [list $file 0 0]
+ }
+ }
+ }
+ }
+ return $result
+ }
+
+ ## Get list of items to load to directories ListBox
+ # @parm String dir - Source directory
+ # @parm Bool no_detail=0 - No details
+ # @return List - {text text ...}
+ proc dir_cmd {dir {no_detail 0}} {
+ # Normalize directory and determinate its parent
+ set dir [file normalize $dir]
+ if {$dir != {/}} {
+ set parent {..}
+ } else {
+ set parent {}
+ }
+
+
+ if {${::KIFSD::FSD::config(sorting)} == {name}} {
+ set result [sort_items [get_dirs_simple $dir]]
+ } else {
+ set result [sort_items [get_dirs_extended $dir]]
+ }
+
+ if {!$no_detail && ${::KIFSD::FSD::config(detailed_view)}} {
+ return [concat $parent [add_details $result $dir]]
+ } else {
+ return [concat $parent $result]
+ }
+ }
+
+ ## Get list of items to load to files ListBox
+ # @parm String dir - Source directory
+ # @parm GLOB mask - GLOB expression which must match each returned file
+ # @parm Bool no_detail=0 - Detailed view
+ # @return List - {text text ...}
+ proc file_cmd {dir mask {no_detail 0}} {
+ if {${::KIFSD::FSD::config(sorting)} == {name}} {
+ set result [sort_items [get_files_simple $dir $mask]]
+ } else {
+ set result [sort_items [get_files_extended $dir $mask]]
+ }
+ if {!$no_detail && ${::KIFSD::FSD::config(detailed_view)}} {
+ return [add_details $result $dir]
+ } else {
+ return $result
+ }
+ }
+
+ ## Adjust list of files/directories returned by proc. file_cmd to
+ #+ format required to display in detailed view mode
+ # @parm List filelist - List returned by procedure file_cmd
+ # @parm String dir - Directory
+ # @return List - {{text text text ... } ... }
+ proc add_details {filelist dir} {
+ set result {}
+ foreach filename $filelist {
+ set line $filename
+ set fullfilename [file join $dir $filename]
+ if {[string length $line] > 31} {
+ set line [string range $line 0 27]
+ append line {...}
+ }
+ if {[catch {
+ append line [string repeat { } [expr {35 - [string length $line]}]]
+ set size [file size $fullfilename]
+ if {$size < 1024} {
+ append size { B}
+ } elseif {$size < 1048576} {
+ set size [expr {($size * 10) / 1024}]
+ if {$size > 1023} {
+ set size [expr {$size / 10}]
+ } else {
+ set size [string range $size 0 {end-1}].[string range $size end end]
+ }
+ append size { kB}
+ } elseif {$size < 1073741824} {
+ set size [expr {($size * 10) / 1048576}]
+ if {$size > 1023} {
+ set size [expr {$size / 10}]
+ } else {
+ set size [string range $size 0 {end-1}].[string range $size end end]
+ }
+ append size { MB}
+ } elseif {$size < 1099511627776} {
+ set size [expr {($size * 10) / 1073741824}]
+ if {$size > 1023} {
+ set size [expr {$size / 10}]
+ } else {
+ set size [string range $size 0 {end-1}].[string range $size end end]
+ }
+ append size { GB}
+ } else {
+ set size {>1TB}
+ }
+ }]} then {
+ append line { - ---- -------- -----}
+ } else {
+ if {!$::MICROSOFT_WINDOWS} {
+ append line [string repeat { } [expr {8 - [string length $size]}]] $size " " \
+ [string range [lindex [file attributes $fullfilename] 5] {end-3} end] " " \
+ [clock format [file mtime $fullfilename] -format {%D %R}]
+ } else {
+ append line [string repeat { } [expr {8 - [string length $size]}]] $size " " \
+ [clock format [file mtime $fullfilename] -format {%D %R}]
+ }
+ }
+ lappend result [list $line $filename]
+ }
+ return $result
+ }
+
+ ## Get list of items to load to files ListBox (mode "Separate folders" OFF)
+ # @parm String dir - Source directory
+ # @parm GLOB mask - GLOB expression which must match each returned file
+ # @return List - {text text ...}
+ proc dir_file_cmd {dir mask} {
+ set dir [file normalize $dir]
+ set result {}
+
+ # Determinate list of directories
+ if {${::KIFSD::FSD::config(sorting)} == {name}} {
+ set result [concat [get_dirs_simple $dir] [get_files_simple $dir $mask]]
+ } else {
+ set result [concat [get_dirs_extended $dir] [get_files_extended $dir $mask]]
+ }
+ if {$dir != {/}} {
+ set parent [list [list {..} {u}]]
+ } else {
+ set parent {}
+ }
+ set tmp_result {}
+
+ # Determinate list of files
+ if {${::KIFSD::FSD::config(detailed_view)}} {
+ foreach item [sort_items $result] {
+ if {![file exists [file join $dir $item]]} {continue}
+ if {[file isdirectory [file join $dir $item]]} {
+ lappend tmp_result [concat [add_details [list $item] $dir] d]
+ } else {
+ lappend tmp_result [concat [add_details [list $item] $dir] f]
+ }
+ }
+ } else {
+ foreach item [sort_items $result] {
+ if {![file exists [file join $dir $item]]} {continue}
+ if {[file isdirectory [file join $dir $item]]} {
+ lappend tmp_result [list $item d]
+ } else {
+ lappend tmp_result [list $item f]
+ }
+ }
+ }
+ return [concat $parent $tmp_result]
+ }
+
+ ## Get configuration list for procedure load_config_array
+ # @return List - (List which specifies bookmarks, settings and such things)
+ proc get_config_array {} {
+ return [regsub -all "\n" [array get ::KIFSD::FSD::config] { }]
+ }
+
+ ## Load configuration list returned by procedure get_config_array
+ # @parm List config - (List which specifies bookmarks, settings and such things)
+ # @return void
+ proc load_config_array {config} {
+ if {$config == {}} {
+ return
+ }
+
+ if {[catch {
+ array set ::KIFSD::FSD::config $config
+ }]} then {
+ puts stderr "KI File Selection Dialog: Unable to load the given configuration string -- using default"
+ return 0
+ } else {
+ return 1
+ }
+ }
+
+ ## Get descriptor of dialog window
+ # @return Widget - Dialog window
+ public method get_window_name {} {
+ return $win
+ }
+
+ ## Determinate path to the "Desktop" folder.
+ # @return String - The path, e.g. "~/Arbeitsfläche" in case of German Ubuntu.
+ proc get_desktop_dir {} {
+ if {![catch {
+ set f [open "~/.config/user-dirs.dirs" "r"]
+ }]} then {
+ while {![eof $f]} {
+ set l [gets $f]
+ if {[string first "XDG_DESKTOP_DIR=" $l] != -1} {
+ if {[regexp {"[^\"]+"} $l d]} {
+ set d [string range $d 1 end-1]
+ regsub {\$HOME} $d {~} d
+ return $d
+ }
+ }
+ }
+ close $f
+ }
+ return "~/Desktop"
+ }
+}
+
+## Text variables for dialog "Edit entry in Quick access bar"
+set KIFSD::FSD::qa_panel_dialog_url_entry {} ;# Entry URL
+set KIFSD::FSD::qa_panel_dialog_name_entry {} ;# Entry name
+set KIFSD::FSD::qa_panel_dialog_icon {} ;# Icon number [0;3]
+
+## Dialog configuration array (these values are daults)
+ # Invalid configuration list may cause program error !
+array set KIFSD::FSD::config {
+ win_geometry {720x380}
+ detailed_view 0
+ separate_folders 1
+ quick_access_panel 1
+ sorting name
+ reverse_sorting 0
+ folders_first 1
+ case_insensitive 1
+ show_hidden_files 0
+ right_PW_size 200
+ main_PW_size 180
+ bookmarks {}
+}
+
+if {$::MICROSOFT_WINDOWS} {
+ set KIFSD::FSD::config(quick_access_bar_data) [subst {
+ {0 {System Drive ${::env(SystemDrive)}} {${::env(SystemDrive)}}}
+ {1 {Documents and Settings} {${::env(USERPROFILE)}}}
+ }]
+} else {
+ set KIFSD::FSD::config(quick_access_bar_data) [subst {
+ {0 {/} {/}}
+ {0 {Removable media} {/media}}
+ {1 {Home} {~}}
+ {2 {Desktop} {[KIFSD::FSD::get_desktop_dir]}}
+ }]
+}
+
+# >>> File inclusion guard
+}
+# <<< File inclusion guard