diff options
Diffstat (limited to 'lib/dialogues/fsd.tcl')
-rw-r--r-- | lib/dialogues/fsd.tcl | 2871 |
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 |