diff options
author | Andrej Shadura <andrewsh@debian.org> | 2018-05-08 15:59:29 +0200 |
---|---|---|
committer | Andrej Shadura <andrewsh@debian.org> | 2018-05-08 15:59:29 +0200 |
commit | 5b8466f7fae0e071c0f4eda13051c93313910028 (patch) | |
tree | 7061957f770e5e245ba00666dad912a2d44e7fdc /lib/leftpanel |
Import Upstream version 1.3.7
Diffstat (limited to 'lib/leftpanel')
-rwxr-xr-x | lib/leftpanel/filelist.tcl | 4824 | ||||
-rwxr-xr-x | lib/leftpanel/fsbrowser.tcl | 1164 | ||||
-rwxr-xr-x | lib/leftpanel/sfrwatches.tcl | 620 |
3 files changed, 6608 insertions, 0 deletions
diff --git a/lib/leftpanel/filelist.tcl b/lib/leftpanel/filelist.tcl new file mode 100755 index 0000000..c5f5c14 --- /dev/null +++ b/lib/leftpanel/filelist.tcl @@ -0,0 +1,4824 @@ +#!/usr/bin/tclsh +# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net ) + +############################################################################ +# Copyright (C) 2007-2009 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. # +############################################################################ + +# -------------------------------------------------------------------------- +# DESCRIPTION +# Provides: +# - List of opened files +# - List of project files +# - Filesystem browser +# - Management of opened files, project files and code editors +# -------------------------------------------------------------------------- + +# Import nesesary sources +source "${::LIB_DIRNAME}/leftpanel/fsbrowser.tcl" ;# File system browser +source "${::LIB_DIRNAME}/leftpanel/sfrwatches.tcl" ;# SRF Watches + +class FileList { + # Inherit content of some other clases + inherit RightPanel SFRWatches FSBrowser + + ## COMMON + # String: Textvariable for dialog "Open with ..." + common open_with ${::CONFIG(OPEN_WITH_DLG)} + common open_with_cnfr 0 ;# Bool: Confirm dialog "Open with ..." + common count 0 ;# Instances counter + common file_indexes {} ;# List of line indexes (auxiliary variable for opening multiple files) + common ac_index_in_fl ;# Index of actual editor filelist + common default_encoding {utf-8} ;# Default encoding + common default_eol {lf} ;# Default EOL + common bookmark 0 ;# Auxiliary variable for popup menu for Icon Borders + common pmenu_cline 0 ;# Auxiliary variable for popup menu for Icon Borders + # Menu items to disable when entering simulator mode + common freezable_menu_items { + {New} {Close} {Close All} {Open} + } + # Font for opened file in project files list + common opened_file_font [font create \ + -weight bold \ + -slant roman \ + -size -12 \ + -family $::DEFAULT_FIXED_FONT \ + ] + # Font for closed file in project files list + common closed_file_font [font create \ + -weight normal \ + -slant italic \ + -size -12 \ + -family $::DEFAULT_FIXED_FONT \ + ] + # Font for icon borders + common icon_border_font [font create \ + -size -12 \ + -family $::DEFAULT_FIXED_FONT \ + ] + + common filelist {} ;# List of files to open + common open_files_cur_file {} ;# Name of file currently being opened + common open_files_progress 0 ;# True if opening files in progress + common open_files_abort 0 ;# Abort variable for open files ProgressDialog + common filedetails_visible 0 ;# Bool: Is file details window visible + common filedetails_after_ID ;# ID of timeout for show window "file details" + + # Definition of popup menu for listbox of opened files + common OPENEDFILESMENU { + {command {Append to project} {} 0 "filelist_append_to_prj" {add} + "Append this file to the current project"} + {separator} + {command {New} {$edit:new} 0 "editor_new" {filenew} + "Create new file and open its editor"} + {separator} + {command {Open} {$edit:open} 0 "editor_open" {fileopen} + "Open an existing file"} + {separator} + {command {Save} {$edit:save} 0 "editor_save" {filesave} + "Save this file"} + {command {Save as} {$edit:save_as} 5 "editor_save_as" {filesaveas} + "Save this file under different name"} + {command {Save all} {$edit:save_all} 6 "editor_save_all" {save_all} + "Save all file in the list"} + {separator} + {command {Close} {$edit:close} 0 "editor_close 1 {}" {fileclose} + "Close this file"} + {command {Close All} {$edit:close_all} 4 "editor_close_all 1 0" {cancel} + "Close all files in the list"} + {separator} + {command {Bookmark} {} 4 "filelist_o_bookmark" {bookmark_add} + "Add/Remove bookmark for this file"} + {separator} + {command {Move up} {} 5 "filelist_move_up" {1uparrow} + "Move this file up in the list"} + {command {Move down} {} 5 "filelist_move_down" {1downarrow} + "Move this file down in the list"} + {command {Move to top} {} 8 "filelist_move_top" {top} + "Move this file to the top of the list"} + {command {Move to bottom} {} 12 "filelist_move_bottom" {bottom} + "Move this file to the bottom of the list"} + {separator} + {cascade "Sort items by" 11 "" .sort_by false 1 { + {command {Document Name} {} 9 "sort_file_list N 1" {} {}} + {command {File URL} {} 5 "sort_file_list U 1" {} {}} + {command {File Size in B} {} 5 "sort_file_list S 1" {} {}} + }} + {cascade "Open with" 6 "" .open_with false 1 { + {command {gvim} {} 1 "filelist_open_with 1 gvim" {gvim} {}} + {command {emacs} {} 1 "filelist_open_with 1 emacs" {emacs} {}} + {command {kwrite} {} 0 "filelist_open_with 1 kwrite" {kwrite} {}} + {command {gedit} {} 0 "filelist_open_with 1 gedit" {gedit} {}} + {command {other} {} 0 "filelist_open_with 1 other" {exec} {}} + }} + {separator} + {command {Hide the panel} {} 0 "filelist_show_hide" {2leftarrow} + "Hide this panel"} + } + + # Definition of popup menu for notebook with opened files + common FILETABSPUMENU { + {command {Append to project} {} 0 "filelist_append_to_prj" {add} + "Append this file to the current project"} + {separator} + {command {Save} {$edit:save} 0 "editor_save" {filesave} + "Save this file"} + {command {Save as} {$edit:save_as} 5 "editor_save_as" {filesaveas} + "Save this file under different name"} + {command {Save all} {$edit:save_all} 6 "editor_save_all" {save_all} + "Save all file in the list"} + {separator} + {command {Close} {$edit:close} 0 "editor_close 1 {}" {fileclose} + "Close this file"} + {command {Close All} {$edit:close_all} 4 "editor_close_all 1 0" {cancel} + "Close all files in the list"} + {separator} + {command {Bookmark} {} 4 "filelist_o_bookmark" {bookmark_add} + "Add/Remove bookmark for this file"} + {separator} + {cascade "Open with" 6 "" .open_with false 1 { + {command {gvim} {} 1 "filelist_open_with 1 gvim" {gvim} {}} + {command {emacs} {} 1 "filelist_open_with 1 emacs" {emacs} {}} + {command {kwrite} {} 0 "filelist_open_with 1 kwrite" {kwrite} {}} + {command {gedit} {} 0 "filelist_open_with 1 gedit" {gedit} {}} + {command {other} {} 0 "filelist_open_with 1 other" {exec} {}} + }} + } + + # Definition of popup menu for listbox of project files + common PROJECTFILESMENU { + {command {Remove file from the project} {} 0 "filelist_remove_file_from_project" {editdelete} + "Remove this file from the project"} + {command {Close file} {$edit:close} 0 "filelist_project_file_close" + {fileclose} "Close this file"} + {command {Open file} {} 0 "filelist_project_file_open" {fileopen} + "Open this file"} + {separator} + {command {Bookmark} {} 4 "filelist_p_bookmark" {bookmark_add} + "Add/Remove bookmark for this file"} + {separator} + {command {Move up} {} 5 "filelist_prj_move_up" {1uparrow} + "Move this item up"} + {command {Move down} {} 5 "filelist_prj_move_down" {1downarrow} + "Move this item down"} + {command {Move to top} {} 8 "filelist_prj_move_top" {top} + "Move this item to the top of the list"} + {command {Move to bottom} {} 12 "filelist_prj_move_bottom" {bottom} + "Move this item to the bottom of the list"} + {separator} + {cascade "Sort items by" 11 "" .sort_by false 1 { + {command {Document Name} {} 9 "sort_file_list N 0" {} {}} + {command {File URL} {} 5 "sort_file_list U 0" {} {}} + {command {File Size in B} {} 5 "sort_file_list S 0" {} {}} + }} + {cascade "Open with" 6 "" .open_with false 1 { + {command {gvim} {} 1 "filelist_open_with 0 gvim" {gvim} {}} + {command {emacs} {} 1 "filelist_open_with 0 emacs" {emacs} {}} + {command {kwrite} {} 0 "filelist_open_with 0 kwrite" {kwrite} {}} + {command {gedit} {} 0 "filelist_open_with 0 gedit" {gedit} {}} + {command {other} {} 0 "filelist_open_with 0 other" {exec} {}} + }} + {separator} + {command {Hide the panel} {} 0 "filelist_show_hide" {2leftarrow} + "Hide this panel"} + } + + # Definition of popup menu icon border for list of of opened files + common OPENEDFILESIBMENU { + {checkbutton "Bookmark" "" {::FileList::bookmark} 1 0 0 + {opened_files_bookmark ${::FileList::pmenu_cline}}} + } + # Definition of popup menu icon border for list of of project files + common PROJECTFILESIBMENU { + {checkbutton "Bookmark" "" {::FileList::bookmark} 1 0 0 + {project_files_bookmark ${::FileList::pmenu_cline}}} + } + + ## PUBLIC + public variable actualEditor ;# Object number of currently selected editor + public variable actualEditor2 -2 ;# Object number of currently selected editor in the second view + public variable ProjectDir ;# Reference to directory of actual project + public variable editors {} ;# list of editor objects + public variable iconBorder $::CONFIG(ICON_BORDER) ;# Bool: display Icon border + public variable lineNumbers $::CONFIG(LINE_NUMBERS) ;# Bool: display Line numbers + + ## PRIVATE + # Bool: procedure switchfile will not forget its frame (cleared by procedure switchfile) + private variable do_not_forget_editor 0 + private variable editor_close_in_progress 0 ;# Bool: Indicates than procedure editor_close is in progress + private variable pwin_orient {} ;# String multiview orientaion (horizontal or vertical) + private variable multiview_sash_pos 0 ;# Int: position of panedwindow sash for multiview + private variable selectedView 0 ;# Int: 0 == left/top view; 1 == right/bottom view + private variable splitted 0 ;# Bool: Editor is splitted + private variable main_frame ;# Widget: frame containing $multiview_paned_win or $pagesManager + private variable untitled_num -1 ;# Number of untitled entries in file list + private variable leftPanel ;# ID of the left panel + private variable notebook ;# ID of left panel Notebook + private variable parent ;# ID of parent container widget + private variable button_bar ;# ID of show/hide button (for listbox of files) + private variable lastItem ;# Descriptor of the last selected file + private variable obj_idx ;# Index of This object + private variable pagesManager ;# ID of frame for packing editors + private variable pagesManager2 ;# ID of frame for packing editors in second view + private variable multiview_paned_win ;# ID of paned window for $pagesManager and $pagesManager2 + private variable listbox_opened_files ;# ID of ListBox of currently opened files + private variable listbox_opened_files_bm ;# ID of icon border for opened files + private variable opened_files_bookmarks {} ;# List: Bookmarks for opened files + private variable IB_o_menu ;# ID of popup menu for 'listbox_opened_files_bm' + private variable listbox_project_files ;# ID of ListBox of currently opened files + private variable listbox_project_files_bm ;# ID of icon border for project files + private variable project_files_bookmarks {} ;# List: Bookmarks for project files + private variable IB_p_menu ;# ID of popup menu for 'listbox_project_files_bm' + private variable last_sash ;# Last position of the paned window sash + private variable next_editor_button ;# ID of button "Next editor" -- tab "Opened files" + private variable prev_editor_button ;# ID of button "Prev editor" -- tab "Opened files" + private variable opened_files_scrollbar ;# ID of scrollbar for opened files visible + private variable o_scrollbar_visible 0 ;# Bool: Scrollbar for opened files visible + private variable project_files_scrollbar ;# ID of scrollbar for project files visible + private variable p_scrollbar_visible 0 ;# Bool: Scrollbar for project files visible + private variable opened_files_menu ;# ID of the popup menu asociated with list of opened files + private variable project_files_menu ;# ID of the popup menu asociated with list of project files + private variable filetabs_pu_menu + private variable frozen 0 ;# Bool: Simulator mode flag + private variable unsaved ;# List of editor objects with positive flag modified + private variable listbox_opened_files_frame ;# Frame for list of opened files + private variable listbox_project_files_frame ;# Frame for list of project files + private variable fs_browser_frame ;# Frame for file system browser + private variable sfr_watches_frame ;# Frame for SFR watches + private variable opened_files_buttonBox ;# ID of buttonBox in list of opened files + private variable project_files_buttonBox ;# ID of buttonBox in list of project files + private variable listbox_opened_files_top_frame ;# Identifier of button frame above listbox of files + + private variable opened_search_entry ;# ID of search entry for opened files + private variable opened_search_clear_button ;# ID of button "Clear" on search panel -- opened files + private variable opened_files_highlighted_item {} ;# ID of currently highlighted item in opened files + private variable opened_files_hg_item_fg_clr {} ;# Fg. color of currently highlighted item in opened files + private variable project_search_entry ;# ID of search entry for project files + private variable project_search_clear_button ;# ID of button "Clear" on search panel -- project files + private variable project_files_highlighted_item {} ;# ID of currently highlighted item in project files + private variable project_files_hg_item_fg_clr {} ;# Fg. color of currently highlighted item in project files + private variable item_menu_invoked 0 ;# Bool: Item menu request + private variable editor_command_line_on 0 ;# Bool: Editor command line visible + + private variable simulator_editor 0 ;# Int: Current file number (for simulator) + private variable file_switching_enabled 1 ;# Bool: Automatic file switching enabled + private variable simulator_editor_obj ;# Object: Code editor used by simulator + + private variable active_page $::CONFIG(LEFT_PANEL_ACTIVE_PAGE) ;# Active page in the left panel + private variable PanelVisible $::CONFIG(LEFT_PANEL) ;# Bool: panel visible + private variable PanelSize $::CONFIG(LEFT_PANEL_SIZE) ;# Panel width (in pixels) + + private variable editor_to_freeze_obj ;# Object: Editor to freeze after simulator startup + private variable filetabs_frm ;# Widget: Frame contaning the tab bar + private variable filetabs_nb ;# Widget: Tab bar's notebook widget + + ## PROTECTED + protected variable file_count 0 ;# counter of opened files + protected variable editor_wdgs {} ;# list of editor widgets + protected variable file_descriptors {} ;# list of descriptors of opened files + protected variable file_eol {} ;# List of EOLs for opened editors + protected variable file_encoding {} ;# List of encodings for opened editors + protected variable file_ro_mode {} ;# List of read only flags for opened editors + protected variable file_sh {} ;# List of syntax highlight id's for opened editors + + ## object constructor + constructor {} { + # increment instance counter + incr count + set obj_idx $count + } + + ## Object destructor + destructor { + # Destroy editors + foreach editor $editors { + delete object $editor + } + # Unregister status bar tips for popup menus + menu_Sbar_remove $opened_files_menu + menu_Sbar_remove $project_files_menu + menu_Sbar_remove $filetabs_pu_menu + } + + ## Initialize GUI components + # @parm String parentPane - Identifier of pane window in which it shoul be packed + # @parm String projectDir - Directory of current project + # @parm List filelist - List of files to open (full filenames including path) + # @parm Bool editor_sw_lock - Enable aoutomatic file switching during simulation + # @return void + public method initiate_FileList {parentPane projectDir FileList editor_sw_lock} { + + # Object variables + set parent $parentPane ;# ID of parent container widget + set ProjectDir $projectDir ;# Reference to directory of actual project + set file_switching_enabled $editor_sw_lock + + # Class variables + set filelist $FileList ;# List of files to open + + # Create notebook frame + set leftPanel [frame $parentPane.frm_FileList_leftPanel] + # Create notebook + set notebook [NoteBook $leftPanel.nb_FileList \ + -side top -arcradius 4 -bg {#EEEEEE} \ + ] + # Create tab "Hide" + $notebook insert end "button_SH" -image ::ICONS::16::2leftarrow \ + -raisecmd "$this filelist_show_hide" \ + -helptext [mc "Hide this panel"] + # Create tab for list of opened files + set listbox_opened_files_frame [$notebook insert end "opened_files" \ + -image ::ICONS::16::fileopen \ + -raisecmd "$this Left_panel_set_active_page opened_files" \ + -helptext [mc "Opened files"] \ + ] + # Create tab for list of project files + set listbox_project_files_frame [$notebook insert end "project_files" \ + -image ::ICONS::16::project_open \ + -raisecmd "$this Left_panel_set_active_page project_files" \ + -helptext [mc "Files in the project"] \ + ] + # Create tab for file system browser + set fs_browser_frame [$notebook insert end "fs_browser" \ + -image ::ICONS::16::exec \ + -raisecmd "$this Left_panel_set_active_page fs_browser" \ + -helptext [mc "Filesystem browser"] \ + -createcmd [list $this CreateFSBrowserGUI] \ + ] + # Create tab for SFR watches + set sfr_watches_frame [$notebook insert end "sfr_watches" \ + -image ::ICONS::16::kcmmemory \ + -raisecmd "$this Left_panel_set_active_page sfr_watches" \ + -helptext [mc "List of SFR's"] \ + -createcmd [list $this CreateSFRWatchesGUI] \ + ] + + # Prepare panel componenets but do not create GUI elements + PrepareFSBrowser $fs_browser_frame + PrepareSFRWatches $sfr_watches_frame + + + # Register notebook status bar tips + notebook_Sbar_set {filelist} [list \ + button_SH [mc "Hide the panel"] \ + opened_files [mc "Opended files"] \ + project_files [mc "Files of the current project"] \ + fs_browser [mc "Filesystem browser"] \ + sfr_watches [mc "Special Function Registers"] \ + ] + $notebook bindtabs <Enter> "notebook_Sbar filelist" + $notebook bindtabs <Leave> "Sbar {} ;#" + + # Create listbox of opened files + set lsbox_frame [frame $listbox_opened_files_frame.lsbox_frame] + set listbox_opened_files_bm [text $lsbox_frame.icon_border \ + -font $icon_border_font \ + -cursor left_ptr \ + -width 2 \ + -bd 0 \ + -pady 1 \ + -highlightthickness 0 \ + -bg {#DDDDDD} \ + -exportselection 0 \ + -takefocus 0 \ + -cursor hand1 \ + ] + $listbox_opened_files_bm tag configure center -justify center + $listbox_opened_files_bm delete 1.0 end + setStatusTip -widget $listbox_opened_files_bm \ + -text [mc "Bookmarks for opened files"] + set listbox_opened_files [ListBox $lsbox_frame.listbox_opened_files \ + -selectmode single -selectfill 0 -bg white \ + -selectbackground white -highlightcolor {#BBBBFF} \ + -selectforeground {#0000FF} -bd 1 \ + -highlightthickness 0 -deltay 15 -padx 14 \ + -yscrollcommand "$this filelist_o_scrollbar_set" \ + ] + setStatusTip -widget $listbox_opened_files \ + -text [mc "List of opened files"] + set opened_files_scrollbar [ttk::scrollbar \ + $lsbox_frame.scrollbar \ + -orient vertical \ + -command "$this filelist_o_scroll" \ + ] + + # Create popup menu for icon border + set IB_o_menu $listbox_opened_files_bm.ib_o_menu + menuFactory $OPENEDFILESIBMENU $IB_o_menu 0 "$this " 0 {} + + # Create bottom frame + set listbox_opened_files_bottom_frame [frame $listbox_opened_files_frame.bottom_frame] + set listbox_opened_files_bottom0_frame [frame $listbox_opened_files_bottom_frame.top] + set listbox_opened_files_bottom1_frame [frame $listbox_opened_files_bottom_frame.bottom] + # Create search panel + set opened_search_entry [ttk::entry $listbox_opened_files_bottom0_frame.entry \ + -validatecommand "$this filelist_opened_search %P" \ + -validate all \ + -width 0 \ + ] + DynamicHelp::add $opened_search_entry -text [mc "Search for file"] + setStatusTip -widget $opened_search_entry \ + -text [mc "Search for certain file name in list of opened files"] + pack $opened_search_entry -side left -fill x -expand 1 + set opened_search_clear_button [ttk::button \ + $listbox_opened_files_bottom0_frame.clear_button \ + -command "$opened_search_entry delete 0 end" \ + -image ::ICONS::16::clear_left \ + -state disabled \ + -style Flat.TButton \ + ] + DynamicHelp::add $listbox_opened_files_bottom0_frame.clear_button -text [mc "Clear search entry box"] + setStatusTip -widget $opened_search_clear_button \ + -text [mc "Clear search entry box"] + pack $opened_search_clear_button -side right -after $opened_search_entry + # Create buttons "Previous" and "Next" + set prev_editor_button [ttk::button \ + $listbox_opened_files_bottom1_frame.prev \ + -command {::X::__prev_editor} \ + -image ::ICONS::16::1leftarrow \ + -style Flat.TButton \ + ] + DynamicHelp::add $listbox_opened_files_bottom1_frame.prev \ + -text [mc "Previous editor"] + pack $prev_editor_button -side left + setStatusTip -widget $prev_editor_button \ + -text [mc "Switch to the previous editor"] + set next_editor_button [ttk::button \ + $listbox_opened_files_bottom1_frame.next \ + -command {::X::__next_editor} \ + -image ::ICONS::16::1rightarrow \ + -style Flat.TButton \ + ] + DynamicHelp::add $listbox_opened_files_bottom1_frame.next \ + -text [mc "Next editor"] + pack $next_editor_button -side left + setStatusTip -widget $next_editor_button \ + -text [mc "Switch to the next editor"] + + # Frame for opened files + set listbox_opened_files_top_frame [frame \ + $listbox_opened_files_frame.listbox_opened_files_top_frame] + # Button box for "Opened files" + set opened_files_buttonBox [frame \ + $listbox_opened_files_top_frame.opened_files_buttonBox] + # Pages managers for editor(s), etc. + set main_frame [frame $parentPane.main_frame] + + # Create filetabs notebook + set filetabs_frm [frame $main_frame.filetabs_frm -height 16] + pack [ttk::button $filetabs_frm.add_button \ + -image ::ICONS::16::filenew \ + -command {::X::__new} \ + -style Flat.TButton \ + ] -side left + set filetabs_nb [NoteBook $filetabs_frm.filetabs_nb \ + -side top -arcradius 4 -bg {#EEEEEE} \ + -font [font create -family {Helvetica} -size -12] \ + ] + pack configure $filetabs_nb.c -fill x -expand 0 + pack $filetabs_nb -fill x -anchor sw -side left -expand 1 + $filetabs_nb bindtabs <Enter> "$this file_details_win_create_from_ftnb" + $filetabs_nb bindtabs <Leave> "$this file_details_win_hide" + $filetabs_nb bindtabs <Motion> "$this file_details_win_move" + $filetabs_nb bindtabs <ButtonRelease-3> "$this filetabs_nb_popup_menu %X %Y" + pack [ttk::button $filetabs_frm.close_button \ + -image ::ICONS::16::fileclose \ + -command {::X::__close} \ + -style Flat.TButton \ + ] -side right + + set multiview_paned_win [panedwindow \ + $main_frame.multiview_paned_win \ + -sashwidth 2 \ + -showhandle 0 \ + -opaqueresize 1 \ + -sashrelief flat \ + ] + set pagesManager [frame $main_frame.pagesManager] + set pagesManager2 [frame $main_frame.pagesManager2] + + # Create icon bar for "Opened files" + iconBarFactory $opened_files_buttonBox "$this " \ + [string range $opened_files_buttonBox 1 end] ::ICONS::16:: { + {bookmark "Bookmark" {bookmark_add} {filelist_o_bookmark} + "Add/Remove bookmark"} + {separator} + {up "Move file up" {1uparrow} {filelist_move_up} + "Move selected file up in the list"} + {down "Move file down" {1downarrow} {filelist_move_down} + "Move selected file down in the list"} + {top "Move item to top" {top} {filelist_move_top} + "Move selected file to the top of the list"} + {bottom "Move item to bottom" {bottom} {filelist_move_bottom} + "Move selected file to the bottom of the list"} + } + + # Pack GUI components of tab "Opened files" + pack $opened_files_buttonBox -side left + pack $listbox_opened_files_top_frame -side top -anchor w + pack $listbox_opened_files_bottom1_frame -side top + pack $listbox_opened_files_bottom0_frame -side top -fill x + pack $listbox_opened_files_bottom_frame -side bottom -fill x -pady 3 + pack $lsbox_frame -side top -anchor nw -fill both -expand 1 + pack $listbox_opened_files -side right -fill both -expand 1 + pack $listbox_opened_files_bm -before $listbox_opened_files -fill y -side left + + # Create list of project files + set ls_frame [frame $listbox_project_files_frame.ls_frame] + set listbox_project_files_bm [text $ls_frame.icon_border \ + -font $icon_border_font \ + -cursor left_ptr \ + -width 2 \ + -bd 0 \ + -pady 1 \ + -highlightthickness 0 \ + -bg {#DDDDDD} \ + -exportselection 0 \ + -takefocus 0 \ + -cursor hand1 \ + ] + $listbox_project_files_bm delete 1.0 end + $listbox_project_files_bm tag configure center -justify center + setStatusTip -widget $listbox_project_files_bm \ + -text [mc "Bookmarks for project files"] + set listbox_project_files [ListBox $ls_frame.listbox_project_files \ + -selectmode single -highlightthickness 0 -bd 1 -padx 0 \ + -selectbackground white -bg white -deltay 15 \ + -selectforeground {#0000FF} -highlightcolor {#BBBBFF} \ + -yscrollcommand "$this filelist_p_scrollbar_set" \ + ] + setStatusTip -widget $listbox_project_files \ + -text [mc "List of project files"] + set project_files_scrollbar [ttk::scrollbar \ + $ls_frame.scrollbar \ + -orient vertical \ + -command "$this filelist_p_scroll" \ + ] + + # Create popup menu for icon border + set IB_p_menu $listbox_project_files.ib_o_menu + menuFactory $PROJECTFILESIBMENU $IB_p_menu 0 "$this " 0 {} + + # Create search panel + set search_panel [frame $listbox_project_files_frame.search_panel] + set project_search_entry [ttk::entry $search_panel.entry \ + -validatecommand "$this filelist_project_search %P" \ + -validate all \ + -width 0 \ + ] + DynamicHelp::add $project_search_entry -text [mc "Search for file"] + setStatusTip -widget $project_search_entry \ + -text [mc "Search for certain file name in list of project files"] + pack $project_search_entry -side left -fill x -expand 1 + set project_search_clear_button [ttk::button \ + $search_panel.clear_button \ + -command "$project_search_entry delete 0 end" \ + -image ::ICONS::16::clear_left \ + -state disabled \ + -style Flat.TButton \ + ] + DynamicHelp::add $search_panel.clear_button \ + -text [mc "Clear search entry box"] + setStatusTip -widget $project_search_clear_button \ + -text [mc "Clear search entry box"] + pack $project_search_clear_button -side right -after $project_search_entry + + # Create header (label and icon bar) for tab "Project files" + set topFrame [frame $listbox_project_files_frame.listbox_project_files_top_frame] + pack [label $topFrame.listbox_project_files_label \ + -text [mc "Project files:"] -anchor w \ + ] -fill x -side top -anchor w -pady 5 + set project_files_buttonBox [frame $topFrame.listbox_project_files_buttonBox] + pack $project_files_buttonBox -side bottom -anchor w -expand 0 + + # Create icon bar for tab "Project files" + iconBarFactory $project_files_buttonBox "$this " \ + [string range $project_files_buttonBox 1 end] ::ICONS::16:: { + {bookmark "Bookmark" {bookmark_add} + {filelist_p_bookmark} + "Add/Remove bookmark"} + {separator} + {open "Open this file" {fileopen} + {filelist_project_file_open} + "Open this file and create its own editor"} + {close "Close this file" {fileclose} + {filelist_project_file_close} + "Close this file and close its editor"} + {separator} + {remove "Remove this file from the project" {editdelete} + {filelist_remove_file_from_project} + "Exclude this file from list of files of this project"} + } + + # Evaluate icon bars button states (tab "Project files") + FileList_project_disEna_buttons + + # Pack frames of tab "Projet files" + pack $topFrame -fill x -side top -anchor w + pack $listbox_project_files -fill both -expand 1 -side right + pack $listbox_project_files_bm -before $listbox_project_files -fill y -side left + pack $search_panel -side bottom -fill x + pack $ls_frame -fill both -expand 1 -side top + + ## Create button bar + set button_bar [frame $leftPanel.button_bar] + # Button "Show" + pack [ttk::button $button_bar.but_show \ + -image ::ICONS::16::2rightarrow \ + -command "$this filelist_show_hide" \ + -style ToolButton.TButton \ + ] + DynamicHelp::add $button_bar.but_show -text [mc "Show the panel"] + setStatusTip -widget $button_bar.but_show \ + -text [mc "Show the panel"] + # Separator + pack [ttk::separator $button_bar.sep -orient horizontal] -fill x -pady 2 + + # Button "Instruction details" + pack [ttk::button $button_bar.but_opened \ + -image ::ICONS::16::fileopen \ + -style ToolButton.TButton \ + -command "$this filelist_show_up opened_files" \ + ] + DynamicHelp::add $button_bar.but_opened -text [mc "Currently opened files"] + setStatusTip -widget $button_bar.but_opened \ + -text [mc "Currently opened files"] + # Button "opened files" + pack [ttk::button $button_bar.but_proj_open \ + -image ::ICONS::16::project_open \ + -style ToolButton.TButton \ + -command "$this filelist_show_up project_files" \ + ] + DynamicHelp::add $button_bar.but_proj_open -text [mc "Files in the current project"] + setStatusTip -widget $button_bar.but_proj_open \ + -text [mc "Files of the current project"] + # Button "Filesystem browser" + pack [ttk::button $button_bar.but_fs_browser \ + -image ::ICONS::16::exec \ + -style ToolButton.TButton \ + -command "$this filelist_show_up fs_browser" \ + ] + DynamicHelp::add $button_bar.but_fs_browser -text [mc "Filesystem browser"] + setStatusTip -widget $button_bar.but_fs_browser \ + -text [mc "Filesystem browser"] + # Button "SFR watches" + pack [ttk::button $button_bar.but_sfr_watches \ + -image ::ICONS::16::kcmmemory \ + -style ToolButton.TButton \ + -command "$this filelist_show_up sfr_watches" \ + ] + DynamicHelp::add $button_bar.but_sfr_watches -text [mc "SFR watches"] + setStatusTip -widget $button_bar.but_sfr_watches \ + -text [mc "SFR watches"] + + # Show the left panel + if {$PanelVisible != 0} { + pack $notebook -expand 1 -fill both + + # Raise active page in the panel notebook + catch { + $notebook raise $active_page + } + } { + set last_sash $PanelSize + pack $button_bar -side top -anchor nw + } + + # Insert left panel and editor pages manager into parent pane window + $parentPane add $leftPanel + $parentPane add $main_frame + + # Set bindings for file lists + $listbox_opened_files bindText <ButtonRelease-3> "$this fileList_opened_filelist_item_popup %X %Y" + $listbox_opened_files bindText <Enter> "$this file_details_win_create O" + $listbox_opened_files bindText <Leave> "$this file_details_win_hide" + $listbox_opened_files bindText <Motion> "$this file_details_win_move" + bind $listbox_opened_files <<ListboxSelect>> "$this switchfile; break" + if {[winfo exists $listbox_opened_files.c]} { + bind $listbox_opened_files.c <Button-5> {%W yview scroll +5 units; break} + bind $listbox_opened_files.c <Button-4> {%W yview scroll -5 units; break} + bind $listbox_opened_files.c <ButtonRelease-3> "$this fileList_opened_filelist_popup %X %Y" + } + + bind $listbox_opened_files_bm <<Selection>> "false_selection $listbox_opened_files_bm" + bind $listbox_opened_files_bm <Button-1> "$this filelist_opened_bookmark_xy %x %y" + bind $listbox_opened_files_bm <ButtonRelease-3> "$this filelist_opened_bm_popup_menu %X %Y %x %y" + bindtags $listbox_opened_files_bm $listbox_opened_files_bm + + $listbox_project_files bindText <ButtonRelease-3> "$this fileList_project_filelist_item_popup %X %Y" + $listbox_project_files bindText <Double-Button-1> "$this filelist_project_file_open" + $listbox_project_files bindText <Enter> "$this file_details_win_create P" + $listbox_project_files bindText <Leave> "$this file_details_win_hide" + $listbox_project_files bindText <Motion> "$this file_details_win_move" + bind $listbox_project_files <<ListboxSelect>> "$this project_files_listbox_select" + if {[winfo exists $listbox_project_files.c]} { + bind $listbox_project_files.c <Button-5> {%W yview scroll +5 units; break} + bind $listbox_project_files.c <Button-4> {%W yview scroll -5 units; break} + bind $listbox_project_files.c <ButtonRelease-3> "$this fileList_project_filelist_popup %X %Y" + } + + bind $listbox_project_files_bm <<Selection>> "false_selection $listbox_project_files_bm" + bind $listbox_project_files_bm <Button-1> "$this filelist_project_bookmark_xy %x %y" + bind $listbox_project_files_bm <ButtonRelease-3> "$this filelist_project_bm_popup_menu %X %Y %x %y" + bindtags $listbox_project_files_bm $listbox_project_files_bm + + # Create popup menus + set opened_files_menu $listbox_opened_files.opened_files_menu + set project_files_menu $listbox_project_files.project_files_menu + set filetabs_pu_menu $filetabs_nb.filetabs_pu_menu + filelist_makePopupMenu + + # Create Editor object for each file in $filelist and insert it into ListBox of opened files + open_files $filelist + + # Initialize list of opened files + set actualEditor [lindex $filelist {1 0}] + set actualEditor2 [lindex $filelist {1 1}] + set multiview_sash_pos [lindex $filelist {1 2}] + set pwin_orient [lindex $filelist {1 3}] + + ## Validate index of current editor(s) + if { + ![string is digit -strict $actualEditor] + || + ($actualEditor >= [llength $editors]) + || + ($actualEditor < 0) + } then { + set actualEditor $actualEditor2 + set splitted 0 + } + if { + ![string is digit -strict $actualEditor2] + || + ($actualEditor2 >= [llength $editors]) + || + ($actualEditor2 < 0) + || + ($actualEditor2 == $actualEditor) + } then { + set actualEditor2 -1 + set splitted 0 + } else { + set splitted 1 + } + + ## Validate index of current editor in the first view + if { + [string is digit -strict $actualEditor] + && + $actualEditor < [llength $editors] + && + $actualEditor >= 0 + } { ;# Valid value + $listbox_opened_files selection set [lindex [$listbox_opened_files items] $actualEditor] + set actualEditor -1 + switchfile + + } else { ;# Invalid value + set actualEditor -1 + if {![llength $editors]} { + editor_new + } { + $listbox_opened_files selection set [lindex [$listbox_opened_files items] 0] + switchfile + } + } + + # Validate selected view, sash orient and sash position + set selectedView [lindex $filelist {1 4}] + if {![string is bool -strict $selectedView]} { + set selectedView 0 + } + if {$pwin_orient != {horizontal} && $pwin_orient != {vertical}} { + set pwin_orient {horizontal} + } + if {![string is digit -strict $multiview_sash_pos] || $multiview_sash_pos < 0} { + set multiview_sash_pos 0 + } + + # Pack editor pages manager + if {$splitted} { + pack $multiview_paned_win -fill both -expand 1 + $multiview_paned_win configure -orient $pwin_orient + $multiview_paned_win add $pagesManager + $multiview_paned_win add $pagesManager2 -after $pagesManager + + if {$pwin_orient == {vertical}} { + if {!$multiview_sash_pos} { + set multiview_sash_pos [expr {[winfo width $pagesManager] / 2}] + } + set minsize 300 + } { + if {!$multiview_sash_pos} { + set multiview_sash_pos [expr {[winfo height $pagesManager] / 2}] + } + set minsize 80 + } + $multiview_paned_win paneconfigure $pagesManager -minsize $minsize + $multiview_paned_win paneconfigure $pagesManager2 -minsize $minsize + pack [[lindex $editors $actualEditor2] cget -ed_sc_frame] \ + -in $pagesManager2 -fill both -expand 1 + } { + pack $pagesManager -fill both -expand 1 + } + foreach editor $editors { + $editor configure_statusbar_menu !$splitted $splitted {} {} + } + + # Set panel width + update idle + if {$PanelVisible != 0} { + $parent paneconfigure $leftPanel -minsize 155 + $parent configure -sashwidth 2 + $parent sash place 0 $PanelSize 0 + } { + $parent paneconfigure $leftPanel -minsize 0 + $parent configure -sashwidth 0 + $parent sash place 0 25 2 + bind $parent <Button> {break} + } + bind $parent <ButtonRelease-1> "$this left_panel_set_size" + + # Update multiview sash position + if {$splitted} { + update idle + if {$pwin_orient == {vertical}} { + $multiview_paned_win sash place 0 0 $multiview_sash_pos + } { + $multiview_paned_win sash place 0 $multiview_sash_pos 0 + } + } + + show_hide_tab_bar + } + + ## Prepare window file details + # @parm Char for - '0' == ListBox of opened files; 'P' == ListBox of project files + # @parm String item - Item ID + # @return void + public method file_details_win_create {for item} { + set filedetails_visible 0 + + set note {} + + # Determinate full filename + if {$for == {O}} { + if {![$listbox_opened_files exists $item]} { + return + } + set shortname [$listbox_opened_files itemcget $item -text] + set filename [$listbox_opened_files itemcget $item -data] + set index [$listbox_opened_files index $item] + set encoding [lindex $file_encoding $index] + set eol [lindex $file_eol $index] + set read_only [lindex $file_ro_mode $index] + regexp -line -- {^.*$} [$this get_file_notes_data $index] note + } { + if {![$listbox_project_files exists $item]} { + return + } + set shortname [$listbox_project_files itemcget $item -text] + set data [$listbox_project_files itemcget $item -data] + if {[llength $data] < 5} { + set filename [lindex $data 0] + set eol [lindex $data 1] + set encoding [lindex $data 2] + set read_only [lindex $data 3] + } { + set filename "[lindex $data 5][lindex $data 0]" + set eol [lindex $data 8] + set encoding [lindex $data 9] + set read_only [lindex $data 2] + } + } + + # Skip untitled files + if {$filename == {}} {return} + + # Destroy previous window + catch {after cancel $filedetails_after_ID} + catch {destroy ${::FILEDETAILSWIN}} + + # Create window + set ::FILEDETAILSWIN [frame .file_details_win -bg {#AADDFF}] + set file_details_win [frame ${::FILEDETAILSWIN}.frm -bg {#FFFFFF}] + bind ${::FILEDETAILSWIN} <Button-1> "catch {destroy ${::FILEDETAILSWIN}}" + + # Determinate file type and set appropriate icon + set ext [string trimleft [file extension $filename] {.}] + if {$ext == {h}} { + set icon {source_h} + } elseif {$ext == {c}} { + set icon {source_c} + } elseif {$ext == {cxx} || $ext == {cpp} || $ext == {cc}} { + set icon {source_cpp} + } elseif {$ext == {asm}} { + set icon {asm} + } else { + set icon {ascii} + } + + # Create header + set header [frame $file_details_win.header -bg {#AADDFF}] + pack [label $header.header \ + -bg {#AADDFF} -text $shortname \ + -justify left -pady 0 -padx 15 \ + -compound left -anchor w \ + -image ::ICONS::16::$icon \ + ] -side left + if {$read_only == 1} { + pack [label $header.ro_text \ + -bg {#AADDFF} -fg {#FF3333} \ + -text [mc "(read only)"] \ + -justify left -pady 0 \ + ] -side left + } + pack $header -fill x + + # Show error message if the file dosn't exist + if {![file exists $filename]} { + pack [label $file_details_win.message_label \ + -text [mc "File does not exist"] \ + -fg {#FF0000} \ + ] -padx 80 -pady 40 + catch {after cancel $filedetails_after_ID} + set filedetails_after_ID [after 750 " + set ::FileList::filedetails_visible 1 + $this file_details_win_move"] + return + } + + # Determinate informations about the file + set size [file size $filename] ;# Size in B + set mtime [file mtime $filename] ;# Modification time + if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights) + set perms [file attributes $filename] ;# Owner - Group - Permissions + } + + # Adjust the informations aboth the file + set mtime [clock format $mtime -format {%D %R}] + if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights) + set owner "[lindex $perms 1] - [lindex $perms 3]" + set perms [lindex $perms 5] + set perms [string range $perms {end-3} end] + } + if {[enc2name $encoding] != {}} { + if {[string length $encoding] < 8} { + append encoding "\t" + } + append encoding "\t(" [enc2name [string trimright $encoding]] {)} + } + if {$size < 1024} { + append size { B} + } { + set kB [expr {$size / 1024}] + set B [expr {$size % 1024}] + set MB [expr {$kB / 1024}] + set kB [expr {$kB % 1024}] + + set original_size $size + set size {} + if {$MB} { + append size $MB { MB } + } + if {$kB} { + append size $kB { kB } + } + if {$B} { + append size $B { B } + } + append size {(} $original_size { B)} + } + switch -- $eol { + {lf} {set eol "Unix\t\t(LF)"} + {crlf} {set eol "DOS\t\t(CRLF)"} + {cr} {set eol "Macintosh\t(CR)"} + } + + # Create main frame (containing everything except the header) + set main_frame [frame $file_details_win.main_frame -bg {#FFFFFF}] + + # Path + grid [label $main_frame.path_label \ + -text [mc "Path:"] \ + -fg {#0000AA} \ + -anchor w -bg {#FFFFFF} \ + ] -row 0 -column 0 -sticky w -pady 0 + grid [label $main_frame.path_value \ + -text [file dirname $filename] \ + -anchor w -bg {#FFFFFF} \ + ] -row 0 -column 1 -sticky w -pady 0 + + # Size + grid [label $main_frame.size_label \ + -text [mc "Size:"] \ + -fg {#0000AA} \ + -anchor w -pady 0 -bg {#FFFFFF} \ + ] -row 1 -column 0 -sticky w -pady 0 + grid [label $main_frame.size_value \ + -text $size -anchor w -pady 0 -bg {#FFFFFF} \ + ] -row 1 -column 1 -sticky w -pady 0 + + # Modified + grid [label $main_frame.modified_label \ + -text [mc "Modified:"] \ + -fg {#0000AA} \ + -anchor w -pady 0 -bg {#FFFFFF} \ + ] -row 2 -column 0 -sticky w -pady 0 + grid [label $main_frame.modified_value \ + -text $mtime -anchor w -pady 0 -bg {#FFFFFF} \ + ] -row 2 -column 1 -sticky w -pady 0 + + # Owner + if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights) + grid [label $main_frame.owner_label \ + -text [mc "Owner:"] \ + -fg {#0000AA} \ + -anchor w -pady 0 -bg {#FFFFFF} \ + ] -row 3 -column 0 -sticky w -pady 0 + grid [label $main_frame.owner_value \ + -text $owner -anchor w -pady 0 -bg {#FFFFFF} \ + ] -row 3 -column 1 -sticky w -pady 0 + + # Permissions + grid [label $main_frame.perms_label \ + -text [mc "Permissions:"] \ + -fg {#0000AA} -bg {#FFFFFF} \ + -anchor w -pady 0 \ + ] -row 4 -column 0 -sticky w -pady 0 + grid [label $main_frame.perms_value \ + -text $perms -anchor w -pady 0 -bg {#FFFFFF} \ + ] -row 4 -column 1 -sticky w -pady 0 + } + + if {!${::Editor::editor_to_use}} { + # Separator + grid [ttk::separator $main_frame.sep \ + -orient horizontal \ + ] -row 5 -column 0 -columnspan 2 -sticky we -pady 0 + + # Encoding + grid [label $main_frame.enc_label \ + -text [mc "Encoding:"] \ + -fg {#880033} \ + -anchor w -pady 0 -bg {#FFFFFF} \ + ] -row 6 -column 0 -sticky w -pady 0 + grid [label $main_frame.enc_value \ + -text $encoding -anchor w \ + -pady 0 -bg {#FFFFFF} \ + ] -row 6 -column 1 -sticky w -pady 0 + + # EOL + grid [label $main_frame.eol_label \ + -text [mc "EOL:"] -fg {#880033} \ + -anchor w -pady 0 -bg {#FFFFFF} \ + ] -row 7 -column 0 -sticky w -pady 0 + grid [label $main_frame.eol_value \ + -text $eol -anchor w -pady 0 -bg {#FFFFFF} \ + ] -row 7 -column 1 -sticky w -pady 0 + } + + # User note + if {$note != {} && $for == {O}} { + set w_max 350 + set w [font measure ${::Todo::normal_font} $note] + + if {$w > $w_max} { + set note [string range $note 0 [expr {int([string length $note] * $w_max/$w * 0.7)}]] + append note {...} + } + + # Separator + grid [ttk::separator $main_frame.sep1 \ + -orient horizontal \ + ] -row 8 -column 0 -columnspan 2 -sticky we -pady 0 + grid [label $main_frame.notes_value \ + -anchor w -pady 0 -bg {#FFFFFF} \ + -text $note -font ${::Todo::normal_font} \ + -justify left -anchor w -wraplength $w_max \ + ] -row 9 -column 0 -sticky w -pady 0 -columnspan 2 + } + + # Pack main frame + grid columnconfigure $main_frame 0 -minsize 90 + pack $main_frame -fill both -expand 1 -padx 8 -pady 3 + pack $file_details_win -fill both -expand 1 -padx 2 -pady 2 + + # After 750 ms show the window + catch {after cancel $filedetails_after_ID} + set filedetails_after_ID [after 750 " + set ::FileList::filedetails_visible 1 + $this file_details_win_move"] + } + + ## Move window "File details" + # @return void + public method file_details_win_move args { + # Abort if the window isn't visible + if {!$filedetails_visible} {return} + + # Show the window + catch { + place ${::FILEDETAILSWIN} -anchor nw \ + -x [expr {[winfo pointerx .] - [winfo rootx .] + 20}] \ + -y [expr {[winfo pointery .] - [winfo rooty .] + 20}] + update + raise ${::FILEDETAILSWIN} + } + } + + ## Hide window "File details" + # @return void + public method file_details_win_hide args { + set filedetails_visible 0 ;# Bool: Is file details window visible + + # Hide window and cancel timeout + catch {after cancel $filedetails_after_ID} + catch {place forget ${::FILEDETAILSWIN}} + } + + ## Define popup menus + # @return void + public method filelist_makePopupMenu {} { + if {[winfo exists $opened_files_menu]} { + destroy $opened_files_menu + } + if {[winfo exists $project_files_menu]} { + destroy $project_files_menu + } + if {[winfo exists $filetabs_pu_menu]} { + destroy $filetabs_pu_menu + } + + menuFactory $PROJECTFILESMENU $project_files_menu 0 "$this " 0 {} + menuFactory $OPENEDFILESMENU $opened_files_menu 0 "$this " 0 {} + menuFactory $FILETABSPUMENU $filetabs_pu_menu 0 "$this " 0 {} + + foreach program {gvim emacs kwrite gedit} \ + program_name {gvim emacs kwrite gedit} \ + { + if {!$::PROGRAM_AVALIABLE($program)} { + foreach menu [list $project_files_menu $opened_files_menu $filetabs_pu_menu] { + ${menu}.open_with entryconfigure [::mc $program_name] -state disabled + } + } + } + if {${::Editor::editor_to_use}} { + $opened_files_menu entryconfigure [::mc "Save"] -state disabled + $opened_files_menu entryconfigure [::mc "Save as"] -state disabled + $opened_files_menu entryconfigure [::mc "Save all"] -state disabled + + $filetabs_pu_menu entryconfigure [::mc "Save"] -state disabled + $filetabs_pu_menu entryconfigure [::mc "Save as"] -state disabled + $filetabs_pu_menu entryconfigure [::mc "Save all"] -state disabled + } + } + + ## Reload the current file + # @return Bool - result + public method filelist_reload_file {} { + if {$splitted && $selectedView} { + set editor_idx $actualEditor2 + } { + set editor_idx $actualEditor + } + set editor [lindex $editors $editor_idx] + + # Local variables + set fullFileName [$editor cget -fullFileName] ;# Full filename + set filename [$editor cget -filename] ;# Simple filename + + if { + ![file exists $fullFileName] || + [file isdirectory $fullFileName] || + (!$::MICROSOFT_WINDOWS && ![file readable $fullFileName]) + } { + tk_messageBox \ + -title [mc "File not found"] \ + -icon error \ + -type ok \ + -parent . \ + -message [mc "The file selected for reload does not exist any more or it is not readable !"] + set fullFileName {} + } + + if {$fullFileName != {}} { + # Prompt user is the file was modified + if {[$editor cget -modified] != 0} { + set response [tk_messageBox \ + -title [mc "Are you sure ?"] \ + -icon question \ + -type yesno \ + -parent . \ + -message [mc "Reload of the file will change contents of the current editor. Are you sure you want that ?"] \ + ] + if {$response != {yes}} { + Sbar [mc "Reload aborted"] + return 0 + } + } + + set enc [lindex $file_encoding $editor_idx] + set eol [lindex $file_eol $editor_idx] + set rom [lindex $file_ro_mode $editor_idx] + set sh [lindex $file_sh $editor_idx] + + # Get number of the current line + set line [$editor get_current_line_number] + # Clear content of the current editor + if {[$editor cget -ro_mode]} { + [$editor cget -editor] configure -state normal + } + $editor clear_autocompletion_list + [$editor cget -editor] configure -autoseparators 0 + [$editor cget -editor] delete 1.0 end + # Insert content of the file into the editor + set file [open $fullFileName r] + fconfigure $file -encoding $enc + set data {} + if {[regsub -all {[\u0000-\u0008\u000B-\u000C\u000E-\u001F\u007F-\u009F]} [read $file] {} data]} { + tk_messageBox -parent . \ + -type ok -icon warning \ + -title [mc "Binary File Opened - MCU 8015 IDE"] \ + -message [mc "The file %s is binary, saving it will result corrupted file." $fullFileName] + } + [$editor cget -editor] insert end [regsub -all {\r\n?} $data "\n"] + if {[$editor cget -ro_mode]} { + [$editor cget -editor] configure -state disabled + } + close $file + $editor goto $line + [$editor cget -editor] edit separator + [$editor cget -editor] configure -autoseparators 1 + + # Set EOL and Encoding in ListBox of project files + foreach item [$listbox_project_files items] { + if {[$listbox_project_files itemcget $item -text] != $filename} { + continue + } + set data [$listbox_project_files itemcget $item -data] + if {[llength $data] > 5} {continue} + if {[lindex $data 0] != $fullFileName} {continue} + lset data 1 $eol + lset data 2 $enc + lset data 3 $rom + $listbox_project_files itemconfigure $item -data $data + } + } + + # Reset status modified + [$editor cget -editor] edit modified 0 + $editor recalc_status_modified 0 + # Restore syntax highlight + rightPanel_clear_all_bookmarks + rightPanel_clear_all_breakpoints + rightPanel_clear_symbol_list + $editor parseAll + + # Successful + return 1 + } + + ## Highlight all loaded source codes, import breakpoints and bookmarks etc. + # This function finalizes project initialization + # @return void + public method filelist_global_highlight {} { + # Class variables + set filelist [lreplace $filelist 0 1] ;# List of files to open (special format) + + # Skip empty/invalid filelist + if {[lindex $filelist $actualEditor] == {}} { + rightPanel_enable + return + } + + # Local variables + set ac $actualEditor ;# Number of actual editor + # Number of current line in the current editor + set ac_line [lindex $filelist [list $ac_index_in_fl 6]] + + # Take care of the current editor + rightPanel_switch_editor_vars $ac + $this todo_switch_editor_vars $ac + [lindex $editors $ac] import_line_markers_data \ + [lindex $filelist [list $ac_index_in_fl 9]] \ + [lindex $filelist [list $ac_index_in_fl 10]] + [lindex $editors $ac] goto $ac_line + + # Import bookmarks and breakpoints into all editors except the current one + set idx -1 + set lines {} + foreach record $filelist { + # Skip closed files + if {[lindex $record 1] != {yes}} {continue} + + # Detrminate file index + incr idx + set i [lindex $file_indexes $idx] + if {$i == {}} { + continue + } + + # Skip current editor + if {$i == $ac} { + incr i + lappend lines $ac_line + continue + } + # Local variables + set editor [lindex $editors $i] ;# Reference to target editor object + set line [lindex $record 6] ;# Current line + + # Adjust right panel + set actualEditor $i + rightPanel_switch_editor_vars $i + $this todo_switch_editor_vars $i + # Import bookmarks and breakpoints into editor + $editor import_line_markers_data \ + [lindex $record 9] \ + [lindex $record 10] + $editor goto $line + lappend lines $line + } + + # Finalize + set filelist {} + set actualEditor $ac + + # Adjust Right panel + rightPanel_enable + set i 0 + foreach line $lines { + set editor [lindex $editors $i] + rightPanel_switch_editor_vars $i + $this todo_switch_editor_vars $i + $editor rightPanel_adjust $line + incr i + } + rightPanel_switch_editor $ac + $this todo_switch_editor $ac + if {${::ASMsyntaxHighlight::validation_L1}} { + [lindex $editors $actualEditor] parse_current_line + } { + [lindex $editors $actualEditor] adjust_instruction_details + } + + set file_indexes {} + } + + ## Switch from Normal mode to Simulator mode + # @return void + public method freeze {} { + # Set mode flag + set frozen 1 + set simulator_editor_obj {} + set simulator_editor -1 + # Freeze editor + if {$splitted && $selectedView} { + set editor_to_freeze $actualEditor2 + } { + set editor_to_freeze $actualEditor + } + set idx 0 + foreach editor $editors { + if {$idx == $editor_to_freeze} { + $editor freeze + set editor_to_freeze_obj $editor + } { + $editor disable + } + incr idx + } + FileList_project_disEna_buttons + # Disable some popupmenu items + foreach entry $freezable_menu_items { + $opened_files_menu entryconfigure [::mc $entry] -state disabled + } + $project_files_menu entryconfigure [::mc "Close file"] -state disabled + } + + ## This method should be called immediately after simulator startup + #+ in order to inform editors about the change + # @return void + public method now_frozen {} { + $editor_to_freeze_obj now_frozen + } + + ## Switch from Simulator mode to Normal mode + # @return void + public method thaw {} { + # Set mode flag + set frozen 0 + # Thaw editors + foreach editor $editors { + $editor thaw + } + # Enable switching files + listBox_disEna_buttons \ + [$listbox_opened_files selection get] \ + [lindex $editors $actualEditor] + if {$splitted} { + listBox_disEna_buttons \ + [$listbox_opened_files selection get] \ + [lindex $editors $actualEditor] + } + # Enable some poupmenu items + foreach entry $freezable_menu_items { + $opened_files_menu entryconfigure [::mc $entry] -state normal + } + $project_files_menu entryconfigure [::mc "Close file"] -state normal + + if {$simulator_editor_obj != {}} { + $listbox_opened_files itemconfigure [lindex \ + $file_descriptors [lsearch -ascii -exact \ + $editors $simulator_editor_obj \ + ] \ + ] -fg {#000000} + } + set simulator_editor_obj {} + } + + ## Set variable containing ID of active page + # @parm String pageName - active page + # @return void + public method Left_panel_set_active_page {pageName} { + set active_page $pageName + } + + ## Get mode flag + # @return Bool - current mode (1 == Simulation mode; 0 == Normal mode) + public method is_frozen {} {return $frozen} + + ## Get current panel width + # @return Int - the width + public method getLeftPanelSize {} { + if {$PanelVisible} { + return $PanelSize + } { + return $last_sash + } + } + + ## Set panel width acording to current sash position + # @return void + public method left_panel_set_size {} { + set PanelSize [lindex [$parent sash coord 0] 0] + } + + ## Get ID of active page + # @return String - the active page + public method getLeftPanelActivePage {} {return $active_page} + + ## Get value of panel visibility flag + # @return Bool - the flag (1 == Visible, 2 == Hidden) + public method isLeftPanelVisible {} {return $PanelVisible} + + ## Show/Hide the left panel + # @return Bool - 1 == now displayed; 0 == now hidden + public method filelist_show_hide {} { + # Hide the panel + if {$PanelVisible} { + $parent paneconfigure $leftPanel -minsize 0 + + pack forget $notebook + # Show button bar + pack $button_bar -side top -anchor nw + # Move the paned window sash and remember current position + set last_sash [lindex [$parent sash coord 0] 0] + update idle + $parent sash place 0 25 2 + # Hide the sash + bind $parent <Button> {break} + $parent configure -sashwidth 0 + # done ... + set PanelVisible 0 + return 0 + + # Show the panel + } { + $parent paneconfigure $leftPanel -minsize 155 + + $notebook raise $active_page + # Hide button bar + pack forget $button_bar + # Show the panel + pack $notebook -expand 1 -fill both + # Restore the paned window sash position to the previous state + update idle + $parent sash place 0 $last_sash 0 + # Show the sash + bind $parent <Button> {} + $parent configure -sashwidth 2 + # done ... + set PanelVisible 1 + return 1 + } + } + + ## Change panel active page + # @parm String page - ID of the page to show + # @return void + public method filelist_show_up {page} { + if {!$PanelVisible} filelist_show_hide + $notebook raise $page + } + + ## Move up currently selected item -- Opened files + # @return void + public method filelist_move_up {} { + # Local variables + set item [$listbox_opened_files selection get] ;# Item ID + set index [$listbox_opened_files index $item] ;# Item index + set target [expr {$index - 1}] ;# Target index + + # 1st item cannot be moved up + if {$index == 0} {return} + + # Move item in listbox + $listbox_opened_files move $item $target + # Move item in list of bookmarks and icon border + if {[lindex $opened_files_bookmarks $index] != [lindex $opened_files_bookmarks $target]} { + # Determinate bookmark flag for source and target index + set trg_bm [lindex $opened_files_bookmarks $target] + set idx_bm [lindex $opened_files_bookmarks $index] + # Move item in list of bookmarks + lset opened_files_bookmarks $target [lindex $opened_files_bookmarks $index] + lset opened_files_bookmarks $index $trg_bm + # Move item in icon border + incr target + incr index + $listbox_opened_files_bm delete $index.0 [list $index.0 lineend] + $listbox_opened_files_bm delete $target.0 [list $target.0 lineend] + if {$trg_bm} { + $listbox_opened_files_bm image create $index.0 \ + -image ::ICONS::16::bookmark \ + -align center + } + if {$idx_bm} { + $listbox_opened_files_bm image create $target.0 \ + -image ::ICONS::16::bookmark \ + -align center + } + } + + # Reevaluate button states on icon bar + listBox_disEna_buttons $item [lindex $editors [lsearch $file_descriptors $item]] + } + + ## Move down currently selected item -- Opened files + # @return void + public method filelist_move_down {} { + # Local variables + set item [$listbox_opened_files selection get] ;# Item ID + set index [$listbox_opened_files index $item] ;# Item index + set target [expr {$index + 1}] ;# Target index + + # Last item cannot be moved up + if {[llength [$listbox_opened_files items]] == $index} {return} + + # Move item in listbox + $listbox_opened_files move $item $target + # Move item in list of bookmarks and icon border + if {[lindex $opened_files_bookmarks $index] != [lindex $opened_files_bookmarks $target]} { + # Determinate bookmark flag for source and target index + set trg_bm [lindex $opened_files_bookmarks $target] + set idx_bm [lindex $opened_files_bookmarks $index] + # Move item in list of bookmarks + lset opened_files_bookmarks $target [lindex $opened_files_bookmarks $index] + lset opened_files_bookmarks $index $trg_bm + # Move item in icon border + incr target + incr index + $listbox_opened_files_bm delete $index.0 [list $index.0 lineend] + $listbox_opened_files_bm delete $target.0 [list $target.0 lineend] + if {$trg_bm} { + $listbox_opened_files_bm image create $index.0 \ + -image ::ICONS::16::bookmark \ + -align center + } + if {$idx_bm} { + $listbox_opened_files_bm image create $target.0 \ + -image ::ICONS::16::bookmark \ + -align center + } + } + + # Reevaluate button states on icon bar + listBox_disEna_buttons $item [lindex $editors [lsearch $file_descriptors $item]] + } + + ## Move to top currently selected item -- Opened files + # @return void + public method filelist_move_top {} { + # Local variables + set item [$listbox_opened_files selection get] ;# Item ID + set index [$listbox_opened_files index $item] ;# Item index + + # Move item + $listbox_opened_files move $item 0 + # Move item in list of bookmarks + set bm [lindex $opened_files_bookmarks $index] + set opened_files_bookmarks [lreplace $opened_files_bookmarks $index $index] + set opened_files_bookmarks [linsert $opened_files_bookmarks 0 $bm] + # Move item in icon border + incr index + $listbox_opened_files_bm delete $index.0 $index.0+1l + $listbox_opened_files_bm insert 1.0 "\n" + if {$bm} { + $listbox_opened_files_bm image create 1.0 \ + -image ::ICONS::16::bookmark \ + -align center + } + + # Reevaluate button states on icon bar + listBox_disEna_buttons $item [lindex $editors [lsearch $file_descriptors $item]] + } + + ## Move to bottom currently selected item -- Opened files + # @return void + public method filelist_move_bottom {} { + # Local variables + set item [$listbox_opened_files selection get] ;# Item ID + set index [$listbox_opened_files index $item] ;# Item index + + # Move item in listbox + $listbox_opened_files move $item end + # Move item in list of bookmarks + set bm [lindex $opened_files_bookmarks $index] + set opened_files_bookmarks [lreplace $opened_files_bookmarks $index $index] + lappend opened_files_bookmarks $bm + # Move item in icon border + incr index + set end [llength $opened_files_bookmarks] + $listbox_opened_files_bm delete $index.0 $index.0+1l + $listbox_opened_files_bm insert $end.0 "\n" + if {$bm} { + $listbox_opened_files_bm image create $end.0 \ + -image ::ICONS::16::bookmark \ + -align center + } + + # Reevaluate button states on icon bar + listBox_disEna_buttons $item [lindex $editors [lsearch $file_descriptors $item]] + } + + ## Show up editor asociated with the currently selected item in the file list (opened files) + # @return void + public method switchfile {} { + # Ensure that autocompletion window is closed + ::Editor::close_completion_popup_window_NOW + + # Determinate ID of the selected item + set item [$listbox_opened_files selection get] + set editor_idx [lsearch $file_descriptors $item] + + # Adjust filetabs notebook + set page [lindex [$filetabs_nb pages] $editor_idx] + $filetabs_nb raise $page + $filetabs_nb see $page + + # Conditionaly switch selected view + if {$splitted && $selectedView} { + if {$editor_idx == $actualEditor} { + set selectedView 0 + } + } { + if {$editor_idx == $actualEditor2} { + set selectedView 1 + } + } + + # Show up the coresponding editor + rightPanel_switch_editor_vars $editor_idx + $this todo_switch_editor_vars $editor_idx + # Right/Bottom view selected + if {$splitted && $selectedView} { + if {$editor_idx != $actualEditor2} { + if {!$do_not_forget_editor && $actualEditor2 >= 0} { + set editor [lindex $editors $actualEditor2] + if {$editor != {}} { + pack forget [$editor cget -ed_sc_frame] + } + } + set actualEditor2 $editor_idx + pack [[lindex $editors $actualEditor2] cget -ed_sc_frame] \ + -in $pagesManager2 -fill both -expand 1 + } + set editor [lindex $editors $actualEditor2] + + # Left/Top view selected + } { + if {$editor_idx != $actualEditor} { + if {!$do_not_forget_editor && $actualEditor >= 0} { + set editor [lindex $editors $actualEditor] + if {$editor != {}} { + pack forget [$editor cget -ed_sc_frame] + } + } + set actualEditor $editor_idx + pack [[lindex $editors $actualEditor] cget -ed_sc_frame] \ + -in $pagesManager -fill both -expand 1 + } + set editor [lindex $editors $actualEditor] + } + + set do_not_forget_editor 0 + $opened_search_entry delete 0 end + update idle + editor_procedure {} Configure {} + editor_procedure {} scroll {scroll +0 lines} + editor_procedure {} highlight_visible_area {} + update + rightPanel_switch_page $editor_idx + $this todo_switch_editor $editor_idx + # Set encoding and eol + set ::editor_encoding [lindex $file_encoding $editor_idx] + set ::editor_EOL [lindex $file_eol $editor_idx] + set ::editor_RO_MODE [lindex $file_ro_mode $editor_idx] + set ::editor_SH [lindex $file_sh $editor_idx] + # Adjust command line status + if {$editor_command_line_on} { + $editor cmd_line_force_on + } { + $editor cmd_line_force_off + } + # Adjust tab "Instruction details" on the right panel + if {${::ASMsyntaxHighlight::validation_L1}} { + $editor parse_current_line + } { + $editor adjust_instruction_details + } + # move arrow image + catch {$listbox_opened_files itemconfigure $lastItem -image {}} + $listbox_opened_files itemconfigure $item -image ::ICONS::16::2_rightarrow + set lastItem $item + # Reevaluate button states on left panel icon bar, program title bar and main menu and main toolbar + listBox_disEna_buttons $item $editor + ::X::adjust_title + ::X::adjust_mainmenu_and_toolbar_to_editor \ + ${::editor_RO_MODE} [expr {[$editor get_language] == 1}] + # Focus on the editor + focus -force [$editor cget -editor] + } + + ## Switch to the next editor + # @return void + public method next_editor {} { + if {$frozen} {return} + set index [$listbox_opened_files index [$listbox_opened_files selection get]] + + if {$index >= ([llength $file_descriptors] - 1)} {return} + $listbox_opened_files selection set [$listbox_opened_files item [expr {$index + 1}]] + switchfile + } + + ## Switch to the previous editor + # @return void + public method prev_editor {} { + if {$frozen} {return} + set index [$listbox_opened_files index [$listbox_opened_files selection get]] + if {$index} { + $listbox_opened_files selection set \ + [$listbox_opened_files item [expr {$index - 1}]] + switchfile + } + } + + ## Switch the last file in list of opened files + # @return void + public method switch_to_last {} { + if {$splitted} { + set item [expr {([llength $file_descriptors] - 1)}] + if {$item == $actualEditor || $item == $actualEditor2} { + set item {end-1} + } + } { + set item {end} + } + $listbox_opened_files selection set [lindex $file_descriptors $item] + switchfile + } + + ## Enable/Disable buttons in opened files icon bar and popup menu + # @parm String item - ID of the current item + # @parm Object editor - reference to current editor object + # @return void + private method listBox_disEna_buttons {item editor} { + + # Is the file part of the project ? + if {[getItemNameFromProjectList [$editor cget -fullFileName]] != {}} { + set state disabled + } { + set state normal + } + $opened_files_menu entryconfigure [::mc "Append to project"] -state $state + $filetabs_pu_menu entryconfigure [::mc "Append to project"] -state $state + + # Items: "Move up" and "Move to top" + set item_idx [$listbox_opened_files index $item] + if {$item_idx == 0} { + set state disabled + } { + set state normal + } + $opened_files_menu entryconfigure [::mc "Move up"] -state $state + $opened_files_menu entryconfigure [::mc "Move to top"] -state $state + $prev_editor_button configure -state $state + ${opened_files_buttonBox}up configure -state $state + ${opened_files_buttonBox}top configure -state $state + + # Items: "Move down" and "Move to bottom" + if {($item_idx + 1) >= [llength [$listbox_opened_files items]]} { + set state disabled + } { + set state normal + } + $opened_files_menu entryconfigure [::mc "Move down"] -state $state + $opened_files_menu entryconfigure [::mc "Move to bottom"] -state $state + $next_editor_button configure -state $state + ${opened_files_buttonBox}down configure -state $state + ${opened_files_buttonBox}bottom configure -state $state + } + + ## Invoke popup menu for "Opened files" + # @parm Int x - absolute X coordinate + # @parm Int y - absolute Y coordinate + # @return void + public method fileList_opened_filelist_popup {x y} { + if {$item_menu_invoked} { + set item_menu_invoked 0 + return + } + + if {!${::Editor::editor_to_use}} { + $opened_files_menu entryconfigure [::mc "Save as"] -state disabled + $opened_files_menu entryconfigure [::mc "Save"] -state disabled + + $filetabs_pu_menu entryconfigure [::mc "Save"] -state disabled + $filetabs_pu_menu entryconfigure [::mc "Save as"] -state disabled + } + foreach entry { + {Close} {Bookmark} {Move up} + {Move down} {Move to top} {Move to bottom} + {Open with} {Append to project} + } { + $opened_files_menu entryconfigure [::mc $entry] -state disabled + } + + tk_popup $opened_files_menu $x $y + } + + ## Invoke popup menu for "Opened files" -- for particular item + # note: This method should be associated with the 'bindtext' command + # @parm Int x - absolute X coordinate + # @parm Int y - absolute Y coordinate + # @parm String item - ID of selected item + # @return void + public method fileList_opened_filelist_item_popup {x y item} { + set item_menu_invoked 1 + + if {!${::Editor::editor_to_use}} { + $opened_files_menu entryconfigure [::mc "Save as"] -state normal + $opened_files_menu entryconfigure [::mc "Save"] -state normal + + $filetabs_pu_menu entryconfigure [::mc "Save"] -state normal + $filetabs_pu_menu entryconfigure [::mc "Save as"] -state normal + } + foreach entry { + {Close} {Bookmark} {Move up} + {Move down} {Move to top} {Move to bottom} + {Open with} + } { + $opened_files_menu entryconfigure [::mc $entry] -state normal + } + # It is not so easy to open the file with an external editor on Microsoft Windows as + # it is on a POSIX system, that's why this feature is disabled here + if {$::MICROSOFT_WINDOWS} { + $opened_files_menu entryconfigure [::mc {Open with}] -state disabled + $filetabs_pu_menu entryconfigure [::mc {Open with}] -state disabled + } + + $listbox_opened_files selection set $item + switchfile + + # Enable/Disable item "Append to project" + set fullFileName [[lindex $editors [lsearch $file_descriptors $item]] cget -fullFileName] + if {$fullFileName == {} || [getItemNameFromProjectList $fullFileName] != {}} { + set state disabled + } { + set state normal + } + $opened_files_menu entryconfigure [::mc "Append to project"] -state $state + + tk_popup $opened_files_menu $x $y + } + + # --------------------------------------------------------------------- + # AUXILIARY DATA MANAGEMENT PROCEDURES + # --------------------------------------------------------------------- + + ## Open all files in the given list + # @parm List filelist - files to open (spec. format) + # @return void + public method open_files {filelist} { + # NS variables + set file_indexes {} ;# List of line indexes (auxiliary variable for opening multiple files) + set ac_index_in_fl -1 ;# Index of actual editor filelist + + # Local variables + set num_of_opened_files 0 ;# Number of opened files + set rfi 0 ;# Record field index + set open_files_progress 0 ;# Value for progress dialog (progress) + set open_files_abort 0 ;# Abort variable + set keep_order 1 ;# Bool: Keep order of files + set rec_i -1 ;# Record index (in $filelist) + set file_indexes_fb {} ;# Fallback file indexes + set unopened_files {} ;# List of files which were unable to open + set changed_files {} ;# List of files changed since last project save + set project_path [$this cget -projectPath] ;# Path to the project directory + set filelist_length [llength $filelist] ;# Length of the given filelist + set ac [lindex $filelist {1 0}] ;# Index of actual editor + + ## Lists of files to open + # Ordered + set files_to_open__path [string repeat {{} } $filelist_length] ;# Path + set files_to_open__enc [string repeat {{} } $filelist_length] ;# Encoding + set files_to_open__eol [string repeat {{} } $filelist_length] ;# EOL + set files_to_open__bm [string repeat {{} } $filelist_length] ;# Bookmark flag + set files_to_open__ro [string repeat {{} } $filelist_length] ;# Read only flag + set files_to_open__sh [string repeat {{} } $filelist_length] ;# Syntax highlight + set files_to_open__nt [string repeat {{} } $filelist_length] ;# Notes for file + # Unordered + set files_to_open_path {} ;# Path + set files_to_open_enc {} ;# Encoding + set files_to_open_eol {} ;# EOL + set files_to_open_bm {} ;# Bookmark flag + set files_to_open_ro {} ;# Read only flag + set files_to_open_sh {} ;# Syntax highlight + set files_to_open_nt {} ;# Notes for file + + # Abort if the given filelist is empty + if {!$filelist_length} {return} + + # Iterate over records in $filelist + foreach record $filelist { + incr rec_i ;# Record index + + # First 2 records have no meaning here + if {$rec_i < 2 || $record == {}} {continue} + + # Parse record + set rfi 0 + foreach var { + file_name active o_bookmark p_bookmark + file_index read_only file_line file_md5 + file_path file_BMs file_BPs eol + enc sh notes + } { + set $var [lindex $record $rfi] + incr rfi + } + + # Adjust file path + if {[string index $file_path 0] != {/}} { + set file_path "$project_path/$file_path" + } + # Determinate full file name + set full_file_name "$file_path$file_name" + + # Check for file usebility + if { + ![file exists $full_file_name] || + [file isdirectory $full_file_name] || + (!$::MICROSOFT_WINDOWS && ![file readable $full_file_name]) + } then { + lappend file_indexes_fb {} + lappend unopened_files $full_file_name + continue + } + + # Compare file MD5 + if {[catch { + if {[md5::md5 -hex -file $file_path$file_name] != $file_md5} { + lappend changed_files $file_path$file_name + } + }]} then { + tk_messageBox \ + -icon warning \ + -type ok \ + -title [mc "Unknown error"] \ + -message [mc "Raised error during md5 checking file %s. Maybe md5 extension is not correctly loaded." $file_name] + } + + # Chech for valid EOL and Encoding + if {$eol != {lf} && $eol != {cr} && $eol != {crlf}} { + set eol $default_eol + puts stderr "Invalid EOL -- using default ($eol)" + } + if {$enc != {def} && [lsearch [encoding names] $enc] == -1} { + set enc $default_encoding + puts stderr "Invalid encoding -- using default ($default_encoding)" + } + if {![string is boolean -strict $read_only]} { + set read_only 0 + puts stderr "Read only flag -- using default (0)" + } + + # Insert bookmark to icon border for project files + if {[llength $project_files_bookmarks]} { + $listbox_project_files_bm insert end "\n" + } + if {$p_bookmark == 1} { + lappend project_files_bookmarks 1 + $listbox_project_files_bm image create [list {end-1l} linestart] \ + -image ::ICONS::16::bookmark -align center + } { + lappend project_files_bookmarks 0 + } + $listbox_project_files_bm tag add center 0.0 end + + # Register the file in the project + if {$active == {no}} { + if {[llength $record] < 5} {continue} + $listbox_project_files insert end #auto \ + -font $closed_file_font -fill {#888888} \ + -text $file_name \ + -data [list $file_name $active \ + $read_only $file_line \ + $file_md5 $file_path \ + $file_BMs $file_BPs \ + $eol $enc \ + $sh $notes \ + ] + continue + } { + $listbox_project_files insert end #auto \ + -font $opened_file_font -fill {#000000} \ + -text $file_name -data [list $file_path$file_name $eol $enc $read_only] + if {![string is digit -strict $file_index]} { + set keep_order 0 + } + } + + # Adjust lists of file indexes + lappend file_indexes $file_index + lappend file_indexes_fb $num_of_opened_files + + # Adjust list of files to open + lset files_to_open__path $file_index $file_path$file_name + lset files_to_open__enc $file_index $enc + lset files_to_open__eol $file_index $eol + lset files_to_open__bm $file_index $o_bookmark + lset files_to_open__ro $file_index $read_only + lset files_to_open__sh $file_index $sh + lset files_to_open__nt $file_index $notes + lappend files_to_open_path $file_path$file_name + lappend files_to_open_enc $enc + lappend files_to_open_eol $eol + lappend files_to_open_bm $o_bookmark + lappend files_to_open_ro $read_only + lappend files_to_open_sh $sh + lappend files_to_open_nt $notes + + # Determinate index in file list for actual editor + if {$file_index == $ac} { + set ac_index_in_fl $rec_i + incr ac_index_in_fl -2 + } + + # Increment number of opened files + incr num_of_opened_files + } + + # Invoke progress dialog + set max [llength $file_indexes_fb] + if {!$max} {set max 1} + create_progress_bar .prgDl \ + . \ + ::FileList::open_files_cur_file \ + {} \ + ::FileList::open_files_progress \ + $max \ + [mc "Opening project files"] \ + ::ICONS::16::fileopen \ + [mc "Abort"] \ + {set ::FileList::open_files_abort 1} + + # Adjust lists of files to open + if {!$keep_order} { + set files_to_open__path $files_to_open_path + set files_to_open__enc $files_to_open_enc + set files_to_open__eol $files_to_open_eol + set files_to_open__bm $files_to_open_bm + set files_to_open__ro $files_to_open_ro + set files_to_open__sh $files_to_open_sh + set files_to_open__nt $files_to_open_nt + set file_indexes $file_indexes_fb + } + + # Check for validity of list of file indexes + if {$unopened_files != {}} { + set file_indexes $file_indexes_fb + } { + for {set i 0} {$i < $num_of_opened_files} {incr i} { + if {[lsearch -ascii -exact $file_indexes $i] == -1} { + set file_indexes $file_indexes_fb + break + } + } + } + + # Open files + set i 0 + set pos 0 + foreach path $files_to_open__path \ + enc $files_to_open__enc \ + eol $files_to_open__eol \ + bm $files_to_open__bm \ + ro $files_to_open__ro \ + sh $files_to_open__sh \ + notes $files_to_open__nt \ + { + incr pos + if {$path == {}} { + continue + } + + # Abort process on user request + if {$open_files_abort} { + $listbox_project_files delete [$listbox_project_files items $i end] + if {$i} { + incr i -1 + set file_indexes [lrange $file_indexes 0 $i] + set file_indexes_fb [lrange $file_indexes_fb 0 $i] + } { + set file_indexes {} + set file_indexes_fb {} + } + + set filelist [lrange $filelist 0 $pos] + break + } + + # Adjust progress dialog + incr open_files_progress + set open_files_cur_file [file tail $path] + update + + # Open file + if {[openfile $path 0 . $enc $eol $ro 0 $sh] != {}} { + if {$bm == 1} { + opened_files_bookmark $i + } + $this set_file_notes_data $notes + } + incr i + } + + # Invoke dialog "File(s) not found" + if {$unopened_files != {}} { + # Create toplevel window + set win [toplevel .file_not_found$obj_idx -class {Error dialog} -bg {#EEEEEE}] + + # Create window header + pack [frame $win.frame1] -side top -fill x -anchor nw + pack [label $win.frame1.image \ + -image ::ICONS::32::messagebox_critical \ + ] -anchor nw -expand 0 -side left -padx 10 -pady 5 + pack [label $win.frame1.header \ + -text [mc "The following files could not be located:"] \ + ] -side left -fill x + + # Create text widget with scrollbar + pack [frame $win.frame2] -side top -expand 1 -fill both -pady 10 -padx 5 + pack [text $win.frame2.text -height 5 -width 40 \ + -yscrollcommand "$win.frame2.scrollbar set"] -side left -fill both -expand 1 + pack [ttk::scrollbar $win.frame2.scrollbar \ + -orient vertical \ + -command "$win.frame2.text yview" \ + ] -side right -fill y + + # Insert list of unopened files into the text widgets + $win.frame2.text insert end [join $unopened_files "\n"] + $win.frame2.text configure -state disabled + + bind $win.frame2.text <1> "focus $win.frame2.text" + + # Create button "Ok" + pack [ttk::button $win.but_ok \ + -text [mc "Ok"] \ + -compound left \ + -image ::ICONS::16::ok \ + -command " + grab release $win + destroy $win + " \ + ] -side bottom + + # Dialog event bindings + bind $win <Return> " + grab release $win + destroy $win + " + bind $win <KP_Enter> " + grab release $win + destroy $win + " + bind $win <Escape> " + grab release $win + destroy $win + " + + # Set window attributes + wm iconphoto $win ::ICONS::16::status_unknown + wm title $win [mc "File(s) not found"] + wm geometry $win 500x200 + wm protocol $win WM_DELETE_WINDOW " + grab release $win + destroy $win + " + update + catch {grab $win} + raise $win + } + + # Invoke dialog "File(s) changed" + if {$changed_files != {}} { + # Create dialog toplevel window + set win [toplevel .changed_files$obj_idx -class {File changed} -bg {#EEEEEE}] + + # Create dialog header + pack [frame $win.frame1] -side top -fill x -anchor nw + pack [label $win.frame1.image -image ::ICONS::32::messagebox_info] \ + -anchor nw -expand 0 -side left -padx 10 -pady 5 + pack [label $win.frame1.header \ + -text [mc "The following files were modified since last save:"] \ + ] -side left -fill x + + # Create text widget and scrollbar + pack [frame $win.frame2] -side top -expand 1 -fill both -pady 10 -padx 5 + pack [text $win.frame2.text -height 5 -width 50 \ + -yscrollcommand "$win.frame2.scrollbar set"] -side left -fill both -expand 1 + pack [ttk::scrollbar $win.frame2.scrollbar \ + -orient vertical \ + -command "$win.frame2.text yview" \ + ] -side right -fill y + + # Insert info about changed files + foreach file $changed_files { + if {[file exists $file_path$file_name]} { + set time [clock format [file mtime $file_path$file_name] -format {%T %D}] + } { + set time " -----\t" + } + $win.frame2.text insert end "$time\t$file\n" + } + $win.frame2.text configure -state disabled + + bind $win.frame2.text <1> "focus $win.frame2.text" + + # Create button "Ok" + pack [ttk::button $win.but_ok \ + -text [mc "Ok"] \ + -compound left \ + -image ::ICONS::16::ok \ + -command " + grab release $win + destroy $win + " \ + ] -side bottom -pady 5 + + # Set dialog event bindings + bind $win <Return> " + grab release $win + destroy $win + " + bind $win <KP_Enter> " + grab release $win + destroy $win + " + bind $win <Escape> " + grab release $win + destroy $win + " + + # Set window attributes + wm iconphoto $win ::ICONS::16::info + wm title $win [mc "File(s) changed"] + wm geometry $win 500x200 + wm protocol $win WM_DELETE_WINDOW " + grab release $win + destroy $win + " + update + catch {grab $win} + raise $win + } + } + + ## Open file at the given location and with some additional options + # Alogorithm: + # * check if the file exists, if it doesn't then invoke an error message + # * if the file exists then open it and read its content + # * if the specified file path is an empty string then consider that file as a new one + # * check if that file in not already opened and if it is then focus on it and return + # * register that file in the class's internal variables + # * create a new editor for that file and eventualy display content of the file + # * focus on that newly created editor + # + # @parm String file_path - full file name including path, {} means create a new one + # @parm Bool ask - ask user about adding the file to the project + # @parm String parent - path to the parent widget (eg. dialog which invoked this procedure) + # @parm String enc - Character encoding + # @parm String eol - End of Line character identifier (one of {lf crlf cr}) + # @parm Bool read_only - Read only flag + # @parm Bool fast - Open the file as fast as possible (only for creating new files) + # sh + # @return String - descriptor of the opened file + public method openfile {file_path ask parent enc eol read_only fast sh} { + set newfile 0 ;# Bool: created new virtual file + + # Open an existing file + if {$file_path != {}} { + # Report error if the file does not exist + if { + !${::Editor::editor_to_use} && ( + ![file exists $file_path] || + ![file isfile $file_path] || + (!$::MICROSOFT_WINDOWS && ![file readable $file_path]) + ) + } { + tk_messageBox \ + -type ok \ + -title [mc "File not found - MCU 8051 IDE"] \ + -message [mc "File %s not found !" $file_path] \ + -icon error + set newfile 1 + } + + # determine the filename + regexp {[^\\\/]+$} $file_path file_name + + # Create a new file (untitled) + } else { + if {![regexp {untitled\d*} $file_descriptors]} { + set untitled_num -1 + } + if {$untitled_num == -1} { + set file_name "untitled" + } { + set file_name "untitled$untitled_num" + } + incr untitled_num + set newfile 1 + } + if {$file_name == {.#special:tmp}} { + if {![regexp {untitled\d*} $file_descriptors]} { + set untitled_num -1 + } + if {$untitled_num == -1} { + set file_name "untitled" + } { + set file_name "untitled$untitled_num" + } + incr untitled_num + set newfile 1 + } + + # Check if the file isn't already opened + if {!$newfile} { + set idx 0 + foreach editor $editors { + if {[$editor cget -fullFileName] == $file_path} { + set item [lindex $file_descriptors $idx] + $listbox_opened_files selection set $item + switchfile + set lastItem $item + Sbar [mc "File: %s is alredy opened." $file_path] + return {} + } + incr idx + } + } + + # Adjust arguments 'eol' and 'enc' + if {$eol == {def}} { + set eol $default_eol + } + if {$enc == {def}} { + set enc $default_encoding + } + + # Determinate unique file descriptor + set file_descriptor [regsub -all {_} $file_name {__}] + set file_descriptor [regsub -all {\.} $file_descriptor {_}] + set file_descriptor [regsub -all -- {-} $file_descriptor {--}] + set file_descriptor [regsub -all -- {\s} $file_descriptor {-}] + # Handle similar file descriptors of different files + while 1 { + if {[lsearch $file_descriptors $file_descriptor] != -1} { + append file_descriptor {_} + } { + break + } + } + + # Register the file descriptor + lappend file_descriptors $file_descriptor + # Insert filename into ListBox of opened files + $listbox_opened_files insert end $file_descriptor \ + -text $file_name -data $file_path -font $icon_border_font + if {[llength $opened_files_bookmarks]} { + $listbox_opened_files_bm insert end "\n" + } + lappend opened_files_bookmarks 0 + + if {$ask} { + # test if the file isn't already included in the project + set item [getItemNameFromProjectList $file_path] + if {$item != {}} { + set ask 0 + } + + if {!$ask} { + $listbox_project_files itemconfigure $item \ + -font $opened_file_font \ + -fg {#000000} \ + -data [list $file_path $eol $enc $read_only] + } + } + + if {$ask && $::FileList::ask__append_file_to_project} { + # Ask for append the file to the project + set ::FileList::dialog_response 0 + set win [toplevel .append_to_the_project_dialog] + + pack [label $win.label -text [mc "Do you want to append this file to the project ?\n%s" $file_name]] -fill x -pady 5 -padx 5 + + pack [frame $win.frm] -pady 5 + pack [ttk::button $win.frm.yes_button -text [mc "Yes"] -command " + set ::FileList::dialog_response 1 + grab release $win + destroy $win" \ + ] -side left + bind $win.frm.yes_button <Return> " + set ::FileList::dialog_response 1 + grab release $win + destroy $win" + bind $win.frm.yes_button <KP_Enter> " + set ::FileList::dialog_response 1 + grab release $win + destroy $win" + pack [ttk::button $win.frm.no_button -text [mc "No"] -command " + grab release $win + destroy $win" \ + ] -side left + bind $win.frm.no_button <Return> " + grab release $win + destroy $win" + bind $win.frm.no_button <KP_Enter> " + grab release $win + destroy $win" + + pack [ttk::separator $win.sep -orient horizontal] -fill x -pady 10 + pack [checkbutton $win.chb -text [mc "Do not ask again"] -onvalue 0 -offvalue 1 -variable ::FileList::ask__append_file_to_project] -anchor w + pack [text $win.tip -fg {#888888} -bg {#EEEEEE} -height 2 -width 0 -bd 0] -fill x + $win.tip insert end [mc "Tip: You can enable/disable this dialog in MCU 8051 IDE configuration dialog."] + $win.tip configure -state disabled + + # Set window attributes + wm iconphoto $win ::ICONS::16::help + wm title $win [mc "Add file ?"] + wm resizable $win 0 0 + wm transient $win . + catch {grab $win} + focus -force $win.frm.yes_button + wm protocol $win WM_DELETE_WINDOW " + grab release $win + destroy $win + " + raise $win + update + tkwait window $win + + if {$::FileList::dialog_response } { + if {[llength $project_files_bookmarks]} { + $listbox_project_files_bm insert end "\n" + } + lappend project_files_bookmarks 0 + $listbox_project_files insert end #auto \ + -font $opened_file_font -fill {#000000} \ + -text $file_name -data [list $file_path $eol $enc $read_only] + } + } + + # Create editor object for the file + if {$file_path != {}} { + set data {} + if {!${::Editor::editor_to_use}} { + set file [open $file_path] + fconfigure $file -encoding $enc + if {[regsub -all {[\u0000-\u0008\u000B-\u000C\u000E-\u001F\u007F-\u009F]} [read $file] {} data]} { + tk_messageBox -parent . \ + -type ok -icon warning \ + -title [mc "Binary File Opened - MCU 8015 IDE"] \ + -message [mc "The file %s is binary, saving it will result corrupted file." $file_path] + } + close $file + } + + set editor [Editor "::editor${file_count}_$obj_idx" \ + [expr {!$fast}] $eol $enc $read_only $file_switching_enabled $this \ + $file_name $file_path "$this editor_procedure {} " \ + [regsub -all {\r\n?} $data "\n"] $sh \ + ] + } { + set editor [Editor "::editor${file_count}_$obj_idx" \ + [expr {!$fast}] $eol $enc $read_only $file_switching_enabled $this \ + $file_name $file_path "$this editor_procedure {} " {} $sh \ + ] + } + + # Determinate file type and set appropriate icon + set ext [string trimleft [file extension $file_name] {.}] + if {$ext == {h}} { + set icon {source_h} + } elseif {$ext == {c}} { + set icon {source_c} + } elseif {$ext == {cxx} || $ext == {cpp} || $ext == {cc}} { + set icon {source_cpp} + } elseif {$ext == {asm}} { + set icon {asm} + } else { + set icon {ascii} + } + $filetabs_nb insert end $file_descriptor \ + -text $file_name -image ::ICONS::16::$icon \ + -raisecmd "$this switch_file_from_filetabs $file_descriptor" + $filetabs_nb see $file_descriptor + + # Conditionaly show Line Numbers and Icon Border + if {$iconBorder == 0} { + $editor hideLineNumbers + } + if {$lineNumbers == 0} { + $editor hideIconBorder + } + + if {$sh == {}} { + set sh [$editor get_language] + } + + # Editor text widget + lappend editor_wdgs [$editor cget -editor] + # Register Editor's object and widget and its frame + lappend editors $editor + lappend file_eol $eol + lappend file_encoding $enc + lappend file_ro_mode $read_only + lappend file_sh $sh + + # Add editor to right panel + rightPanel_add_Editor [expr {!$fast}] + $this todo_add_Editor {} + $this todo_change_filename end $file_name + $editor goto 1 + + # Increment counter of opened files + incr file_count + # Return descriptor of the file + return $file_descriptor + } + + ## Switch file from filetabs notebook + # @parm String page - Page ID + # @return void + public method switch_file_from_filetabs {page} { + $listbox_opened_files selection set $page + switchfile + } + + ## Show file details windows from files tab (or something ...) + # $filetabs_nb bindtabs <Enter> "$this file_details_win_create_from_ftnb" + # @parm String page - Page ID + # @return void + public method file_details_win_create_from_ftnb {page} { + $this file_details_win_create O $page + } + + ## Invoke popup menu for specific file from files tab (or something ...) + # $filetabs_nb bindtabs <ButtonRelease-3> "$this filetabs_nb_popup_menu %X %Y" + # @parm Int X - X coordinate + # @parm Int Y - Y coordinate + # @parm String page - Page ID + # @return void + public method filetabs_nb_popup_menu {X Y page} { + switch_file_from_filetabs $page + + tk_popup $filetabs_pu_menu $X $Y + } + + ## Save currently opened file under a given filename + # note: should be used only for saving untitled files ! + # @parm String filename - Full file name including path + # @return bool - 1: (maybe) successful; 0: argument is empty + public method save_as {filename} { + + # Handle empty argument + if {$filename == {}} {return 0} + + # Adjust filename + if {!$::MICROSOFT_WINDOWS} { ;# POSIX way + if {![regexp "^(~|/)" $filename]} { + set filename "[$this cget -ProjectDir]/$filename" + } + } { ;# Microsoft windows way + if {![regexp "^\w:" $filename]} { + set filename [file join [$this cget -ProjectDir] $filename] + } + } + set filename [file normalize $filename] + if {[file extension $filename] == {}} { + append filename {.asm} + } + # Determinate file rootname + set rootname [file tail $filename] + + # Ask user for overwrite existing file + if {[file exists $filename] && [file isfile $filename]} { + if {[tk_messageBox \ + -type yesno \ + -icon question \ + -parent . \ + -title [mc "Overwrite file"] \ + -message [mc "A file name '%s' already exists. Are you sure you want to overwrite it ?" $rootname] + ] != {yes} + } { + return 1 + } + } + + # Change filename in the listbox of opened files + set item [$listbox_opened_files selection get] + $listbox_opened_files itemconfigure $item -text $rootname -data $filename + $filetabs_nb itemconfigure $item -text $rootname + + # Determinate some additional informations + if {$splitted && $selectedView} { + set idx $actualEditor2 + } { + set idx $actualEditor + } + set editor [lindex $editors $idx] + set fullFileName [$editor cget -fullFileName] ;# Original full filename + set original_rootname [$editor cget -filename] ;# Original file rootname + + # Mark the file as opened (in listbox of project files) + foreach item [$listbox_project_files items] { + if {[$listbox_project_files itemcget $item -text] != $original_rootname} { + continue + } + set data [$listbox_project_files itemcget $item -data] + if {[llength $data] > 4} {continue} + if {[lindex $data 0] != $fullFileName} {continue} + lset data 0 $filename + $listbox_project_files itemconfigure $item -data $data -text $rootname + } + + # Set new file name + $editor set_FileName $filename $rootname + $editor save + $this todo_change_filename $idx $rootname + + # Ask for appending the file to the project + set response [tk_messageBox \ + -title [mc "Add file ?"] \ + -icon question -type yesno \ + -parent $parent \ + -message [mc "Do you want to append this file to the project ?\n%s" $rootname] + ] + if {$response == {yes}} { + filelist_append_to_prj + } + + ::X::recent_files_add 1 $filename + + # Done ... + return 1 + } + + + # --------------------------------------------------------------------- + # EDITOR PROCEDURES + # --------------------------------------------------------------------- + + ## Show/Hide line numbers + # @return void + public method show_hide_lineNumbers {} { + if {$lineNumbers} { + set lineNumbers 0 + foreach editor $editors {$editor hideLineNumbers} + } { + set lineNumbers 1 + foreach editor $editors {$editor showLineNumbers} + } + } + + ## Show/Hide icon border + # @return void + public method show_hide_IconBorder {} { + if {$iconBorder} { + set iconBorder 0 + foreach editor $editors {$editor hideIconBorder} + } { + set iconBorder 1 + foreach editor $editors {$editor showIconBorder} + } + } + + ## Get number of lines in the current editor + # @return Int - result + public method editor_linescount {} { + if {$splitted && $selectedView} { + set tmp $actualEditor2 + } { + set tmp $actualEditor + } + set tmp [[lindex $editors $tmp] cget -lastEnd] + return [expr {$tmp-1}] + } + + ## Get number of line with the insertion cursor + # @return Int - result + public method editor_actLineNumber {} { + if {$splitted && $selectedView} { + set idx $actualEditor2 + } { + set idx $actualEditor + } + return [expr {int([[lindex $editor_wdgs $idx] index insert])}] + } + + ## Call any editor procedure + # @parm Int objectNumber - Number of editor object to use, {} mean current editor + # @parm String procedure - name of the procedure + # @parm String arguments - list of arguments to pass that procedure + # @retrurn mixed - result of invoked procedure + public method editor_procedure {objectNumber procedure arguments} { + # Determinate editor number + if {$objectNumber == {}} { + if {$splitted && $selectedView} { + set objectNumber $actualEditor2 + } { + set objectNumber $actualEditor + } + } + # Call editor procedure + set editor [lindex $editors $objectNumber] + if {$editor == {}} { + switch_to_last + update + } + return [eval "$editor $procedure $arguments"] + } + + ## Compare two tag ranges (text widget tags) + # @parm TextIndex first - 1st text tag range to compare {TextIndex Bool__Start_or_End} + # @parm TextIndex second - 2nd text tag range to compare {TextIndex Bool__Start_or_End} + # @return Int - result (on of {-1 0 1}) + proc editor__sort_tag_ranges {first second} { + + # Local variables + set idx0 [split [lindex $first 0] {.}] ;# Adjusted 1st text index -- list: {Row Column} + set row0 [lindex $idx0 0] ;# Row (1st index) + set col0 [lindex $idx0 1] ;# Column (1st index) + set idx1 [split [lindex $second 0] {.}] ;# Adjusted 2nd text index -- list: {Row Column} + set row1 [lindex $idx1 0] ;# Row (2nd index) + set col1 [lindex $idx1 1] ;# Column (2nd index) + set StartEnd0 [lindex $first 2] ;# Bool: Start_or_End (1st index) + set StartEnd1 [lindex $second 2] ;# Bool: Start_or_End (2nd index) + + # Compare rows + if {$row0 > $row1} { + return -1 + } elseif {$row0 < $row1} { + return 1 + } + + # Compare columns + if {$col0 > $col1} { + return -1 + } elseif {$col0 < $col1} { + return 1 + } + + # Compare "Start_or_End" flags + if {!$StartEnd0 && $StartEnd1} { + return 1 + } elseif {$StartEnd0 && !$StartEnd1} { + return -1 + } else { + return 0 + } + } + + ## Get list of project files + # @return List - result + public method get_project_files_list {} { + ## Local variables + # List header + if {$splitted} { + set _actualEditor2 $actualEditor2 + } { + set _actualEditor2 -1 + } + if {$splitted} { + if {$pwin_orient == {vertical}} { + set idx 1 + } { + set idx 0 + } + set multiview_sash_pos [lindex [$multiview_paned_win sash coord 0] $idx] + } + set file_list [list \ + [llength $editors] \ + [list \ + $actualEditor \ + $_actualEditor2 \ + $multiview_sash_pos \ + $pwin_orient \ + $selectedView \ + ] \ + ] + # Project directory + set project_path [$this cget -projectPath] + append project_path {/} + # Lenght of the project directory path string + set project_path_length [string length $project_path] + # Opened files index + set opened_i 0 + + ## Create list of full paths of opened files (in order of listbox of opened files) + set opened_files {} + foreach item [$listbox_opened_files items] { + set file_path [$listbox_opened_files itemcget $item -data] + if {$file_path == {}} {continue} + lappend opened_files $file_path + } + + # Iterate over items of ListBox of project files + set i -1 + foreach item [$listbox_project_files items] { + incr i + + # Determinate item data + set data [$listbox_project_files itemcget $item -data] + + # Unopened file + if {[llength $data] > 4} { + # Set opened flag + lset data 1 {no} + # Set file path + set path [lindex $data 5] + if {[string first $project_path $path] == 0} { + lset data 5 [string range $path $project_path_length end] + } + + # Append o-bookmark=0, p-bookmark=$bm and file index=0 + set data [linsert $data 2 0 [lindex $project_files_bookmarks $i] 0] + + # Append file record to the resulting list + lappend file_list $data + + # Opened file + } { + # Find the file in list of opened files + foreach editor $editors { + # Local variables + set file_name [$editor cget -fullFileName] ;# Full file name + + if {$file_name != [lindex $data 0]} {continue} + + # Determinate true item data + set data [getFileInfo $editor {yes}] + + # Set file path + set path [lindex $data 5] + if {[string first $project_path $path] == 0} { + lset data 5 [string range $path $project_path_length end] + } + + # Determinate index in Listbox of opened files + set index [lsearch $opened_files $file_name] + + # Append o-bookmark, p-bookmark and file index + set data [linsert $data 2 \ + [lindex $opened_files_bookmarks $index] \ + [lindex $project_files_bookmarks $i] \ + $index] + + # Append encoding and EOL info + lappend data \ + [lindex $file_eol $opened_i] \ + [lindex $file_encoding $opened_i] \ + [lindex $file_sh $opened_i] \ + [$this get_file_notes_data $i] + + incr opened_i + + # Append file record to the resulting list + lappend file_list $data + } + } + } + + # Return the file list + return $file_list + } + + ## Get opened file item data to use in filelists + # @see get_project_files_list + # @see editor_close + # @parm Object editor - Reference to editor object + # @parm String active - Active flag + # @return List - resulting data or '{}' + private method getFileInfo {editor active} { + # Determinate full file name + set file_name [$editor cget -fullFileName] + if {$file_name == {}} {return {}} + + # Determinate file rootname, path and MD5 hex hash + regexp {[^\\\/]*$} $file_name name + regexp {^.*[\\\/]} $file_name path + if {[catch { + set md5_hash [md5::md5 -hex -hex -file $file_name] + }]} { + set md5_hash {} + } + + set actual_line [$editor get_current_line_number] ;# Current line + set line_markers [$editor export_line_markers_data] ;# bookmarks and breakpoints + set bookmarks [lindex $line_markers 0] ;# Bookmarks + set breakpoints [lindex $line_markers 1] ;# Breakpoints + + # Return result + return [list \ + $name $active [$editor cget -ro_mode] \ + $actual_line $md5_hash $path \ + $bookmarks $breakpoints \ + ] + } + + ## Invoke dialog "Open file" (require NS 'X') + # @return void + public method editor_open {} { + X::__open + } + + ## Save the current file + # @return void + public method editor_save {} { + if {$splitted && $selectedView} { + [lindex $editors $actualEditor2] save + } { + [lindex $editors $actualEditor] save + } + } + + ## Save current file under a different name (reires NS 'X') + # @return void + public method editor_save_as {} { + X::__save_as + } + + ## Call procedure save for each editor object in the current project + # note: in other words save all opened files + # @return void + public method editor_save_all {} { + foreach editor $editors { + $editor save + } + } + + ## Create a new empty editor object inside the project and focus on it + # @return void + public method editor_new {} { + openfile {} 0 . def def 0 1 {} + switch_to_last + set editor [lindex $editors end] + update + $editor create_highlighting_tags + update + rightPanel_add_Editor__create_menu_and_tags + $editor parseAll + focus [$editor cget -editor] + } + + ## Open a new editor containing the given data + # @parm String data - Data to insert into the editor + # @return void + public method background_open {data} { + if {!${::Editor::editor_to_use}} { + openfile {} 0 . def def 0 0 {} + set editor [lindex $editors end] + $editor insertData $data {} + [$editor cget -editor] edit modified 0 + [$editor cget -editor] edit reset + } { + set dir [${::X::actualProject} cget -ProjectDir] + catch { + file delete -force -- [file join $dir .#special:tmp] + } + + set file [open [file join $dir .#special:tmp] w 420] + puts -nonewline $file $data + close $file + + openfile [file join $dir .#special:tmp] 0 . def def 0 0 {} + } + } + + ## Close the current editor and optionaly save its data to some file + # note: if this procedure was executed to destroy the last + # remainig editor then a new one would be created !!! + # @parm Bool ask - Ask user for saving the file (if was modified) + # @parm Int editorIdx - number of editor to close, {} mean currently active editor + # @return Bool - Created a new editor ? + public method editor_close {ask editorIdx} { + if {$editor_close_in_progress} {return} + set editor_close_in_progress 1 + + # Determinate editor object reference + if {$editorIdx == {}} { + if {$splitted && $selectedView} { + set editorIdx $actualEditor2 + } { + set editorIdx $actualEditor + } + } { + if {$editorIdx == $actualEditor} { + set selectedView 0 + } elseif {$editorIdx == $actualEditor2} { + set selectedView 1 + } + } + set editor [lindex $editors $editorIdx] + + # Ask user for saving the file (if was modified) + if {$ask && [$editor cget -modified]} { + set response [tk_messageBox \ + -type yesnocancel \ + -title [mc "Close document - MCU 8051 IDE"] \ + -icon question \ + -default yes \ + -message [mc "The document %s have been modified.\nDo you want to save it ?" [[lindex $editors $editorIdx] cget -fullFileName]]] + + if {$response == {yes}} { + $editor save + } elseif {$response == {cancel}} { + set editor_close_in_progress 0 + return {} + } + } + + # Mark the file as unopened (in ListBox of project fies) + set items [$listbox_project_files items] ;# List of project files + set fullFileName [$editor cget -fullFileName] ;# Full filename of the current file + set rootname [$editor cget -filename] ;# Rootname of the current file + foreach item $items { + if {[$listbox_project_files itemcget $item -text] != $rootname} { + continue + } + set data [$listbox_project_files itemcget $item -data] + if {[llength $data] > 4} {continue} + + if {[lindex $data 0] == $fullFileName} { + $listbox_project_files itemconfigure $item \ + -fg {#888888} \ + -font $closed_file_font \ + -data [concat \ + [getFileInfo $editor {no}] \ + [lindex $file_eol $editorIdx] \ + [lindex $file_encoding $editorIdx] \ + [lindex $file_sh $editorIdx] \ + [$this get_file_notes_data $editorIdx] \ + ] + } + } + + # Delete editor object and all its widgets + set file_descriptor [lindex $file_descriptors $editorIdx] + set item_index [$listbox_opened_files index $file_descriptor] + $listbox_opened_files delete $file_descriptor + $listbox_opened_files_bm delete [expr {$item_index + 1}].0 [expr {$item_index + 2}].0 + set opened_files_bookmarks [lreplace $opened_files_bookmarks $item_index $item_index] + delete object $editor + rightPanel_remove_Editor $editorIdx + $this todo_remove_editor $editorIdx + + $filetabs_nb delete $file_descriptor + + # Adjust object variables + foreach var {editors file_descriptors editor_wdgs file_eol file_encoding file_ro_mode file_sh} { + set $var [lreplace [subst "\$$var"] $editorIdx $editorIdx] + } + if {$actualEditor > $editorIdx} { + incr actualEditor -1 + } + if {$actualEditor2 > $editorIdx} { + incr actualEditor2 -1 + } + if {$actualEditor == $editorIdx || $actualEditor2 == $editorIdx} { + set do_not_forget_editor 1 + if {$actualEditor == $editorIdx} { + set actualEditor -1 + } + if {$actualEditor2 == $editorIdx} { + set actualEditor2 -1 + } + + # Conditionaly open a new editor + if {$splitted} { + set min 2 + } { + set min 1 + } + if {[llength $file_descriptors] < $min} { + if {$min == 1} { + set file_count 0 + } + Sbar [mc "Last editor window closed -> opening a new one ..."] + editor_new + set editor_close_in_progress 0 + return 1 + } + # Switch to last editor in the list + switch_to_last + } + + set editor_close_in_progress 0 + return 1 + } + + ## Close all editors in the list of opened files + # @parm Bool allowCancelButton - Display button "Cancel" in dialog "Save multiple files" + # @parm Bool projectClose - Should be 1 if closing project + # @return Bool - 1: all have been done smoothly; 0: user has been asked about modified files + public method editor_close_all {allowCancelButton projectClose} { + # Determinate number of editors to close + set editorCount [llength $file_descriptors] + + # Create list of the modified ones + set unsaved {} + foreach editor $editors { + if {[$editor cget -modified]} { + lappend unsaved $editor + } + } + + # Ask user for file save + if {$unsaved != {}} { + save_multiple_files $allowCancelButton + return 0 + } { + if {!$projectClose} { + editor_force_close_all + } + return 1 + } + } + + ## Close all opened files without any warning + # @return void + public method editor_force_close_all {} { + # Determinate number of editors + set editorMaxIdx [llength $file_descriptors] + set editorMaxIdx [expr {$editorMaxIdx - 1}] + + # Close editors + for {set i $editorMaxIdx} {$i >= 0} {incr i -1} { + editor_close 0 $i + } + } + + ## Create special dialog to ask user which files should be saved + # Intended for closing multiple files + # note: * Using class variable 'unsaved' instead of any argument !!! + # * Depend on methods: save_multiple_files_DESTROY, save_multiple_files_CANCEL, + # save_multiple_files_SAVEALL, save_multiple_files_SAVESELECTED + # @parm allowCancelButton bool - 1: show 'Cancel' button; 0: nothing + # @return void + public method save_multiple_files {allowCancelButton} { + + # Create a new toplevel window for the dialog + set dialog .save_multiple_files + toplevel $dialog + + # Create the top part of dialog (Header and some icon) + pack [frame $dialog.topframe] -fill x -expand 1 + pack [label $dialog.topframe.image -image ::ICONS::32::fileclose] -side left -padx 10 + pack [label $dialog.topframe.message \ + -text [mc "The following documents have been modified,\ndo you want to save them before closing ?"] \ + ] -side right -fill x -expand 1 + + # Create the middle part of the dialog (list of unsaved files) + pack [tkk::labelframe $dialog.lf \ + -text [mc "Unsaved files"] \ + ] -fill both -expand 1 -pady 10 -padx 10 + set i 0 + foreach editorObj $unsaved { + pack [checkbutton $dialog.lf.chb$i \ + -text [$editorObj cget -filename] \ + -variable unsavedfile$i \ + -image ::ICONS::16::kcmdf \ + -compound left \ + ] -anchor w -padx 10 + incr i + } + + # Create the bottom part of the dialog (buttons "Save selected", "Save all" etc.) + pack [ttk::separator $dialog.separator -orient horizontal] -fill x -expand 1 + pack [frame $dialog.f] + # SAVESELECTED + pack [ttk::button $dialog.f.b_save_selected \ + -text [mc "Save selected"] \ + -compound left \ + -image ::ICONS::16::filesave \ + -command {${X::actualProject} save_multiple_files_SAVESELECTED} \ + ] -side left + # SAVEALL + pack [ttk::button $dialog.f.b_save_all \ + -text [mc "Save all"] \ + -compound left \ + -image ::ICONS::16::save_all \ + -command {${X::actualProject} save_multiple_files_SAVEALL} \ + ] -side left + # DESTROY + pack [ttk::button $dialog.f.b_discard \ + -text [mc "Discard"] \ + -compound left \ + -image ::ICONS::16::editdelete \ + -command {${X::actualProject} save_multiple_files_DESTROY} \ + ] -side left + # CANCEL + if {$allowCancelButton} { + pack [ttk::button $dialog.f.b_cancel \ + -text [mc "Cancel"] \ + -compound left \ + -image ::ICONS::16::button_cancel \ + -command {${X::actualProject} save_multiple_files_CANCEL} \ + ] -side left + } + + # Set dialog attributes (modal window) + wm iconphoto $dialog ::ICONS::16::exit + wm title $dialog [mc "Close files - MCU 8051 IDE"] + wm state $dialog normal + wm minsize $dialog 350 200 + wm transient $dialog . + wm protocol $dialog WM_DELETE_WINDOW " + grab release $dialog + destroy $dialog + " + update + catch { + grab $dialog + } + raise $dialog + focus $dialog + tkwait window $dialog + } + + ## Auxiliary procedure for method 'save_multiple_files' + # It should be executed on pressing button 'Save selected' dialog 'Save multiple files' + # This function saves all files selected in dialog 'Save multiple files' + # @return void + public method save_multiple_files_SAVESELECTED {} { + set i 0 + foreach editor $unsaved { + set cnd [subst "\${::unsavedfile$i}"] + if {$cnd} {$editor save} + incr i + } + save_multiple_files_DESTROY + } + + ## Auxiliary procedure for method 'save_multiple_files' + # It should be executed on pressing button 'Save all' dialog 'Save multiple files' + # @return void + public method save_multiple_files_SAVEALL {} { + foreach editor $unsaved { + $editor save + } + save_multiple_files_DESTROY + } + + ## Auxiliary procedure for method 'save_multiple_files' + # It should be executed on pressing button 'Discard' in 'Save multiple files' dialog + # @return void + public method save_multiple_files_DESTROY {} { + set editorMaxIdx [llength $file_descriptors] + set editorMaxIdx [expr {$editorMaxIdx - 1}] + editor_force_close_all + save_multiple_files_CANCEL + } + + ## Auxiliary procedure for method 'save_multiple_files' + # It should be executed on pressing button 'Cancel' in 'Save multiple files' dialog + # @return void + public method save_multiple_files_CANCEL {} { + destroy .save_multiple_files + } + + ## Reevaluate state of buttons on icon bar in tab LProject files + # @return void + public method FileList_project_disEna_buttons {} { + + # Determinate selected item + set item [$listbox_project_files selection get] + + # Non empty selection + if {$item != {}} { + ${project_files_buttonBox}remove configure -state normal + ${project_files_buttonBox}bookmark configure -state normal + + # Simulator engaged + if {$frozen} { + ${project_files_buttonBox}close configure -state disabled + ${project_files_buttonBox}open configure -state disabled + + # Simulator disengaged + } { + # Opened file + if {[llength [$listbox_project_files itemcget $item -data]] < 5} { + ${project_files_buttonBox}close configure -state normal + ${project_files_buttonBox}open configure -state disabled + + # Unopened file + } { + ${project_files_buttonBox}close configure -state disabled + ${project_files_buttonBox}open configure -state normal + } + } + + # Nothing selected + } { + ${project_files_buttonBox}remove configure -state disabled + ${project_files_buttonBox}open configure -state disabled + ${project_files_buttonBox}close configure -state disabled + ${project_files_buttonBox}bookmark configure -state disabled + } + } + + ## Invoke project files popup menu + # @parm Int X - relative X coordinate + # @parm Int Y - relative Y coordinate + # @return void + public method fileList_project_filelist_popup {X Y} { + if {$item_menu_invoked} { + set item_menu_invoked 0 + return + } + + foreach entry { + {Remove file from the project} {Close file} {Open file} + {Bookmark} {Move up} {Move down} + {Move to top} {Move to bottom} {Open with} + } { + $project_files_menu entryconfigure [::mc $entry] -state disabled + } + + tk_popup $project_files_menu $X $Y + } + + ## Invoke project files popup menu -- for particular item + # @parm Int X - relative X coordinate + # @parm Int Y - relative Y coordinate + # @parm String item - ID of the current item + # @return void + public method fileList_project_filelist_item_popup {X Y item} { + set item_menu_invoked 1 + + foreach entry { + {Remove file from the project} {Bookmark} {Open with} + } { + $project_files_menu entryconfigure [::mc $entry] -state normal + } + + # It is not so easy to open the file with an external editor on Microsoft Windows as + # it is on a POSIX system, that's why this feature is disabled here + if {$::MICROSOFT_WINDOWS} { + $project_files_menu entryconfigure [::mc {Open with}] -state disabled + } + + # Adjust ListBox selection + $listbox_project_files selection set $item + + # Opened file + if {[llength [$listbox_project_files itemcget $item -data]] < 5} { + if {!$frozen} { + $project_files_menu entryconfigure [::mc "Close file"] -state normal + } + $project_files_menu entryconfigure [::mc "Open file"] -state disabled + # Unopened file + } { + if {!$frozen} { + $project_files_menu entryconfigure [::mc "Close file"] -state disabled + } + $project_files_menu entryconfigure [::mc "Open file"] -state normal + } + + # Movement commands + if {[$listbox_project_files index $item] == 0} { + set state disabled + } { + set state normal + } + $project_files_menu entryconfigure [::mc "Move up"] -state $state + $project_files_menu entryconfigure [::mc "Move to top"] -state $state + + if {[$listbox_project_files index $item] == ([llength [$listbox_project_files items]] - 1)} { + set state disabled + } { + set state normal + } + $project_files_menu entryconfigure [::mc "Move down"] -state $state + $project_files_menu entryconfigure [::mc "Move to bottom"] -state $state + + # Invoke the menu + tk_popup $project_files_menu $X $Y + } + + ## Move up current item in project filelist + # @return void + public method filelist_prj_move_up {} { + # Local variables + set item [$listbox_project_files selection get] ;# Item ID + set index [$listbox_project_files index $item] ;# Item index + set target [expr {$index - 1}] ;# Target index + + # Check if the item can be moved + if {$index == 0} {return} + + # Move item in listbox + $listbox_project_files move $item $target + # Move item in list of bookmarks and icon border + if {[lindex $project_files_bookmarks $index] != [lindex $project_files_bookmarks $target]} { + # Determinate bookmark flag for source and target index + set trg_bm [lindex $project_files_bookmarks $target] + set idx_bm [lindex $project_files_bookmarks $index] + # Move item in list of bookmarks + lset project_files_bookmarks $target [lindex $project_files_bookmarks $index] + lset project_files_bookmarks $index $trg_bm + # Move item in icon border + incr target + incr index + $listbox_project_files_bm delete $index.0 [list $index.0 lineend] + $listbox_project_files_bm delete $target.0 [list $target.0 lineend] + if {$trg_bm} { + $listbox_project_files_bm image create $index.0 \ + -image ::ICONS::16::bookmark \ + -align center + } + if {$idx_bm} { + $listbox_project_files_bm image create $target.0 \ + -image ::ICONS::16::bookmark \ + -align center + } + } + } + + ## Move down current item in project filelist + # @return void + public method filelist_prj_move_down {} { + # Local variables + set item [$listbox_project_files selection get] ;# Item ID + set index [$listbox_project_files index $item] ;# Item index + set items [llength [$listbox_project_files items]] ;# Number of items in listbox + set target [expr {$index + 1}] ;# Target index + + # Check if the item can be moved + if {$index == $items} {return} + + # Move item in listbox + $listbox_project_files move $item $target + # Move item in list of bookmarks and icon border + if {[lindex $project_files_bookmarks $index] != [lindex $project_files_bookmarks $target]} { + # Determinate bookmark flag for source and target index + set trg_bm [lindex $project_files_bookmarks $target] + set idx_bm [lindex $project_files_bookmarks $index] + # Move item in list of bookmarks + lset project_files_bookmarks $target [lindex $project_files_bookmarks $index] + lset project_files_bookmarks $index $trg_bm + # Move item in icon border + incr target + incr index + $listbox_project_files_bm delete $index.0 [list $index.0 lineend] + $listbox_project_files_bm delete $target.0 [list $target.0 lineend] + if {$trg_bm} { + $listbox_project_files_bm image create $index.0 \ + -image ::ICONS::16::bookmark \ + -align center + } + if {$idx_bm} { + $listbox_project_files_bm image create $target.0 \ + -image ::ICONS::16::bookmark \ + -align center + } + } + } + + ## Move to top current item in project filelist + # @return void + public method filelist_prj_move_top {} { + # Determinate index of the current item + set item [$listbox_project_files selection get] + set index [$listbox_project_files index $item] + + # Check if the item can be moved + if {$index == 0} {return} + + # Move item in listbox + $listbox_project_files move $item 0 + # Move item in list of bookmarks + set bm [lindex $project_files_bookmarks $index] + set project_files_bookmarks [lreplace $project_files_bookmarks $index $index] + set project_files_bookmarks [linsert $project_files_bookmarks 0 $bm] + # Move item in icon border + incr index + $listbox_project_files_bm delete $index.0 $index.0+1l + $listbox_project_files_bm insert 1.0 "\n" + if {$bm} { + $listbox_project_files_bm image create 1.0 \ + -image ::ICONS::16::bookmark \ + -align center + } + } + + ## Move to bottom current item in project filelist + # @return void + public method filelist_prj_move_bottom {} { + # Determinate index of the current item and end index + set item [$listbox_project_files selection get] + set index [$listbox_project_files index $item] + set items [llength [$listbox_project_files items]] + + # Check if the item can be moved + if {$index == $items} {return} + + # Move item in listbox + $listbox_project_files move $item [expr {$items - 1}] + # Move item in list of bookmarks + set bm [lindex $project_files_bookmarks $index] + set project_files_bookmarks [lreplace $project_files_bookmarks $index $index] + lappend project_files_bookmarks $bm + # Move item in icon border + incr index + set end [llength $project_files_bookmarks] + $listbox_project_files_bm delete $index.0 $index.0+1l + $listbox_project_files_bm insert $end.0 "\n" + if {$bm} { + $listbox_project_files_bm image create $end.0 \ + -image ::ICONS::16::bookmark \ + -align center + } + } + + ## Open file from ListBox of project files + # Takes any set of arguments and discards them + # @return void + public method filelist_project_file_open args { + if {$frozen} {return} + + # Local varibales + set item [$listbox_project_files selection get] ;# Item ID + set record [$listbox_project_files itemcget $item -data] ;# Item data + + # If the file is already opended -- abort + if {[llength $record] == 4} {return} + + # Parse item data + set ri 0 + foreach var {file_name active ro file_line file_md5 file_path file_BMs file_BPs eol enc sh notes} { + set $var [lindex $record $ri] + incr ri + } + + # Check for file existence + if {![file exists $file_path$file_name]} { + tk_messageBox \ + -title [mc "File not found"] \ + -icon error \ + -type ok \ + -message [mc "File %s could not be located at the specified location." $file_name] + return + } + + # Verify file MD5 hash + if {[catch { + if {[md5::md5 -hex -file $file_path$file_name] != $file_md5} { + tk_messageBox \ + -icon warning \ + -type ok \ + -title [mc "File changed"] \ + -message [mc "File \"%s\" was modified since last project save\nTime: %s" $file_name [clock format [file mtime $file_path$file_name] -format {%T %D}]] + } + }]} then { + tk_messageBox \ + -icon warning \ + -type ok \ + -title [mc "Unknown error"] \ + -message [mc "Raised error during md5 checking file %s. Maybe md5 extension is not correctly loaded." $file_name] + } + + # Open the file + if {[openfile $file_path$file_name 0 . $enc $eol $ro 0 $sh] != {}} { + set i [llength $editors] + incr i -1 + set editor [lindex $editors $i] + rightPanel_switch_editor $i + $this todo_switch_editor $i + $editor import_line_markers_data $file_BMs $file_BPs + $editor goto $file_line + switch_to_last + incr i + + $this set_file_notes_data $notes + } + + # Adjust listbox of opened files + $listbox_project_files itemconfigure $item \ + -font $opened_file_font -fg {#000000} -data [list $file_path$file_name $eol $enc $ro] + + # Reevaluate iconbar + FileList_project_disEna_buttons + } + + ## Close file in ListBox of project files + # @return void + public method filelist_project_file_close {} { + # Determinate filename + set item [$listbox_project_files selection get] + set filename [$listbox_project_files itemcget $item -data] + if {[llength $filename] > 4} {return} + + # Determinate editor index + set filename [lindex $filename 0] + set idx 0 + foreach editor $editors { + if {[$editor cget -fullFileName] == $filename} {break} + incr idx + } + + # Close the editor + editor_close 1 $idx + FileList_project_disEna_buttons + } + + ## Remove file from the project ListBox + # @return void + public method filelist_remove_file_from_project {} { + # Determinate item ID + set item [$listbox_project_files selection get] + set index [$listbox_project_files index $item] + # Remove item from the ListBox + $listbox_project_files delete $item + # Remove item from icon border and list of bookmarks + $listbox_project_files_bm delete [expr {$index + 1}].0 [expr {$index + 2}].0 + set project_files_bookmarks [lreplace $project_files_bookmarks $index $index] + # Select the next item + set end [llength [$listbox_project_files items]] + incr end -1 + if {$index > $end} { + set index $end + } + if {$index != -1} { + $listbox_project_files selection set \ + [$listbox_project_files items $index] + } + # Reevaluate icon bar + FileList_project_disEna_buttons + } + + ## Append the current file to the project + # @return void + public method filelist_append_to_prj {} { + # Index of the current file + set idx [lsearch $file_descriptors [$listbox_opened_files selection get]] + # Reference to editor object + set editor [lindex $editors $idx] + + # Check if the file isn't already part of the project + set fullFileName [$editor cget -fullFileName] + if {$fullFileName == {} || [getItemNameFromProjectList $fullFileName] != {}} { + return + } + + # Adjust ListBox of project files + $listbox_project_files insert end #auto \ + -font $opened_file_font \ + -fg {#000000} \ + -text [$editor cget -filename] \ + -data [list $fullFileName \ + [lindex $file_eol $idx] \ + [lindex $file_encoding $idx] \ + [lindex $file_ro_mode $idx] \ + ] + + # Adjust icon border + if {[llength $project_files_bookmarks]} { + $listbox_project_files_bm insert end "\n" + } + lappend project_files_bookmarks 0 + + } + + ## Translate full filename to item ID (in project files ListBox) + # @parm String fullFileName - full file name + # @return String - item ID or '{}' + private method getItemNameFromProjectList {fullFileName} { + # Get list of project file items + set items [$listbox_project_files items] + + # Search for the given filename + foreach item $items { + # Determinate item data + set data [$listbox_project_files itemcget $item -data] + + # Opened file + if {[llength $data] < 5} { + if {[lindex $data 0] == $fullFileName} { + return $item + } + + # Unopened file + } { + if { "[lindex $data 5][lindex $data 0]" == $fullFileName} { + return $item + } + } + } + + # Failed + return {} + } + + ## Change encoding in the current editor + # @return void + public method change_encoding {} { + if {$splitted && $selectedView} { + set idx $actualEditor2 + } { + set idx $actualEditor + } + if {[lindex $file_encoding $idx] == ${::editor_encoding}} { + return + } + + # Configure editor + set original_encoding [lindex $file_encoding $idx] + lset file_encoding $idx ${::editor_encoding} + [lindex $editors $idx] configure -encoding ${::editor_encoding} + if {![filelist_reload_file]} { + set ::editor_encoding $original_encoding + lset file_encoding $idx $original_encoding + [lindex $editors $idx] configure -encoding $original_encoding + } { + # Configure list of project files + set filename [[lindex $editors $idx] cget -fullFileName] + foreach item [$listbox_project_files items] { + set data [$listbox_project_files itemcget $item -data] + if {[lindex $data 0] == $filename} { + lset data 2 ${::editor_encoding} + $listbox_project_files itemconfigure $item -data $data + break + } + } + } + } + + ## Change EOL in the current editor + # @return void + public method change_EOL {} { + if {$splitted && $selectedView} { + set idx $actualEditor2 + } { + set idx $actualEditor + } + if {[lindex $file_eol $idx] == ${::editor_EOL}} { + return + } + + # Configure editor + lset file_eol $idx ${::editor_EOL} + [lindex $editors $idx] configure -eol ${::editor_EOL} + + # Configure list of project files + set filename [[lindex $editors $idx] cget -fullFileName] + foreach item [$listbox_project_files items] { + set data [$listbox_project_files itemcget $item -data] + if {[lindex $data 0] == $filename} { + lset data 1 ${::editor_EOL} + $listbox_project_files itemconfigure $item -data $data + break + } + } + } + + ## Change RO mode in the current editor + # @return void + public method switch_editor_RO_MODE {} { + if {$splitted && $selectedView} { + set idx $actualEditor2 + } { + set idx $actualEditor + } + if {[lindex $file_ro_mode $idx] == ${::editor_RO_MODE}} { + return + } + + # Configure editor + lset file_ro_mode $idx ${::editor_RO_MODE} + [lindex $editors $idx] change_RO_MODE ${::editor_RO_MODE} + + # Configure list of project files + set filename [[lindex $editors $idx] cget -fullFileName] + foreach item [$listbox_project_files items] { + set data [$listbox_project_files itemcget $item -data] + + # Unknown bug workaround :-( + if {[llength $data] < 4} { + puts "data == {$data}" ;# Dump + lappend data {} + } + + if {[lindex $data 0] == $filename} { + lset data 3 ${::editor_RO_MODE} + $listbox_project_files itemconfigure $item -data $data + break + } + } + } + + ## Adjust scrollbar for listbox of opened files + # @parm Float frac0 - 1st fraction + # @parm Float frac0 - 2nd fraction + # @return void + public method filelist_o_scrollbar_set {frac0 frac1} { + # Hide scrollbar + if {$frac0 == 0 && $frac1 == 1} { + if {$o_scrollbar_visible} { + pack forget $opened_files_scrollbar + set o_scrollbar_visible 0 + } + # Show scrollbar + } { + if {!$o_scrollbar_visible} { + pack $opened_files_scrollbar \ + -side left \ + -fill y \ + -before $listbox_opened_files_bm + set o_scrollbar_visible 1 + } + # Adjust icon border + $listbox_opened_files_bm yview moveto $frac0 + # Adjust scrollbar + $opened_files_scrollbar set $frac0 $frac1 + } + } + + ## Scroll synchronously listbox of opened files and its icon border + # @parm List - arguments for subcommand yview + # @return void + public method filelist_o_scroll args { + eval "$listbox_opened_files yview $args" + eval "$listbox_opened_files_bm yview $args" + } + + ## Adjust scrollbar for listbox of opened files + # @parm Float frac0 - 1st fraction + # @parm Float frac0 - 2nd fraction + # @return void + public method filelist_p_scrollbar_set {frac0 frac1} { + # Hide scrollbar + if {$frac0 == 0 && $frac1 == 1} { + if {$p_scrollbar_visible} { + pack forget $project_files_scrollbar + set p_scrollbar_visible 0 + } + # Show scrollbar + } { + if {!$p_scrollbar_visible} { + pack $project_files_scrollbar \ + -side left \ + -fill y \ + -before $listbox_project_files_bm + set p_scrollbar_visible 1 + } + # Adjust icon border + $listbox_project_files_bm yview moveto $frac0 + # Adjust scrollbar + $project_files_scrollbar set $frac0 $frac1 + } + } + + ## Scroll synchronously listbox of project files and its icon border + # @parm List - arguments for subcommand yview + # @return void + public method filelist_p_scroll args { + eval "$listbox_project_files yview $args" + eval "$listbox_project_files_bm yview $args" + } + + ## Validator function for search entry in tab of opened files + # @parm String content - String which to search for (in listbox of opened files) + # @return Bool - always 1 + public method filelist_opened_search {content} { + # Empty input string + if {$content == {}} { + $opened_search_clear_button configure -state disabled + $opened_search_entry configure -style TEntry + opened_files_unhighlight_item + return 1 + } + + # Enable clear button + $opened_search_clear_button configure -state normal + + # Search the listbox + foreach item [$listbox_opened_files items] { + if {![string first $content [$listbox_opened_files itemcget $item -text]]} { + $opened_search_entry configure -style StringFound.TEntry + opened_files_highlight_item $item + return 1 + } + } + + # Search failed + $opened_search_entry configure -style StringNotFound.TEntry + return 1 + } + + + ## Highlight item in listbox of opened files + # @parm String item - item ID + # @return void + private method opened_files_highlight_item {item} { + opened_files_unhighlight_item + set opened_files_highlighted_item $item + set opened_files_hg_item_fg_clr [$listbox_opened_files itemcget $item -fg] + $listbox_opened_files itemconfigure $item -indent 10 -fg {#00DD00} + $listbox_opened_files see $item + } + + ## Clear highlightion for currently highlighted item in listbox of opened files + # @return void + private method opened_files_unhighlight_item {} { + # If no item highlighted -> abort + if {$opened_files_highlighted_item == {}} { + return + } + + # Unhighlight item + $listbox_opened_files itemconfigure \ + $opened_files_highlighted_item \ + -indent 0 -fg $opened_files_hg_item_fg_clr + set opened_files_hg_item_fg_clr {} + set opened_files_highlighted_item {} + } + + ## Validator function for search entry in tab of project files + # @parm String content - String which to search for (in listbox of project files) + # @return Bool - always 1 + public method filelist_project_search {content} { + # Empty input string + if {$content == {}} { + $project_search_clear_button configure -state disabled + $project_search_entry configure -style TEntry + project_files_unhighlight_item + return 1 + } + + # Enable clear button + $project_search_clear_button configure -state normal + + # Search the listbox + foreach item [$listbox_project_files items] { + if {![string first $content [$listbox_project_files itemcget $item -text]]} { + $project_search_entry configure -style StringFound.TEntry + project_files_highlight_item $item + return 1 + } + } + + # Search failed + $project_search_entry configure -style StringNotFound.TEntry + return 1 + } + + ## Highlight item in listbox of project files + # @parm String item - item ID + # @return void + private method project_files_highlight_item {item} { + project_files_unhighlight_item + set project_files_highlighted_item $item + set project_files_hg_item_fg_clr [$listbox_project_files itemcget $item -fg] + $listbox_project_files itemconfigure $item -indent 10 -fg {#00DD00} + $listbox_project_files see $item + } + + ## Clear highlightion for currently highlighted item in listbox of project files + # @return void + private method project_files_unhighlight_item {} { + # If no item highlighted -> abort + if {$project_files_highlighted_item == {}} { + return + } + + # Unhighlight item + $listbox_project_files itemconfigure \ + $project_files_highlighted_item \ + -indent 0 -fg $project_files_hg_item_fg_clr + set project_files_hg_item_fg_clr {} + set project_files_highlighted_item {} + } + + ## Binding for virtual event '<<ListboxSelect>>' for listbox of project files + # Clear search entry and unhighlight currently highlighted item (if any) + # @return void + public method project_files_listbox_select {} { + $project_search_entry delete 0 end + $this FileList_project_disEna_buttons + } + + ## Add/Remove bookmark to/from item in listbox of opened files + # @parm Int x - Relative position in icon border (X axis) + # @parm Int y - Relative position in icon border (Y axis) + # @return void + public method filelist_opened_bookmark_xy {x y} { + opened_files_bookmark [expr {int([$listbox_opened_files_bm index @$x,$y]) - 1}] + } + + ## Add/Remove bookmark to/from item in listbox of opened files + # Affects currently selected item + # @return void + public method filelist_o_bookmark {} { + opened_files_bookmark [$listbox_opened_files index \ + [$listbox_opened_files selection get]] + } + + ## Add/Remove bookmark to/from item in listbox of opened files + # @parm Int line - Target line (begins from zero) + # @return void + public method opened_files_bookmark {line} { + # Check for allowed range + if {$line >= [llength $opened_files_bookmarks]} { + return + } + + set page [lindex [$listbox_opened_files items] $line] + + # Remove bookmark + if {[lindex $opened_files_bookmarks $line]} { + lset opened_files_bookmarks $line 0 + incr line + $listbox_opened_files_bm delete $line.0 [list $line.0 lineend] + + set ext [string trimleft [file extension [$listbox_opened_files itemcget $page -text]] {.}] + if {$ext == {h}} { + set icon {source_h} + } elseif {$ext == {c}} { + set icon {source_c} + } elseif {$ext == {cxx} || $ext == {cpp} || $ext == {cc}} { + set icon {source_cpp} + } elseif {$ext == {asm}} { + set icon {asm} + } else { + set icon {ascii} + } + $filetabs_nb itemconfigure $page -image ::ICONS::16::$icon + + # Add bookmark + } { + lset opened_files_bookmarks $line 1 + incr line + $listbox_opened_files_bm image create $line.0 \ + -image ::ICONS::16::bookmark \ + -align center + + $filetabs_nb itemconfigure $page -image ::ICONS::16::bookmark + } + + $listbox_opened_files_bm tag add center 0.0 end + } + + ## Invoke icon border popup menu -- list of opened files + # @parm Int x - Abolute position in icon border (X axis) + # @parm Int y - Abolute position in icon border (Y axis) + # @parm Int x - Relative position in icon border (X axis) + # @parm Int y - Relative position in icon border (Y axis) + # @return void + public method filelist_opened_bm_popup_menu {X Y x y} { + set pmenu_cline [expr {int([$listbox_opened_files_bm index @$x,$y]) - 1}] + set bookmark [lindex $opened_files_bookmarks $pmenu_cline] + tk_popup $IB_o_menu $X $Y + } + + ## Add/Remove bookmark to/from item in listbox of project files + # @parm Int x - Relative position in icon border (X axis) + # @parm Int y - Relative position in icon border (Y axis) + # @return void + public method filelist_project_bookmark_xy {x y} { + project_files_bookmark [expr {int([$listbox_project_files_bm index @$x,$y]) - 1}] + } + + ## Add/Remove bookmark to/from item in listbox of project files + # Affects currently selected item + # @return void + public method filelist_p_bookmark {} { + project_files_bookmark [$listbox_project_files index \ + [$listbox_project_files selection get]] + } + + ## Add/Remove bookmark to/from item in listbox of project files + # @parm Int line - Target line (begins from zero) + # @return void + public method project_files_bookmark {line} { + # Check for allowed range + if {($line < 0) || ($line >= [llength $project_files_bookmarks])} { + return + } + + # Remove bookmark + if {[lindex $project_files_bookmarks $line]} { + lset project_files_bookmarks $line 0 + incr line + $listbox_project_files_bm delete $line.0 [list $line.0 lineend] + # Add bookmark + } { + lset project_files_bookmarks $line 1 + incr line + $listbox_project_files_bm image create $line.0 \ + -image ::ICONS::16::bookmark \ + -align center + } + + $listbox_project_files_bm tag add center 0.0 end + } + + ## Invoke icon border popup menu -- list of project files + # @parm Int x - Abolute position in icon border (X axis) + # @parm Int y - Abolute position in icon border (Y axis) + # @parm Int x - Relative position in icon border (X axis) + # @parm Int y - Relative position in icon border (Y axis) + # @return void + public method filelist_project_bm_popup_menu {X Y x y} { + set pmenu_cline [expr {int([$listbox_project_files_bm index @$x,$y]) - 1}] + set bookmark [lindex $project_files_bookmarks $pmenu_cline] + tk_popup $IB_p_menu $X $Y + } + + ## Clear flag "command line on" + # @return void + public method cmd_line_off {} { + set editor_command_line_on 0 + if {$splitted} { + [lindex $editors $actualEditor2] cmd_line_force_off + } + [lindex $editors $actualEditor] cmd_line_force_off + } + + ## Set flag "command line on" + # All editors in current project will focus on command line + # @return void + public method cmd_line_on {} { + set editor_command_line_on 1 + if {$splitted} { + [lindex $editors $actualEditor2] cmd_line_force_on + } + [lindex $editors $actualEditor] cmd_line_force_on + + if {$splitted && $selectedView} { + [lindex $editors $actualEditor2] cmd_line_focus 1 + } { + [lindex $editors $actualEditor] cmd_line_focus 1 + } + } + + ## Split editor vertical + # @return void + public method split_vertical {} { + split_editor 1 + } + + ## Split editor horizontal + # @return void + public method split_horizontal {} { + split_editor 0 + } + + ## Close current view (if editor is splitted) + # If editor is already splitted this procedure will do nothing + # @return void + public method close_current_view {editor_object} { + if {!$splitted} {return} + + # Save current sash position + if {$pwin_orient == {vertical}} { + set idx 1 + } { + set idx 0 + } + set multiview_sash_pos [lindex [$multiview_paned_win sash coord 0] $idx] + + # Unmap paned window and the second pages manager and remap the first pages manager + $multiview_paned_win forget $pagesManager2 + $multiview_paned_win forget $pagesManager + pack forget $multiview_paned_win + pack $pagesManager -fill both -expand 1 + + # Configure all editor status bar popup menus + foreach editor $editors { + $editor configure_statusbar_menu 1 0 {} {} + } + + # Determinate which editor will be visible now + if {$editor_object != {}} { + set editor_object [lsearch $editors $editor_object] + if {$editor_object == $actualEditor2} { + set selectedView 1 + } { + set selectedView 0 + } + } + + # Insure than the choosen editor (see above) is (in)visible + if {!$selectedView} { + $listbox_opened_files selection set [lindex $file_descriptors $actualEditor2] + } + set selectedView 0 + set splitted 0 + set actualEditor2 -1 + switchfile + } + + ## Syntax highlight changed from editor + # @parm Object editor_object - New active editor object reference + # @parm Int lang - -1 == unknown; 0 == Assembly language; 1 == C language + # @return void + public method filelist_editor_sh_changed {editor_object lang} { + lset file_sh [lsearch $editors $editor_object] $lang + } + + ## Change active view if editor is splitted + # If editor is already splitted this procedure will do nothing + # @parm Object editor_object - New active editor object reference + # @return void + public method filelist_editor_selected {editor_object} { + if {!$splitted} {return} + + # Search for the given object + set idx [lsearch $editors $editor_object] + if {$idx == $actualEditor} { + set selectedView 0 + } elseif {$idx == $actualEditor2} { + set selectedView 1 + } + rightPanel_switch_editor_vars $idx + $this todo_switch_editor_vars $idx + + # Adjust selection in list of opened files + set item [lindex $file_descriptors $idx] + $listbox_opened_files selection set $item + catch {$listbox_opened_files itemconfigure $lastItem -image {}} + $listbox_opened_files itemconfigure $item -image ::ICONS::16::2_rightarrow + set lastItem $item + + update + $filetabs_nb raise [lindex $file_descriptors $idx] + $filetabs_nb see [lindex $file_descriptors $idx] + rightPanel_switch_page $idx + $this todo_switch_editor $idx + listBox_disEna_buttons $item $editor_object + ::X::adjust_title + ::X::adjust_mainmenu_and_toolbar_to_editor \ + ${::editor_RO_MODE} [expr {[$editor_object get_language] == 1}] + } + + ## Split editor vertical or horizontal + # If editor is already splitted this procedure will do nothing + # @parm Bool vert_or_horz - 1 == Vertical; 0 == Horizontal + # @return void + private method split_editor {vert_or_horz} { + if {$splitted} {return} + + # Determinate orientation + if {$vert_or_horz} { + set pwin_orient {horizontal} + } { + set pwin_orient {vertical} + } + $multiview_paned_win configure -orient $pwin_orient + + # Validate sash position + if {!$multiview_sash_pos} { + set multiview_sash_pos [expr {[winfo width $pagesManager] / 2}] + } + + # Unmap current pages manager and remap it with the second one into paned window + pack forget $pagesManager + pack $multiview_paned_win -fill both -expand 1 + $multiview_paned_win add $pagesManager + $multiview_paned_win add $pagesManager2 -after $pagesManager + + # Configure minimum size for panes + if {$vert_or_horz} { + set minsize 300 + } { + set minsize 80 + } + $multiview_paned_win paneconfigure $pagesManager -minsize $minsize + $multiview_paned_win paneconfigure $pagesManager2 -minsize $minsize + + # Move paned window sash + update idle + if {$pwin_orient == {vertical}} { + $multiview_paned_win sash place 0 0 $multiview_sash_pos + } { + $multiview_paned_win sash place 0 $multiview_sash_pos 0 + } + + # Configure status bar popup menu for all opened editors + foreach editor $editors { + $editor configure_statusbar_menu 0 1 {} {} + } + + # Show up some editor in the second view + set splitted 1 + set selectedView 0 + set len [llength $file_descriptors] + if {$len > 1} { + if {$actualEditor < ($len - 1)} { + set actualEditor2 [expr {$actualEditor + 1}] + } { + set actualEditor2 0 + } + } { + set selectedView 1 + editor_new + set selectedView 0 + } + pack [[lindex $editors $actualEditor2] cget -ed_sc_frame] \ + -in $pagesManager2 -fill both -expand 1 + } + + ## Sort items in list of opened files or project files + # @parm Char by - {S} == Size; {U} == URL; {N} == Name + # @parm Bool opened_project - 1 == List of opened files; 0 == List of project files + # @return void + public method sort_file_list {by opened_project} { + if {$opened_project} { + set listbox $listbox_opened_files + set bookmarks_text $listbox_opened_files_bm + set bookmarks_var {opened_files_bookmarks} + } { + set listbox $listbox_project_files + set bookmarks_text $listbox_project_files_bm + set bookmarks_var {project_files_bookmarks} + } + + # Determinate list of values (strings or integers) to sort + set items {} ;# List of values to sort + set num_of_items 0 ;# Length of items + foreach item [$listbox items] { + switch -- $by { + {N} { ;# For sorting by name + lappend items [$listbox itemcget $item -text] + } + {U} { ;# For sorting by URL + set data [$listbox itemcget $item -data] + if {!$opened_project} { + # Unopened file + if {[llength $data] > 4} { + set data [lindex $data 5] + + # Opened file + } { + set data [lindex $data 0] + } + } + lappend items $data + } + {S} { ;# For sorting by size + set path [$listbox itemcget $item -data] + if {!$opened_project} { + # Unopened file + if {[llength $path] > 4} { + set path [lindex $path 5] + + # Opened file + } { + set path [lindex $path 0] + } + } + set size 0 + catch { + set size [file size $path] + } + lappend items $size + } + } + incr num_of_items + } + + # List of item indexes in new order (e.g. {0 2 1 3 4 5 7 6}) + set new_order {} + for {set i 0} {$i < $num_of_items} {incr i} { + lappend new_order $i + } + + ## Sort lists items and new_order using Bouble Sort + # By name of URL (string comparison) + if {$by == {N} || $by == {U}} { + for {set i 1} {$i < $num_of_items} {incr i} { + for {set j 1; set k 0} {$j < $num_of_items} {incr j; incr k} { + if {[string compare [lindex $items $k] [lindex $items $j]] < 0} { + set tmp [lindex $items $k] + lset items $k [lindex $items $j] + lset items $j $tmp + + set tmp [lindex $new_order $k] + lset new_order $k [lindex $new_order $j] + lset new_order $j $tmp + } + } + } + # By size (integer comparison) + } { + for {set i 1} {$i < $num_of_items} {incr i} { + for {set j 1; set k 0} {$j < $num_of_items} {incr j; incr k} { + if {[lindex $items $k] > [lindex $items $j]} { + set tmp [lindex $items $k] + lset items $k [lindex $items $j] + lset items $j $tmp + + set tmp [lindex $new_order $k] + lset new_order $k [lindex $new_order $j] + lset new_order $j $tmp + } + } + } + } + + # Reorder list of bookmarks and + #+ determinate list of item descriptors in the new order. + #+ No GUI will be affected + set new_items_order {} + set bookmarks_new {} + set bookmarks_org [subst "\$$bookmarks_var"] + for {set i 0} {$i < $num_of_items} {incr i} { + set idx [lindex $new_order $i] + lappend new_items_order [$listbox items $idx] + lappend bookmarks_new [lindex $bookmarks_org $idx] + } + set $bookmarks_var $bookmarks_new + + # Adjust GUI to the new order + $listbox reorder $new_items_order + $bookmarks_text delete 1.0 end + foreach bm $bookmarks_new { + if {$bm} { + $bookmarks_text image create insert \ + -image ::ICONS::16::bookmark \ + -align center + } + $bookmarks_text insert end "\n" + } + } + + ## Open selected file with an external editor + # @parm Bool o_p - 1 == opened file; 0 == project file + # @parm String command - Command to execute the editor + # @return void + public method filelist_open_with {o_p command} { + # Determinate filename + if {$o_p} { + set item [$listbox_opened_files selection get] + if {![$listbox_opened_files exists $item]} { + return + } + set filename [$listbox_opened_files itemcget $item -data] + } { + set item [$listbox_project_files selection get] + if {![$listbox_project_files exists $item]} { + return + } + set data [$listbox_project_files itemcget $item -data] + if {[llength $data] < 5} { + set filename [lindex $data 0] + } { + set filename "[lindex $data 5][lindex $data 0]" + } + } + + # Adjust editor command + if {$command == {other}} { + set command [open_with_other] + } + if {$command == {}} { + return + } + + # Start external editor + if {[catch { + exec $command "$filename" & + }]} { + tk_messageBox \ + -parent . \ + -icon error \ + -type ok \ + -title [mc "Program not found"] \ + -message [mc "Unable to execute \"%s\"" $command] + } + } + + ## Open dialog "Open with other editor" and return text entered by user + # @return String - Command which executes exernal editor + private method open_with_other {} { + set ::FileList::open_with_cnfr 0 + + # Create toplevel window + set win [toplevel .open_with_other_dlg -class {Open with ...} -bg {#EEEEEE}] + + # Create label, entryBox and horizontal separator + pack [label $win.lbl -text [mc "Enter command to execute:"]] -fill x -anchor w -padx 5 + pack [ttk::entry $win.ent \ + -textvariable ::FileList::open_with \ + -width 0 \ + ] -fill x -padx 10 -anchor w +# pack [ttk::separator $win.sep -orient horizontal] -fill x -padx 5 -pady 10 + + bind $win.ent <Return> "grab release $win; destroy $win" + bind $win.ent <KP_Enter> "grab release $win; destroy $win" + + # Create button frame + set buttonFrame [frame $win.buttonFrame] + pack [ttk::button $buttonFrame.ok \ + -text [mc "Ok"] \ + -compound left \ + -image ::ICONS::16::ok \ + -command " + set ::FileList::open_with_cnfr 1 + grab release $win + destroy $win + " \ + ] -side left + pack [ttk::button $buttonFrame.cancel \ + -text [mc "Cancel"] \ + -compound left \ + -image ::ICONS::16::button_cancel \ + -command " + grab release $win + destroy $win + " \ + ] -side left + pack $buttonFrame -side bottom -padx 5 -pady 5 -anchor e + + # Set window attributes + wm iconphoto $win ::ICONS::16::terminal + wm title $win [mc "Open with other ..."] + wm minsize $win 320 80 + wm transient $win . + catch {grab $win} + wm protocol $win WM_DELETE_WINDOW " + grab release $win + destroy $win + " + raise $win + update + $win.ent selection range 0 end + focus $win.ent + tkwait window $win + + # Return result + if {${::FileList::open_with_cnfr}} { + return ${::FileList::open_with} + } { + return {} + } + } + + ## Kill childern + # @return void + public method filelist_kill_childern {} { + foreach editor $editors { + $editor kill_childern + } + } + + ## Focus and conditionaly open editor with the specified filename + # @parm String filename - Name of file + # @parm Bool suppress_error - Suppress error messages + # @return Bool - 1 == Success; 0 == Fail + public method fucus_specific_editor {filename suppress_error} { + + # Search list of opened files + foreach item [$listbox_opened_files items] { + if {$filename == [$listbox_opened_files itemcget $item -text]} { + $listbox_opened_files selection set $item + switchfile + return 1 + } + } + # Search list of project files + foreach item [$listbox_project_files items] { + if {$filename == [$listbox_project_files itemcget $item -text]} { + $listbox_project_files selection set $item + filelist_project_file_open + return 1 + } + } + + # Display error message + if {!$suppress_error} { + tk_messageBox \ + -parent . \ + -type ok \ + -icon warning \ + -title [mc "File not found"] \ + -message [mc "Unable to find \"%s\" in list of opened files or project files" $filename] + } + return 0 + } + + ## Move simulator pointer in editor + # - Switch to specified editor and go to specified line + # @parm List line_info - Line information number {Line_number File_number} + # @retun void + public method move_simulator_line {line_info} { + set line_number [lindex $line_info 0] + set file_number [lindex $line_info 1] + + if {$line_number == {}} { + return + } + + if {[$this cget -programming_language]} { + $this cvarsview_load_local_variables [lindex $line_info 2] [lindex $line_info 3] + } + + # Switch file + if {$file_number != {} && $simulator_editor != $file_number} { + # Gain target file name + set file_name [$this simulator_get_filename $file_number] + + # Search for the given file and try to switch to it + if {$file_switching_enabled || $simulator_editor == -1} { + foreach item [$listbox_opened_files items] { + if {$file_name != [$listbox_opened_files itemcget $item -data]} { + continue + } + + $listbox_opened_files selection set $item + if {$simulator_editor_obj != {}} { + $simulator_editor_obj disable + $listbox_opened_files itemconfigure [lindex \ + $file_descriptors [lsearch -ascii -exact \ + $editors $simulator_editor_obj \ + ] \ + ] -fg {#000000} + } + $listbox_opened_files itemconfigure $item -fg {#FF0000} + set simulator_editor_obj [lindex $editors \ + [lsearch -ascii -exact $file_descriptors $item] \ + ] + $simulator_editor_obj freeze + $simulator_editor_obj move_simulator_line $line_number + switchfile + set simulator_editor $file_number + return + } + } + Sbar [mc "Simulator: unable to switch to file: '%s'" $file_name] + + # Move simulator pointer directly + } elseif {$simulator_editor_obj != {}} { + $simulator_editor_obj move_simulator_line $line_number + } + } + + ## Get editor object used by simulator + # @return Object - Editor object + public method filelist_get_simulator_editor_obj {} { + return $simulator_editor_obj + } + + ## Set "auto file switch" lock + # @parm Object from_obj - Editor object from which this procedure is called + # @parm Bool new_state - New state of the lock + # @return void + public method set_editor_lock {from_obj new_state} { + foreach editor $editors { + if {$editor == $from_obj} { + continue + } + $editor set_lock $new_state + } + set file_switching_enabled [expr {!$new_state}] + } + + ## Get value of "auto file switch lock" + # This lock disables automatic file switching during sumulation + # @return Bool - 1 == unlocked; 0 == locked + public method get_file_switching_enabled {} { + return $file_switching_enabled + } + + ## Redraw panel pane + # @return void + public method leftpanel_redraw_pane {} { + update idle + if {$PanelVisible != 0} { + $parent sash place 0 $PanelSize 0 + } + } + + ## Get object reference for the current editor + # @return Object - Active editor + public method get_current_editor_object {} { + if {$splitted && $selectedView} { + set editor_num $actualEditor2 + } { + set editor_num $actualEditor + } + return [lindex $editors $editor_num] + } + + ## Show or hide the tab bar + # @return void + public method show_hide_tab_bar {} { + # Show + if {${::CONFIG(SHOW_EDITOR_TAB_BAR)}} { + if {![winfo ismapped $filetabs_frm]} { + if {$splitted} { + set before $multiview_paned_win + } { + set before $pagesManager + } + pack $filetabs_frm -fill x -before $before + + filelist_adjust_size_of_tabbar + } + # Hide + } { + if {[winfo ismapped $filetabs_frm]} { + pack forget $filetabs_frm + } + } + } + + ## Special purpose method (see the usage in the code) + # It should be used to ensure that the height of the tab bat is not too big + # @return void + public method filelist_adjust_size_of_tabbar {} { + $filetabs_nb see [lindex [$filetabs_nb pages] 0] + update + catch { + $filetabs_nb.c configure -height 20 + } + $filetabs_nb see [$filetabs_nb raise] + + # Keep editor nice after adjustment of filestab height + if {!${::Editor::editor_to_use}} { + [get_current_editor_object] scroll scroll +0 lines + } + } + + ## Call method Configure in both editors + # @return void + public method ensure_that_both_editors_are_properly_initialized {} { + if {$splitted} { + update + [lindex $editors $actualEditor] Configure + [lindex $editors $actualEditor2] Configure + } + } +} +set ::FileList::ask__append_file_to_project ${::CONFIG(ASK_ON_FILE_OPEN)} diff --git a/lib/leftpanel/fsbrowser.tcl b/lib/leftpanel/fsbrowser.tcl new file mode 100755 index 0000000..0a28d82 --- /dev/null +++ b/lib/leftpanel/fsbrowser.tcl @@ -0,0 +1,1164 @@ +#!/usr/bin/tclsh +# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net ) + +############################################################################ +# Copyright (C) 2007-2009 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. # +############################################################################ + +# -------------------------------------------------------------------------- +# DESCRIPTION +# Implements file system browser for the left panel +# -------------------------------------------------------------------------- + +class FSBrowser { + + # Definition of popup menu for filesystem browser, part: configure + common FSMENU_CONFIGURE { + {cascade "Sorting" 0 "" .sorting false 1 { + {radiobutton "By Name" "" {::KIFSD::FSD::config(sorting)} + {name} {filelist_fsb_reload} 3 + "Sort files by name"} + {radiobutton "By Date" "" {::KIFSD::FSD::config(sorting)} + {date} {filelist_fsb_reload} 3 + "Sort files by date"} + {radiobutton "By Size" "" {::KIFSD::FSD::config(sorting)} + {size} {filelist_fsb_reload} 3 + "Sort files by size"} + {separator} + {checkbutton "Reverse" "" + {::KIFSD::FSD::config(reverse_sorting)} 1 0 0 + {filelist_fsb_reload} "Decremental sorting"} + {checkbutton "Case insensitive" "" + {::KIFSD::FSD::config(case_insensitive)} 1 0 0 + {filelist_fsb_reload} "Sorting mode ASCII / Dictionary"} + }} + {checkbutton "Show hidden files" "" + {::KIFSD::FSD::config(show_hidden_files)} 1 0 5 + {filelist_fsb_reload} "Show / Ignore files starting with dot"} + } + + # Definition of popup menu for filesystem browser, part: listbox + common FSMENU_LISTBOX { + {command {Up} {} 0 "filelist_fsb_up" {up} + "Go to parent folder"} + {command {Back} {} 0 "filelist_fsb_back" {left} + "Go back in history"} + {command {Forward} {} 0 "filelist_fsb_forward" {right} + "Go forward in history"} + {separator} + {command {Home} {} 0 "filelist_fsb_gohome" {gohome} + "Go to your home folder"} + {command {Reload} {} 1 "filelist_fsb_reload" {reload} + "Reload filelist"} + {separator} + {command {Rename} {} 0 "filelist_fsb_rename" {edit} + "Rename file"} + {command {Delete} {} 0 "filelist_fsb_delete" {editdelete} + "Delete file"} + {command {New folder} {} 0 "filelist_fsb_new_folder" {folder_new} + "Create new directory"} + {command {Bookmark folder} {} 0 "filelist_fsb_bookmark_this" {bookmark_add} + "Bookmark the current directory"} + {separator} + {command {Properties} {} 0 "filelist_fsb_properties" {} + "Show file properties"} + } + + # Definition of popup menu for filesystem browser, part: bookmarks + common FSMENU_BOOKMARKS { + {command {Add bookmark} {} 0 "filelist_fsb_add_bookmark" + {bookmark_add} "Bookmark the current folder"} + {command {Edit bookmarks} {} 0 "filelist_fsb_edit_bookmarks" + {bookmark} "Invoke bookmark editor"} + {separator} + } + + ## PRIVATE + private variable fs_browser_selected_item {} ;# Item selected by popup menu for filesystem browser + private variable fs_browser_selection_in_P 0 ;# Procedure "filelist_fsb_select" in progress + private variable fs_browser_listbox_top_frame ;# Top frame of filesystem browser + private variable forward_history {} ;# List of forward history (filesystem browser) + private variable back_history {} ;# List of backward history (filesystem browser) + private variable fs_browser_current_dir ;# Current directory (filesystem browser) + private variable fs_browser_conf_menu ;# ID of filesystem browser configuration menu + private variable fs_browser_dir_ok ;# Button: Confirm location + private variable fs_browser_listbox_menu ;# ID of popup menu for filesystem browser + private variable fs_browser_bm_menu ;# ID of bookmarks popup menu (filesystem browser) + private variable fs_browser_toolbar ;# ID of filesystem browser toolbar + private variable fs_browser_dir ;# ComboBox: Current directory + private variable fs_browser_listbox ;# ListBox: Files & Directories + private variable fs_browser_listbox_v_scrollbar ;# Vertical scrollbar for filesystem browser + private variable fs_browser_listbox_h_scrollbar ;# Horizontal scrollbar for filesystem browser + private variable fs_browser_filter ;# ComboBox: Filter + private variable item_menu_invoked 0 ;# Bool: Item menu request + # Current GLOB filter for filesystem browser + private variable fs_browser_current_mask ${::CONFIG(FS_BROWSER_MASK)} + + # Variables related to object initialization + private variable parent + private variable gui_initialized 0 + + constructor {} { + # Configure local ttk styles + ttk::style configure FSBrowser_RedBg.TCombobox \ + -fieldbackground {#FFDDDD} + ttk::style map FSBrowser_RedBg.TCombobox \ + -fieldbackground [list {readonly !readonly} {#FFDDDD}] + } + + destructor { + } + + ## Prepare object for creating its GUI + # @parm Widget _parent - GUI parent widget + # @return void + public method PrepareFSBrowser {_parent} { + set parent $_parent + set gui_initialized 0 + } + + ## Create GUI of tab "File system browser" + # @return void + public method CreateFSBrowserGUI {} { + if {$gui_initialized} {return} + set gui_initialized 1 + + set fs_browser_current_dir [$this cget -projectPath] + + # Toolbar + set fs_browser_toolbar [frame $parent.toolbar] + iconBarFactory $fs_browser_toolbar "$this " \ + [string range $fs_browser_toolbar 1 end] ::ICONS::16:: { + {up "Up" {up} {filelist_fsb_up} + "Go to parent folder"} + {back "Back" {left} {filelist_fsb_back} + "Back in history"} + {forward "Forward" {right} {filelist_fsb_forward} + "Forward in history"} + {separator} + {bookmark "Bookmark" {bookmark_toolbar} {filelist_fsb_popup_bm_menu} + "Bookmark menu"} + {current "Current document folder" {next} {filelist_fsb_current_doc_folder} + "Go to directory containing the current document"} + {configure "Configure" {configure} {filelist_fsb_popup_config_menu} + "Filesystem browser configuration menu"} + } + ${fs_browser_toolbar}forward configure -state disabled + ${fs_browser_toolbar}back configure -state disabled + + # Directory location bar + set fs_browser_dir_frame [frame $parent.dir_frame] + set fs_browser_dir [ttk::combobox $fs_browser_dir_frame.dir \ + -validatecommand [list $this filelist_fsb_validate_dir %P] \ + -width 1 \ + -values {} \ + -validate all \ + ] + bind $fs_browser_dir <Return> [list $this filelist_fsb_dir_ok] + bind $fs_browser_dir <KP_Enter> [list $this filelist_fsb_dir_ok] + bind $fs_browser_dir <<ComboboxSelected>> "$this filelist_fsb_dir_ok" + DynamicHelp::add $fs_browser_dir -text [mc "Current directory"] + setStatusTip -widget $fs_browser_dir \ + -text [mc "Directory location bar"] + set fs_browser_dir_ok [ttk::button $fs_browser_dir_frame.ok \ + -style Flat.TButton \ + -image ::ICONS::16::key_enter \ + -command [list $this filelist_fsb_dir_ok] \ + ] + DynamicHelp::add $fs_browser_dir_frame.ok -text [mc "Confirm directory location"] + setStatusTip -widget $fs_browser_dir_ok \ + -text [mc "Confirm directory location"] + pack $fs_browser_dir -fill x -expand 1 -side left + pack $fs_browser_dir_ok -side right -after $fs_browser_dir + + # ListBox of files and directories + set fs_browser_listbox_frame [frame $parent.lsbox_frame] + set fs_browser_listbox_top_frame [frame $fs_browser_listbox_frame.tp_frame] + set fs_browser_listbox [ListBox $fs_browser_listbox_top_frame.listbox \ + -bg white -highlightthickness 0 -selectmode single -bd 1 \ + -selectfill 1 -width 0 -height 10 -highlightcolor {#BBBBFF} \ + -selectbackground {#8888FF} -selectforeground black \ + -yscrollcommand "$this filelist_fsb_vscroll" \ + -xscrollcommand "$this filelist_fsb_hscroll" \ + ] + if {[winfo exists $fs_browser_listbox.c]} { + bind $fs_browser_listbox.c <Button-5> {%W yview scroll +5 units; break} + bind $fs_browser_listbox.c <Button-4> {%W yview scroll -5 units; break} + bind $fs_browser_listbox.c <ButtonRelease-3> \ + [list $this filelist_fsb_popup_listbox_menu %X %Y] + } + bind $fs_browser_listbox <<ListboxSelect>> "catch {$this filelist_fsb_select}" + $fs_browser_listbox bindText <ButtonRelease-3> \ + [list $this filelist_fsb_popup_listbox_item_menu %X %Y] + $fs_browser_listbox bindImage <ButtonRelease-3> \ + [list $this filelist_fsb_popup_listbox_item_menu %X %Y] + + # Scrollbars + set fs_browser_listbox_v_scrollbar [ttk::scrollbar \ + $fs_browser_listbox_top_frame.scrollbar \ + -orient vertical -command "$fs_browser_listbox yview" \ + ] + set fs_browser_listbox_h_scrollbar [ttk::scrollbar \ + $fs_browser_listbox_frame.scrollbar \ + -orient horizontal -command "$fs_browser_listbox xview" \ + ] + + pack $fs_browser_listbox -fill both -expand 1 -side left + pack $fs_browser_listbox_top_frame -fill both -expand 1 + + # GLOB Filter + set fs_browser_bottom_frame [frame $parent.bottom_frame] + set fs_browser_filter [ttk::combobox $fs_browser_bottom_frame.filter \ + -state readonly \ + -width 0 \ + -font ${::FileList::opened_file_font} \ + -values { + {*.asm - Assembler} + {*.inc - INC files} + {*.c - C source} + {*.h - C header} + {*.lst - Code listing} + {* - All files} + } \ + ] + bind $fs_browser_filter <Return> [list $this filelist_fsb_filter_ok] + bind $fs_browser_filter <KP_Enter> [list $this filelist_fsb_filter_ok] + bind $fs_browser_filter <<ComboboxSelected>> [list $this filelist_fsb_filter_ok] + DynamicHelp::add $fs_browser_filter -text [mc "Filter"] + setStatusTip -widget $fs_browser_filter \ + -text [mc "File filter"] + set val [lsearch -exact -ascii {{*.asm} {*.inc} {*.c} {*.h} {*}} $fs_browser_current_mask] + if {$val == -1} { + set val 0 + } + $fs_browser_filter current $val + pack $fs_browser_filter -fill x -expand 1 -side left + + # Pack componets of filesystem browser + pack $fs_browser_toolbar -anchor w + pack $fs_browser_dir_frame -fill x -pady 3 + pack $fs_browser_listbox_frame -fill both -expand 1 + pack $fs_browser_bottom_frame -fill x -pady 3 + + # Create popup menus + set fs_browser_conf_menu $parent.conf_menu + set fs_browser_listbox_menu $parent.listbox_menu + set fs_browser_bm_menu $parent.bm_menu + filelist_fsb_makePopupMenu + + # Initialize filesystem browser + filelist_fsb_change_dir $fs_browser_current_dir + filelist_fsb_refresh_bookmarks + } + + ## Popup bookmarks menu for filesystem browser + # @return void + public method filelist_fsb_popup_bm_menu {} { + set x [winfo rootx ${fs_browser_toolbar}bookmark] + set y [winfo rooty ${fs_browser_toolbar}bookmark] + incr y [winfo height ${fs_browser_toolbar}bookmark] + + tk_popup $fs_browser_bm_menu $x $y + } + + ## Popup configuration menu for filesystem browser + # @return void + public method filelist_fsb_popup_config_menu {} { + set x [winfo rootx ${fs_browser_toolbar}configure] + set y [winfo rooty ${fs_browser_toolbar}configure] + incr y [winfo height ${fs_browser_toolbar}configure] + + tk_popup $fs_browser_conf_menu $x $y + } + + ## Popup filesystem browser listbox menu + # @parm Int x - Relative horizontal position of mouse pointer + # @parm Int y - Relative vertical position of mouse pointer + # @return void + public method filelist_fsb_popup_listbox_menu {x y} { + # If item menu was invoked then abort + if {$item_menu_invoked} { + set item_menu_invoked 0 + return + } + + # Configure and popup the menu + set fs_browser_selected_item {} + foreach entry {Rename Delete Properties} { + $fs_browser_listbox_menu entryconfigure [::mc $entry] -state disabled + } + tk_popup $fs_browser_listbox_menu $x $y + } + + ## Popup filesystem browser listbox menu + # @parm Int x - Relative horizontal position of mouse pointer + # @parm Int y - Relative vertical position of mouse pointer + # @parm String item - Selected item (file of directory) + # @return void + public method filelist_fsb_popup_listbox_item_menu {x y item} { + if {[$fs_browser_listbox itemcget $item -text] == {..}} { + return + } + + # Configure and popup the menu + set item_menu_invoked 1 + foreach entry {Rename Delete Properties} { + $fs_browser_listbox_menu entryconfigure [::mc $entry] -state normal + } + set fs_browser_selected_item $item + tk_popup $fs_browser_listbox_menu $x $y + } + + ## Change current directory in filesystem browser + # @parm String dir - New directory location + # @return void + public method filelist_fsb_change_dir {dir} { + if {!$gui_initialized} {CreateFSBrowserGUI} + + if {$::MICROSOFT_WINDOWS} { + # Transform for instance "C:" to "C:/" + if {[regexp {^\w+:$} $dir]} { + append dir {/} + } + } + + # Check if the given directory is valid + if {![file exists $dir] || ![file isdirectory $dir]} { + tk_messageBox -parent . \ + -title [mc "Invalid directory"] \ + -type ok -icon warning \ + -message [mc "The specified directory does not exist:\n%s" $dir] + return + } + + # Normalize path and configure toolbar (history control) + set dir [file normalize $dir] + if {$dir != $fs_browser_current_dir} { + lappend back_history $fs_browser_current_dir + set forward_history {} + $fs_browser_listbox_menu entryconfigure [::mc "Forward"] -state disabled + $fs_browser_listbox_menu entryconfigure [::mc "Back"] -state normal + ${fs_browser_toolbar}forward configure -state disabled + ${fs_browser_toolbar}back configure -state normal + } + set fs_browser_current_dir $dir + + # Reload contents of browser ListBox + set tmp ${::KIFSD::FSD::config(detailed_view)} + set ::KIFSD::FSD::config(detailed_view) 0 + $fs_browser_listbox delete [$fs_browser_listbox items] + foreach file [::KIFSD::FSD::dir_file_cmd $dir $fs_browser_current_mask] { + + # Local variables + set filename {} ;# File name (if $file file) + set folder {} ;# Directory name (if $file is directory) + set fullname [lindex $file 0] ;# Full path + set text $fullname ;# Text to display + + # Determinate icon + switch -- [lindex $file 1] { + u { ;# Parent directory + set image {up} + set folder {..} + } + d { ;# Directory + set image {fileopen} + set folder $fullname + } + f { ;# File + set image {ascii} + set filename $fullname + } + } + + # Insert item into the listbox + $fs_browser_listbox insert end #auto \ + -text $text \ + -image ::ICONS::16::$image \ + -data [list $filename $folder] + } + set ::KIFSD::FSD::config(detailed_view) $tmp + + # Configure button "Up" + if {$dir == [file separator]} { + $fs_browser_listbox_menu entryconfigure [::mc "Up"] -state disabled + ${fs_browser_toolbar}up configure -state disabled + } { + $fs_browser_listbox_menu entryconfigure [::mc "Up"] -state normal + ${fs_browser_toolbar}up configure -state normal + } + + # Fill directory location 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 [::KIFSD::FSD::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}:/" + } + } + } + + $fs_browser_dir configure -values $values + $fs_browser_dir current 0 + $fs_browser_dir icursor end + catch { + $fs_browser_dir.e xview end + } + } + + ## Select file/directory to open + # This method should be connected to <<Selection>> event on FS browser ListBox + # @return void + public method filelist_fsb_select {} { + if {[$this is_frozen]} { + tk_messageBox \ + -parent . \ + -icon info \ + -type ok \ + -title [mc "Unable to compile"] \ + -message [mc "Unable to open source file while simulator is engaged."] + return + } + + if {$fs_browser_selection_in_P} {return} + set fs_browser_selection_in_P 1 + + # Determinate name of file/directory to open + set file [$fs_browser_listbox itemcget \ + [$fs_browser_listbox selection get] -data] + + # Open file + if {[lindex $file 0] != {}} { + set simplename $file + set file [file join $fs_browser_current_dir [lindex $file 0]] + + # Check if the file seems to be valid source code + if {![regexp {\.(asm|inc|c|h|cpp|cc|cxx|lst)$} $file] || ([file size $file] > 1048576)} { + set response [tk_messageBox \ + -parent . -type yesno \ + -icon warning \ + -title [mc "Open file %s" $simplename] \ + -message [mc "This file does not look like a source code.\nDo you really want to open it ?"] \ + ] + if {$response != {yes}} { + set fs_browser_selection_in_P 0 + return + } + } + + # Perform opening procedure + if {[$this openfile $file 1 . def def 0 0 {}] != {}} { + $this switch_to_last + update + $this editor_procedure {} parseAll {} + + # Make LST read only + if {[file extension $file] == {.lst}} { + set ::editor_RO_MODE 1 + $this switch_editor_RO_MODE + } + + ::X::recent_files_add 1 $file + } + + # Open directory + } { + filelist_fsb_change_dir \ + [file join $fs_browser_current_dir [lindex $file 1]] + } + set fs_browser_selection_in_P 0 + update + } + + ## Invoke dialog to edit FS browser bookmarks + # @return void + public method filelist_fsb_edit_bookmarks {} { + catch {delete object fsd} + KIFSD::FSD fsd + fsd edit_bookmarks + delete object fsd + } + + ## Synchronize bookmarks in FS browser with KIFSD (KI File selection dialog) + # This method shoul be called after FSD close + # @return void + public method filelist_fsb_refresh_bookmarks {} { + if {!$gui_initialized} {CreateFSBrowserGUI} + + # Clear current bookmarks entries + if {[$fs_browser_bm_menu index end] > 2} { + $fs_browser_bm_menu delete 3 end + } + # Create new bookmark entries + foreach dir ${::KIFSD::FSD::config(bookmarks)} { + $fs_browser_bm_menu add command \ + -label $dir -compound left \ + -image ::ICONS::16::fileopen \ + -command "$this filelist_fsb_change_dir {$dir}" + } + } + + ## Bookmark current directory + # @return void + public method filelist_fsb_add_bookmark {} { + lappend ::KIFSD::FSD::config(bookmarks) $fs_browser_current_dir + $fs_browser_bm_menu add command \ + -label $fs_browser_current_dir -compound left \ + -image ::ICONS::16::fileopen \ + -command "$this filelist_fsb_change_dir {$fs_browser_current_dir}" + } + + ## Bookmark directory selected by popup menu + # @return void + public method filelist_fsb_bookmark_this {} { + # No item selected -> bookmark current directory + if {$fs_browser_selected_item == {}} { + filelist_fsb_add_bookmark + return + } + + # Directory selected -> bookmark it + if {[lindex [$fs_browser_listbox itemcget $fs_browser_selected_item -data] 1] != {}} { + set tmp $fs_browser_current_dir + set fs_browser_current_dir [file join $fs_browser_current_dir \ + [$fs_browser_listbox itemcget $fs_browser_selected_item -text]] + filelist_fsb_add_bookmark + set fs_browser_current_dir $tmp + + # File selected -> bookmark current directory + } { + filelist_fsb_add_bookmark + } + } + + ## Reload filesystem browser contents + # @return void + public method filelist_fsb_reload {} { + if {!$gui_initialized} {CreateFSBrowserGUI} + filelist_fsb_change_dir $fs_browser_current_dir + } + + ## Go to parent directory (in FS browser) + # @return void + public method filelist_fsb_up {} { + filelist_fsb_change_dir [file join $fs_browser_current_dir {..}] + } + + ## Go back in history (in FS browser) + # @return void + public method filelist_fsb_back {} { + # Gain new directory location + set folder [lindex $back_history end] + if {$folder == {}} {return} + + # Adjust back and forward history + set back_history [lreplace $back_history end end] + lappend forward_history $fs_browser_current_dir + + # Make backup for history lists + set tmp_forw_hist $forward_history + set tmp_back_hist $back_history + + # Change current directory (go back in history) + filelist_fsb_change_dir $folder + + # Restore history lists + set forward_history $tmp_forw_hist + set back_history $tmp_back_hist + + # Configure toolbar and popup menu + if {![llength $back_history]} { + ${fs_browser_toolbar}back configure -state disabled + $fs_browser_listbox_menu entryconfigure [::mc "Back"] -state disabled + } { + ${fs_browser_toolbar}back configure -state normal + $fs_browser_listbox_menu entryconfigure [::mc "Back"] -state normal + } + $fs_browser_listbox_menu entryconfigure [::mc "Forward"] -state normal + ${fs_browser_toolbar}forward configure -state normal + } + + ## Go forward in history (in FS browser) + # @return void + public method filelist_fsb_forward {} { + # Gain new directory location + set folder [lindex $forward_history end] + if {$folder == {}} {return} + + # Adjust forward and back history + set forward_history [lreplace $forward_history end end] + lappend back_history $fs_browser_current_dir + + # Make backup for history lists + set tmp_forw_hist $forward_history + set tmp_back_hist $back_history + + # Change current directory (go forward in history) + filelist_fsb_change_dir $folder + + # Restore history lists + set forward_history $tmp_forw_hist + set back_history $tmp_back_hist + + # Configure toolbar and popup menu + if {![llength $forward_history]} { + ${fs_browser_toolbar}forward configure -state disabled + $fs_browser_listbox_menu entryconfigure [::mc "Forward"] -state disabled + } { + ${fs_browser_toolbar}forward configure -state normal + $fs_browser_listbox_menu entryconfigure [::mc "Forward"] -state normal + } + ${fs_browser_toolbar}back configure -state normal + $fs_browser_listbox_menu entryconfigure [::mc "Back"] -state normal + } + + ## Change current directory to the current document folder + # @return void + public method filelist_fsb_current_doc_folder {} { + # Determinate path to current document + set file [$this editor_procedure {} getFileName {}] + if {[lindex $file 0] != {}} { + set dir [lindex $file 0] + } { + set dir $projectPath + } + # Change current directory + filelist_fsb_change_dir $dir + } + + ## Rename selected file + # @return void + public method filelist_fsb_rename {} { + # Determina original and new name + set original [$fs_browser_listbox itemcget $fs_browser_selected_item -text] + set newname [$fs_browser_listbox edit $fs_browser_selected_item \ + [$fs_browser_listbox itemcget $fs_browser_selected_item -text]] + if {$newname == {}} { + return + } + + # Normalize file names (original and new) + set original [file join $fs_browser_current_dir $original] + set newname [file join $fs_browser_current_dir $newname] + + # Rename file/directory + if {[catch {file rename -force $original $newname}]} { + tk_messageBox \ + -parent . \ + -type ok \ + -icon warning \ + -title [mc "Permission denied"] \ + -message [mc "Unable to rename file:\n%s" $original] + } + + # Refresh browser + filelist_fsb_reload + } + + ## Delete selected file/directory + # @return void + public method filelist_fsb_delete {} { + set filename [$fs_browser_listbox itemcget $fs_browser_selected_item -text] + + if {[tk_messageBox \ + -parent . \ + -type yesno \ + -icon question \ + -title [mc "Delete file"] \ + -message [mc "Do you really want to delete file:\n%s" $filename]] + == + {yes} + } { + if {[catch {file delete -force -- [file join $fs_browser_current_dir $filename]}]} { + tk_messageBox \ + -parent . \ + -type ok \ + -icon warning \ + -title [mc "Permission denied"] \ + -message [mc "Unable to remove file:\n%s" $filename] + } + } + filelist_fsb_reload + } + + ## Invoke dialog: "Create new directory" (FS browser) + # @return void + public method filelist_fsb_new_folder {} { + # Create dialog window + set dialog [toplevel .new_dir_dialog -class {New folder} -bg {#EEEEEE}] + + # Create header + pack [label $dialog.header \ + -justify left \ + -text [mc "Create new folder in:\n%s" $fs_browser_current_dir] \ + ] -side top -anchor w -padx 15 -pady 5 + # Create EntryBox for name of new folder + pack [ttk::entry $dialog.entry -bg white \ + ] -side top -fill x -expand 1 -padx 5 -pady 5 + + # Create bottom button bar + set button_frame [frame $dialog.bottom] + # - Button: Clear + 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 + # - Button: OK + 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 + # - Button: Cancel + 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 + # Pack button frame + 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 . + grab $dialog + raise $dialog + focus -force $dialog.entry + tkwait window $dialog + } + + ## Create new directory (in FS browser) + # @return void + public method create_new_folder {} { + # Local variables + set dialog .new_dir_dialog ;# ID of dialog window + set folder [$dialog.entry get] ;# Name of folder to create + set error 0 ;# Bool: error occured + + # Check for folder name validity + if {$folder == {}} { + set error 1 + } + + # Create new folder + if {$error || [catch {file mkdir [file join $fs_browser_current_dir $folder]}]} { + tk_messageBox -parent $dialog -icon warning -type ok \ + -title [mc "Unable to create folder"] \ + -message [mc "Unable to create the specified folder"] + } { + # Remove dialog and reload browser + grab release $dialog + destroy $dialog + filelist_fsb_reload + } + } + + ## Invoke dialog: "File/Directory properties" (in FS browser) + # @return void + public method filelist_fsb_properties {} { + ## Determinate item properties + # - filename + # - full path + # - size + # - permissions + # - owner + group + # - modification time + # - access time + set name [$fs_browser_listbox itemcget $fs_browser_selected_item -data] + if {[lindex $name 0] == {}} { + set name [lindex $name 1] + set type [mc "Directory"] + } { + set name [lindex $name 0] + set type [mc "File"] + } + set fullname [file join $fs_browser_current_dir $name] + if {![file exists $fullname]} { + tk_messageBox \ + -parent . \ + -type ok \ + -icon warning \ + -title [mc "Unknown Error"] \ + -message [mc "This file apparently does not exist"] + return + } + set size [file size $fullname] + append size { B} + set modified [clock format [file mtime $fullname] -format {%D %R}] + set accessed [clock format [file atime $fullname] -format {%D %R}] + 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 componets + set dialog [toplevel .properties_dialog -class {File properties} -bg {#EEEEEE}] ;# Toplevel window itself + set nb [NoteBook $dialog.nb -bg {#EEEEEE}] ;# NoteBook + set bottom_frame [frame $dialog.bottom_frame] ;# Button frame + + # Create tabs in NoteBook + $nb insert end general -text [mc "General"] + if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights) + $nb insert end permission -text [mc "Permissions"] + } + $nb raise general + + # + ## Create componets of tab "GENERAL" + # + set frame [frame [$nb getframe general].frame] + pack $frame -side top -anchor n -fill x -expand 1 + set row 0 + grid [label $frame.lbl_$row \ + -text [mc "Name:"] -anchor w \ + ] -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 + incr row + foreach lbl {Type Location Size Modified Accessed} \ + value [list $type $fs_browser_current_dir $size $modified $accessed] \ + { + grid [label $frame.lbl_$row \ + -text "$lbl:" -anchor w \ + ] -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 componets of tab "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 {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 $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"] \ + ] -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"] \ + ] -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 componets of 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 + pack [ttk::button $bottom_frame.cancel \ + -text [mc "Cancel"] \ + -compound left \ + -image ::ICONS::16::button_cancel \ + -command " + grab release $dialog + destroy $dialog" \ + ] + + # 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 . + grab $dialog + raise $dialog + tkwait window $dialog + } + + ## Binding to OK button in item properties dialog + # @parm String dialog - ID of dialog toplevel window + # @parm String file - Name of file related to the dialog + # @return void + public method properties_ok {dialog file} { + set error 0 + + # Determinate permissions (in decimal) + if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights) + set perm 0 + 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 + } + } + # Change permissions + 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] + + # Set new file name + if {${::KIFSD::FSD::item_properties(name)} != [file tail $file]} { + if {[catch { + file rename -force -- \ + $file [file join $dir \ + ${::KIFSD::FSD::item_properties(name)}]}] + } { + set error 1 + tk_messageBox -type ok -icon warning -parent $dialog \ + -title [mc "Permission denied"] \ + -message [mc "Unable to rename file:\n%s\n\t=>\n%s" [file tail $file] ${::KIFSD::FSD::item_properties(name)}] + } + filelist_fsb_reload + } + + # If no error occured, close dialog + if {!$error} { + grab release $dialog + destroy $dialog + } + } + + ## Go to home directory + # @return void + public method filelist_fsb_gohome {} { + filelist_fsb_change_dir {~} + } + + ## Confirm new filter settings + # @return void + public method filelist_fsb_filter_ok {} { + set fs_browser_current_mask [$fs_browser_filter current] + switch -- $fs_browser_current_mask { + 0 {set fs_browser_current_mask {*.asm}} + 1 {set fs_browser_current_mask {*.inc}} + 2 {set fs_browser_current_mask {*.c}} + 3 {set fs_browser_current_mask {*.h}} + 4 {set fs_browser_current_mask {*.lst}} + 5 {set fs_browser_current_mask {*}} + } + filelist_fsb_reload + } + + ## Validate content of directory location ComboBox + # @parm String content - Directory to validate + # @return Bool - always true + public method filelist_fsb_validate_dir {content} { + if {[file exists $content] && [file isdirectory $content]} { + $fs_browser_dir_ok configure -state normal + $fs_browser_dir configure -style TCombobox + + # Fill directory location 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}:/" + } + } + } + $fs_browser_dir configure -values $values + } { + $fs_browser_dir_ok configure -state disabled + $fs_browser_dir configure -style FSBrowser_RedBg.TCombobox + } + + return 1 + } + + ## Confirm directory location in ComboBox + # @return void + public method filelist_fsb_dir_ok {} { + filelist_fsb_change_dir [$fs_browser_dir get] + } + + ## Verticaly scroll FileSystem browser ListBox + # @parm Float frac0 - Fraction of top visible area + # @parm Float frac1 - Fraction of bottom visible area + # @return void + public method filelist_fsb_vscroll {frac0 frac1} { + # All content is in visible area -> unmap scrollbar + if {$frac0 == 0 && $frac1 == 1} { + if {[winfo ismapped $fs_browser_listbox_v_scrollbar]} { + pack forget $fs_browser_listbox_v_scrollbar + update + } + + # Otherwise -> create scrollbar + } { + if {![winfo ismapped $fs_browser_listbox_v_scrollbar]} { + pack $fs_browser_listbox_v_scrollbar \ + -after $fs_browser_listbox \ + -fill y -expand 1 + update + } + $fs_browser_listbox_v_scrollbar set $frac0 $frac1 + } + } + + ## Horizontaly scroll FileSystem browser ListBox + # @parm Float frac0 - Fraction of top visible area + # @parm Float frac1 - Fraction of bottom visible area + # @return void + public method filelist_fsb_hscroll {frac0 frac1} { + # All content is in visible area -> unmap scrollbar + if {$frac0 == 0 && $frac1 == 1} { + if {[winfo ismapped $fs_browser_listbox_h_scrollbar]} { + pack forget $fs_browser_listbox_h_scrollbar + update + } + + # Otherwise -> create scrollbar + } { + if {![winfo ismapped $fs_browser_listbox_h_scrollbar]} { + pack $fs_browser_listbox_h_scrollbar \ + -after $fs_browser_listbox_top_frame \ + -side bottom -fill x -expand 0 + update + } + $fs_browser_listbox_h_scrollbar set $frac0 $frac1 + } + } + + ## Recreate popup menus + # @return void + public method filelist_fsb_makePopupMenu {} { + if {!$gui_initialized} {return} + if {[winfo exists $fs_browser_conf_menu]} { + destroy $fs_browser_conf_menu + } + if {[winfo exists $fs_browser_listbox_menu]} { + destroy $fs_browser_listbox_menu + } + if {[winfo exists $fs_browser_bm_menu]} { + destroy $fs_browser_bm_menu + } + + menuFactory $FSMENU_CONFIGURE $fs_browser_conf_menu 0 "$this " 0 {} + menuFactory $FSMENU_LISTBOX $fs_browser_listbox_menu 0 "$this " 0 {} + menuFactory $FSMENU_BOOKMARKS $fs_browser_bm_menu 0 "$this " 0 {} + + if {![llength $back_history]} { + $fs_browser_listbox_menu entryconfigure [::mc "Back"] -state disabled + } + if {![llength $forward_history]} { + $fs_browser_listbox_menu entryconfigure [::mc "Forward"] -state disabled + } + } + + ## Get current file mask + # @return String - Current mask + public method fs_browser_get_current_mask {} { + return $fs_browser_current_mask + } +} diff --git a/lib/leftpanel/sfrwatches.tcl b/lib/leftpanel/sfrwatches.tcl new file mode 100755 index 0000000..ba47dc5 --- /dev/null +++ b/lib/leftpanel/sfrwatches.tcl @@ -0,0 +1,620 @@ +#!/usr/bin/tclsh +# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net ) + +############################################################################ +# Copyright (C) 2007-2009 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. # +############################################################################ + +# -------------------------------------------------------------------------- +# DESCRIPTION +# Provides SFR watches for left panel +# -------------------------------------------------------------------------- + +class SFRWatches { + + ## COMMON + # Font for addresses and register names + common main_font [font create \ + -family $::DEFAULT_FIXED_FONT \ + -size -14 \ + -weight bold \ + ] + # Just another font but not bold + common roman_font [font create \ + -family $::DEFAULT_FIXED_FONT \ + -size -14 \ + ] + # Fonr for register entry boxes + common entry_font [font create \ + -family $::DEFAULT_FIXED_FONT \ + -size -12 \ + -weight bold \ + ] + + ## PRIVATE + private variable text_widget ;# Widget: Text widget containing SFR watches + private variable scrollbar ;# Widget: Scrollbar for $text_widget + private variable search_entry ;# Widget: Search entry box at the bottom of the panel + private variable search_clear_but ;# Widget: Button "Clear" at the bottom of the panel + private variable main_left_frame ;# Widget: Frame containing $text_widget and its header label + private variable entry_count 0 ;# Int: Number of SFRs + private variable validation_ena 1 ;# Bool: SFR entry box validation enabled + private variable haddr2idx ;# Array: $haddr2idx($hex_addr) --> row_in_text_widget - 1 + private variable addr2idx ;# Array: $addr2idx($dec_addr) --> row_in_text_widget - 1 + private variable reg2idx ;# Array: $addr2idx($register_name_upppercase) --> row_in_text_widget - 1 + private variable last_selected_line 0 ;# Int: Selected row in the text widget + private variable search_ena 1 ;# Bool: Search enabled + private variable menu ;# Widget: Popup menu for the text widget + + # Variables related to object initialization + private variable parent ;# Parent GUI object (tempotary variable) + private variable gui_initialized 0 ;# GUI ready + + constructor {} { + } + + destructor { + if {$gui_initialized} { + menu_Sbar_remove $menu + } + } + + ## Prepare object for creating its GUI + # @parm Widget _parent - parent container (some frame) + # @return void + public method PrepareSFRWatches {_parent} { + set parent $_parent + set gui_initialized 0 + } + + ## Initialize SFR watches GUI + # @return void + public method CreateSFRWatchesGUI {} { + if {$gui_initialized} {return} + set gui_initialized 1 + + set validation_ena 0 + create_GUI + fill_gui + set validation_ena 1 + + if {![$this is_frozen]} { + sfr_watches_disable + } + } + + ## Create entry box to embedd in the text widget + # @parm Int i - Entry index (row - 1) + # @parm String type - Entry type (hex or dec) + # @parm Int addr - SFR address (128..255) + # @parm String reg - SFR name (e.g. PSW) + # @return Widget - Created entry box + private method create_entry {i type addr reg} { + # Determinate entry box width + if {$type == {hex}} { + set width 2 + } { + set width 3 + } + + # Create entry widget + set entry [entry $text_widget.${type}_entry_${i} \ + -width $width -font $entry_font \ + -bg {#FFFFFF} -validate all \ + -takefocus 0 -highlightthickness 0 \ + -disabledbackground {#FFFFFF} \ + -vcmd "$this sfr_watches_validate ${type} $addr %P" \ + -bd 0 -justify right \ + ] + + # Perform name correction for accumulators + if {$reg == {A} || $reg == {B}} { + append reg {_hex} + } + + # Set event bindins + bind $entry <Motion> {help_window_show %X %Y} + bind $entry <Leave> {help_window_hide} + bind $entry <FocusIn> "$this unmark_entry $addr" + bind $entry <Enter> "$this create_help_window_ram $reg" + bind $entry <Button-1> "$this sfr_watches_select_line 0 [expr {$i + 1}] $type" + bind $entry <Key-Up> "$this sfr_watches_up $type 1" + bind $entry <Key-Down> "$this sfr_watches_down $type 1" + bind $entry <Key-Next> "$this sfr_watches_down $type 4" + bind $entry <Key-Prior> "$this sfr_watches_up $type 4" + bind $entry <Button-4> "$text_widget yview scroll -5 units" + bind $entry <Button-5> "$text_widget yview scroll +5 units" + if {$type == {hex}} { + bind $entry <Key-Right> " + focus $text_widget.dec_entry_${i} + $text_widget.dec_entry_${i} selection clear + update + $text_widget.dec_entry_${i} icursor 0" + } { + bind $entry <Key-Left> " + focus $text_widget.hex_entry_${i} + $text_widget.hex_entry_${i} selection clear + update + $text_widget.dec_entry_${i} icursor end" + } + + return $entry + } + + ## Complite GUI initialization (load all SFRs into the text widget) + # @return void + private method fill_gui {} { + set entry_count 0 + set validation_ena 0 + + # Iterate over defined SFRs ({{addr name} ... }) + foreach reg [$this simulator_get_sfrs] { + # Determinate hexadecimal address + set addr [lindex $reg 0] + set hex_addr [format %X $addr] + if {[string length $hex_addr] == 1} { + set hex_addr "0$hex_addr" + } elseif {[string length $hex_addr] == 3} { + set hex_addr [string replace $hex_addr 0 0] + } + # Determinate register name and make it 8 characters long + set reg [lindex $reg 1] + set reg_org $reg + switch -- $reg { + SBUFR { + set reg {SBUF R} + } + SBUFT { + set reg {SBUF T} + } + default { + set reg $reg + } + } + append reg [string repeat { } [expr {8 - [string length $reg]}]] + + # Register this SFR + set haddr2idx($hex_addr) $entry_count + set addr2idx($addr) $entry_count + set reg2idx($reg_org) $entry_count + + # Insert address and name into the text widget + $text_widget insert end $hex_addr + $text_widget insert end { } + $text_widget insert end $reg + + # Set highlighting tags + set line [expr {int([$text_widget index insert])}] + $text_widget tag add tag_addr $line.0 $line.2 + $text_widget tag add tag_name $line.3 $line.11 + + # Create and insert embedded entry boxes + set entry [create_entry $entry_count hex $addr $reg_org] + $entry insert 0 [$this getSfr $addr] + $text_widget window create end -window $entry -pady 0 + $text_widget insert end { } + set entry [create_entry $entry_count dec $addr $reg_org] + $entry insert 0 [$this getSfrDEC $addr] + $text_widget window create end -window $entry -pady 0 + + # Finalize this row + $text_widget insert end "\n" + incr entry_count + } + + # Remove the last line (empty line) and disable the text widget + $text_widget delete end-1l end + set validation_ena 1 + } + + ## Set value of SFR at current line to the specified value + # @parm String value - Hexadecimal value + # @return void + public method sfr_watches_set_current_to {value} { + set idx [expr {$last_selected_line - 1}] + set addr [lindex [$this simulator_get_sfrs] [list $idx 0]] + + $this setSfr $addr $value + $this Simulator_GUI_sync S $addr + } + + ## Create GUI elements of this panel + # @return void + private method create_GUI {} { + # Create and pack panel frames + set main_frame [frame $parent.main_frame] + set main_left_frame [frame $main_frame.left] + pack $main_left_frame -side left -fill both -expand 1 + pack $main_frame -fill both -expand 1 + + # Create text widget and its header + pack [label $main_left_frame.header_label \ + -anchor w -justify left -pady 0 -padx 2 \ + -fg ${::Simulator_GUI::small_color} \ + -font ${::Simulator_GUI::smallfont} \ + -text "[mc {Register}] [mc {HEX}] [mc {DEC}]" -width 1 \ + ] -fill x -pady 0 -anchor nw + set text_widget [text $main_left_frame.text \ + -bg {#FFFFFF} -font $roman_font -bd 2 \ + -width 0 -height 0 -wrap none \ + -yscrollcommand "$this sfr_watches_scroll_set" \ + -cursor left_ptr \ + ] + + # Create popup menu for the text widget + set menu $text_widget.menu + menuFactory { + {command {Set to 0x00} {} 9 "sfr_watches_set_current_to 00" + {} "Set this register to 0"} + {command {Set to 0xFF} {} 9 "sfr_watches_set_current_to FF" + {} "Set this register to 255"} + } $menu 0 "$this " 0 {} + + # Set event bindings for the text widget + bindtags $text_widget $text_widget + foreach event { + <ButtonRelease-1> <B1-Enter> <B1-Leave> + <B2-Motion> <Button-5> <Button-4> + <MouseWheel> + } { + bind $text_widget $event [bind Text $event] + } + bind $text_widget <Button-1> \ + "$this sfr_watches_select_line 0 \[expr {int(\[%W index @%x,%y\])}\] hex" + bind $text_widget <ButtonRelease-3> \ + "$this sfr_watches_select_line 0 \[expr {int(\[%W index @%x,%y\])}\] hex + tk_popup $menu %X %Y" + + # Pack the text widget and create its scrollbar + pack $text_widget -fill both -expand 1 + set scrollbar [ttk::scrollbar $main_frame.scrollbar \ + -orient vertical -command "$text_widget yview" \ + ] + + # Create bottom frame (search bar) + set search_frame [frame $parent.top] + pack [label $search_frame.lbl \ + -text [mc "Search:"] \ + ] -side left + set search_entry [ttk::entry $search_frame.entry \ + -width 0 \ + -validate all \ + -validatecommand "$this sfr_watches_search_validate %P" \ + ] + pack $search_entry -side left -fill x -expand 1 + set search_clear_but [ttk::button $search_frame.button \ + -style Flat.TButton \ + -state disabled \ + -image ::ICONS::16::clear_left \ + -command "$search_entry delete 0 end" \ + ] + pack $search_clear_but -side right -after $search_entry + pack $search_frame -fill x + + # Create highlighting tags for the text widget + $text_widget tag configure tag_addr \ + -foreground {#000000} -font $main_font + $text_widget tag configure tag_name \ + -foreground {#0000DD} -font $main_font + $text_widget tag configure tag_curLine \ + -background ${::RightPanel::selection_color_dark} + } + + ## Adjust scrollbar + # @parm Float frac0 - 1st fraction + # @parm Float frac1 - 2nd fraction + # @return void + public method sfr_watches_scroll_set {frac0 frac1} { + # Hide scrollbar + if {$frac0 == 0 && $frac1 == 1} { + if {[winfo ismapped $scrollbar]} { + pack forget $scrollbar + } + # Show scrollbar + } { + if {![winfo ismapped $scrollbar]} { + pack $scrollbar \ + -side left \ + -fill y \ + -after $main_left_frame + } + $scrollbar set $frac0 $frac1 + } + } + + ## Validate content of search entry box at the bottom bar + # @parm String string - String to validate + # @return Bool - Always 1 + public method sfr_watches_search_validate {string} { + # Check if searching is enabled + if {!$search_ena} {return 1} + + # Adjust state of clear button (+ clear selection on the text widget) + if {$string == {}} { + $search_clear_but configure -state disabled + $search_entry configure -style TEntry + sfr_watches_select_line 1 0 hex + return 1 + } { + $search_clear_but configure -state normal + } + + set string [string toupper $string] + + # Perform case insensitive search for the given chunk of SFR name and address + foreach arr {reg2idx haddr2idx} { + foreach str [lsort -ascii -increasing [array names $arr]] { + # Search successful + if {![string first $string $str]} { + $search_entry configure -style StringFound.TEntry + sfr_watches_select_line 1 [expr {[subst "\${${arr}(${str})}"] + 1}] hex + return 1 + } + } + } + + # Search failed + $search_entry configure -style StringNotFound.TEntry + return 1 + } + + ## Select line in the text widget + # @parm Bool search - Invoked form search validator (do not clear search entry box) + # @parm Int line - Target line + # @parm String type - Entry box to select (hex or dec) + # @return void + public method sfr_watches_select_line {search line type} { + + # Unselect the last selected line and determinate cursor position + if {$last_selected_line} { + $text_widget tag remove tag_curLine 0.0 end + $this simulator_reg_label_set_highlighted $last_selected_line 0 + incr last_selected_line -1 + foreach tp {dec hex} { + $text_widget.${tp}_entry_$last_selected_line selection clear + $text_widget.${tp}_entry_$last_selected_line configure \ + -bg {#FFFFFF} -disabledbackground {#FFFFFF} + } + set cursor [$text_widget.${type}_entry_$last_selected_line index insert] + } { + set cursor 0 + } + + # Adjust last selected line (if 0 the return) + set last_selected_line $line + if {!$line} { + return + } + + + # Highlight this line as selected in the text widget + $text_widget tag add tag_curLine \ + $last_selected_line.0 \ + $last_selected_line.0+1l + $text_widget see $last_selected_line.0 + + # Highlight SFR on this line in simulator control panel + $this simulator_reg_label_set_highlighted $last_selected_line 1 + + # Adjust background color for entry boxes at this line + incr line -1 + $text_widget.dec_entry_$line configure \ + -fg ${Simulator::normal_color} \ + -bg ${::RightPanel::selection_color_dark} \ + -disabledbackground ${::RightPanel::selection_color_dark} + $text_widget.hex_entry_$line configure \ + -fg ${Simulator::normal_color} \ + -bg ${::RightPanel::selection_color_dark} \ + -disabledbackground ${::RightPanel::selection_color_dark} + + # Clear search entry box and focus and entry box at this line + if {!$search} { + $text_widget.${type}_entry_$line icursor $cursor + $text_widget.${type}_entry_$line selection range 0 end + focus $text_widget.${type}_entry_$line + set search_ena 0 + $search_entry delete 0 end + set search_ena 1 + } + } + + ## Validator for SFR value entry boxes + # @parm String type - Entry box type (hex or dec) + # @parm Int addr - Register address + # @parm String value - String to validate + # @return Bool - Validation result + public method sfr_watches_validate {type addr value} { + # Prevent recursion + if {!$validation_ena} {return 1} + set validation_ena 0 + + # Validate value + if {$value == {}} { + set value 0 + } + if {$type == {hex}} { + if {![string is xdigit $value]} { + set validation_ena 1 + return 0 + } + set value [expr "0x$value"] + } { + if {![string is digit $value]} { + set validation_ena 1 + return 0 + } + } + if {$value > 255 || $value < 0} { + set validation_ena 1 + return 0 + } + + # Synchronize with engine and simulator control panel + $this setSfr $addr [format %X $value] + $this SimGUI_disable_sync + $this Simulator_GUI_sync S $addr + $this SimGUI_enable_sync + + # Synchronize with the other one entry box + if {$type == {hex}} { + $text_widget.dec_entry_$addr2idx($addr) delete 0 end + $text_widget.dec_entry_$addr2idx($addr) insert 0 $value + } { + set value [format %X $value] + if {[string length $value] == 1} { + set value "0$value" + } + $text_widget.hex_entry_$addr2idx($addr) delete 0 end + $text_widget.hex_entry_$addr2idx($addr) insert 0 $value + } + + # Done + set validation_ena 1 + return 1 + } + + ## Remove all SFRs for the text widget and unregister them + # @return void + private method clear_gui {} { + if {!$gui_initialized} {return} + + # Clear SFR name label highlight in simultor contol panel + if {$last_selected_line} { + $this simulator_reg_label_set_highlighted $last_selected_line 0 + } + + # Reset object variables + array unset haddr2idx + array unset addr2idx + array unset reg2idx + set last_selected_line 0 + set entry_count 0 + + # Clear the text widget + $text_widget delete 1.0 end + foreach wdg [$text_widget window names] { + destroy $wdg + } + } + + ## Set new value of certain SFR in this panel + # @parm Int addr - SFR address + # @parm Int new_val - New SFR value + # @return void + public method sfr_watches_sync {addr new_val} { + if {!$gui_initialized} {return} + + # Prevent recursion + if {!$validation_ena} {return} + set validation_ena 0 + + # Check if this SFR is avaliable here + if {[lsearch [array names addr2idx] $addr] == -1} { + set validation_ena 1 + return + } + + # Determinate references of HEX and DEC entry boxes + set hex_entry $text_widget.hex_entry_$addr2idx($addr) + set dec_entry $text_widget.dec_entry_$addr2idx($addr) + + # Highlight entry boxes + set org_val [$dec_entry get] + if {$org_val != $new_val} { + $hex_entry configure -fg ${::Simulator_GUI::hcolor} + $dec_entry configure -fg ${::Simulator_GUI::hcolor} + } + + # Set decimal value + $dec_entry delete 0 end + $dec_entry insert 0 $new_val + + # Set hexadecimal value + set new_val [format %X $new_val] + if {[string length $new_val] == 1} { + set new_val "0$new_val" + } + $hex_entry delete 0 end + $hex_entry insert 0 $new_val + + # Reenable entry box value validations + set validation_ena 1 + } + + ## Enable this panel + # @return vois + public method sfr_watches_enable {} { + if {!$gui_initialized} {return} + $menu entryconfigure [::mc "Set to 0x00"] -state normal + $menu entryconfigure [::mc "Set to 0xFF"] -state normal + for {set i 0} {$i < $entry_count} {incr i} { + $text_widget.hex_entry_$i configure -state normal + $text_widget.dec_entry_$i configure -state normal + } + } + + ## Disable this panel + # @return vois + public method sfr_watches_disable {} { + if {!$gui_initialized} {return} + $menu entryconfigure [::mc "Set to 0x00"] -state disabled + $menu entryconfigure [::mc "Set to 0xFF"] -state disabled + for {set i 0} {$i < $entry_count} {incr i} { + $text_widget.hex_entry_$i configure -state disabled + $text_widget.dec_entry_$i configure -state disabled + } + } + + ## This function shuld be call after processor was changed + # Reload avaliable SFRs + # @return void + public method sfr_watches_commit_new_sfr_set {} { + if {!$gui_initialized} {return} + clear_gui + fill_gui + } + + ## Move selected line up + # @parm String type - Which entry box should be selected (hex or dec) + # @parm Int lines - Number of lines to move by + # @return void + public method sfr_watches_up {type lines} { + set line $last_selected_line + incr line -$lines + if {$line <= 0} { + set line $entry_count + } + + sfr_watches_select_line 0 $line $type + } + + ## Move selected line down + # @parm String type - Which entry box should be selected (hex or dec) + # @parm Int lines - Number of lines to move by + # @return void + public method sfr_watches_down {type lines} { + set line $last_selected_line + incr line $lines + if {$line >= $entry_count} { + set line 0 + } + + sfr_watches_select_line 0 $line $type + } +} |