#---------------------------------------------------------- -*- tcl -*-
# Eskil, Preprocess dialog
#
# Copyright (c) 2004-2017, Peter Spjuth (peter.spjuth@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; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
#
#----------------------------------------------------------------------
#
# The format of the ::Pref(preprocessn) is:
# Flat list of stride 2, (name data)
# Data dict elements: preprocess active save
# Preprocess element is a flat list of stride 3 (RE sub side)
#
# There used to be a ::Pref(preprocess) with a different format, the new
# was named a bit different for compatibilty with saved preferences.
# Return active preprocess items as a flat list with stride 3
proc getActivePreprocess {top} {
set res {}
foreach {name data} $::Pref(preprocessn) {
if {[dict get $data active]} {
foreach {RE sub side} [dict get $data preprocess] {
lappend res $RE $sub $side
}
}
}
return $res
}
# Entry for adding preprocess from command line
proc addPreprocess {name RE sub side} {
set data {}
dict set data preprocess [list $RE $sub $side]
dict set data active 1
dict set data save 0
lappend ::Pref(preprocessn) $name $data
}
# Get the value used when saving preferences
proc getPreprocessSave {} {
set res {}
foreach {name data} $::Pref(preprocessn) {
if {[dict get $data save]} {
# Always save with active 0 for now.
# A user can edit the save file to have it by default.
dict set data active 0
lappend res $name $data
}
}
return $res
}
# This is called when Ok or Apply is pressed.
# Update preference from dialog contents.
proc EditPrefRegsubOk {top w item {keep 0}} {
set exa $::eskil($top,prefregexa)
set result {}
for {set t 1} {[info exists ::eskil($top,prefregexp$t)]} {incr t} {
set RE $::eskil($top,prefregexp$t)
set Sub $::eskil($top,prefregsub$t)
set l $::eskil($top,prefregleft$t)
set r $::eskil($top,prefregright$t)
set side ""
if {$l && !$r} { set side left }
if {!$l && $r} { set side right }
if {!$l && !$r} { continue }
if {$RE eq ""} continue
if {[catch {regsub -all -- $RE $exa $Sub _} err]} {
return
}
lappend result $RE $Sub $side
}
set ::TmpPref(preprocess,re,$item) $result
set ::TmpPref(preprocess,active,$item) 1
if {$keep} {
# Apply was pressed, also apply main dialog
# TODO: Get widgets right. Right now it does not matter
EditPrefPrepOk . $top 1
return
}
destroy $w
array unset ::eskil $top,prefregexp*
array unset ::eskil $top,prefregsub*
array unset ::eskil $top,prefregleft*
array unset ::eskil $top,prefregright*
}
# Update the example in the preprocess dialog
proc EditPrefRegsubUpdate {top args} {
set exal $::eskil($top,prefregexa)
set exar $::eskil($top,prefregexa)
set exal2 $::eskil($top,prefregexa2)
set exar2 $::eskil($top,prefregexa2)
set ok $::widgets($top,prefRegsubOk)
set app $::widgets($top,prefRegsubApply)
for {set t 1} {[info exists ::eskil($top,prefregexp$t)]} {incr t} {
set RE $::eskil($top,prefregexp$t)
set Sub $::eskil($top,prefregsub$t)
set l $::eskil($top,prefregleft$t)
set r $::eskil($top,prefregright$t)
if {$RE eq ""} continue
if {$l} {
if {[catch {regsub -all -- $RE $exal $Sub result} err]} {
set ::eskil($top,prefregresultl) "$t ERROR: $err"
$ok configure -state disabled
$app configure -state disabled
return
} else {
set exal $result
}
if {[catch {regsub -all -- $RE $exal2 $Sub result} err]} {
set ::eskil($top,prefregresultl2) "$t ERROR: $err"
$ok configure -state disabled
$app configure -state disabled
return
} else {
set exal2 $result
}
}
if {$r} {
if {[catch {regsub -all -- $RE $exar $Sub result} err]} {
set ::eskil($top,prefregresultr) "$t ERROR: $err"
$ok configure -state disabled
$app configure -state disabled
return
} else {
set exar $result
}
if {[catch {regsub -all -- $RE $exar2 $Sub result} err]} {
set ::eskil($top,prefregresultr2) "$t ERROR: $err"
$ok configure -state disabled
$app configure -state disabled
return
} else {
set exar2 $result
}
}
}
set ::eskil($top,prefregresultl2) $exal2
set ::eskil($top,prefregresultr2) $exar2
set ::eskil($top,prefregresultl) $exal
set ::eskil($top,prefregresultr) $exar
$ok configure -state normal
$app configure -state normal
}
# Add a new entry in the preprocess dialog
proc AddPrefRegsub {top parent} {
# Figure out next number to use
for {set t 1} {[winfo exists $parent.fr$t]} {incr t} {
#Empty
}
# Default values
if {![info exists ::eskil($top,prefregexp$t)]} {
set ::eskil($top,prefregexp$t) ""
set ::eskil($top,prefregsub$t) ""
set ::eskil($top,prefregleft$t) 1
set ::eskil($top,prefregright$t) 1
}
set w [ttk::frame $parent.fr$t -borderwidth 2 -relief groove -padding 3]
ttk::label $w.l1 -text "Regexp:" -anchor "w"
ttk::entryX $w.e1 -textvariable ::eskil($top,prefregexp$t) -width 60
ttk::label $w.l2 -text "Subst:" -anchor "w"
ttk::entryX $w.e2 -textvariable ::eskil($top,prefregsub$t)
ttk::checkbutton $w.cb1 -text "Left" -variable ::eskil($top,prefregleft$t)
ttk::checkbutton $w.cb2 -text "Right" -variable ::eskil($top,prefregright$t)
addBalloon $w.cb1 "Apply to left file"
addBalloon $w.cb2 "Apply to right file"
grid $w.l1 $w.e1 $w.cb1 -sticky we -padx 3 -pady 3
grid $w.l2 $w.e2 $w.cb2 -sticky we -padx 3 -pady 3
grid columnconfigure $w 1 -weight 1
pack $w -side "top" -fill x -padx 3 -pady 3
trace add variable ::eskil($top,prefregexp$t) write \
[list EditPrefRegsubUpdate $top]
trace add variable ::eskil($top,prefregsub$t) write \
[list EditPrefRegsubUpdate $top]
trace add variable ::eskil($top,prefregleft$t) write \
[list EditPrefRegsubUpdate $top]
trace add variable ::eskil($top,prefregright$t) write \
[list EditPrefRegsubUpdate $top]
}
# Editor for one item in ::Pref(preprocessn)
proc EditPrefRegsub {top item} {
set w $top.prefregsub
ToplevelForce $w "Preferences: Preprocess item"
ttk::button $w.b -text "Add" -command [list AddPrefRegsub $top $w]
# Result example part
if {![info exists ::eskil($top,prefregexa)]} {
set ::eskil($top,prefregexa) \
"An example TextString FOR_REGSUB /* Comment */"
set ::eskil($top,prefregexa2) \
"An example TextString FOR_REGSUB /* Comment */"
}
ttk::labelframe $w.res -text "Preprocessing result" -padding 3
ttk::label $w.res.l3 -text "Example 1:" -anchor "w"
ttk::entryX $w.res.e3 -textvariable ::eskil($top,prefregexa) -width 60
ttk::label $w.res.l4 -text "Result 1:" -anchor "w"
ttk::label $w.res.e4l -textvariable ::eskil($top,prefregresultl) \
-anchor "w" -width 10
ttk::label $w.res.e4r -textvariable ::eskil($top,prefregresultr) \
-anchor "w" -width 10
ttk::label $w.res.l5 -text "Example 2:" -anchor "w"
ttk::entryX $w.res.e5 -textvariable ::eskil($top,prefregexa2)
ttk::label $w.res.l6 -text "Result 2:" -anchor "w"
ttk::label $w.res.e6l -textvariable ::eskil($top,prefregresultl2) \
-anchor "w" -width 10
ttk::label $w.res.e6r -textvariable ::eskil($top,prefregresultr2) \
-anchor "w" -width 10
grid $w.res.l3 $w.res.e3 -sticky we -padx 3 -pady 3
grid $w.res.l4 $w.res.e4l -sticky we -padx 3 -pady 3
grid x $w.res.e4r -sticky we -padx 3 -pady 3
grid $w.res.l5 $w.res.e5 -sticky we -padx 3 -pady 3
grid $w.res.l6 $w.res.e6l -sticky we -padx 3 -pady 3
grid x $w.res.e6r -sticky we -padx 3 -pady 3
grid columnconfigure $w.res 1 -weight 1
# Buttons
ttk::frame $w.fb -padding 3
ttk::button $w.fb.b1 -text "Ok" -command [list EditPrefRegsubOk $top $w $item]
ttk::button $w.fb.b2 -text "Apply" -command [list EditPrefRegsubOk $top $w $item 1]
ttk::button $w.fb.b3 -text "Cancel" -command [list destroy $w]
set ::widgets($top,prefRegsubOk) $w.fb.b1
set ::widgets($top,prefRegsubApply) $w.fb.b2
grid $w.fb.b1 x $w.fb.b2 x $w.fb.b3 -sticky we
grid columnconfigure $w.fb {0 2 4} -uniform a
grid columnconfigure $w.fb {1 3} -weight 1
# Top layout
pack $w.b -side "top" -anchor "w" -padx 3 -pady 3 -ipadx 15
pack $w.fb $w.res -side bottom -fill x -padx 3 -pady 3
# Fill in existing or an empty line
set preprocess $::TmpPref(preprocess,re,$item)
if {[llength $preprocess] == 0} {
AddPrefRegsub $top $w
} else {
set t 1
foreach {RE Sub side} $preprocess {
set ::eskil($top,prefregexp$t) $RE
set ::eskil($top,prefregsub$t) $Sub
set ::eskil($top,prefregleft$t) 0
set ::eskil($top,prefregright$t) 0
if {$side eq "" || $side eq "left"} {
set ::eskil($top,prefregleft$t) 1
}
if {$side eq "" || $side eq "right"} {
set ::eskil($top,prefregright$t) 1
}
AddPrefRegsub $top $w
incr t
}
}
trace add variable ::eskil($top,prefregexa) write \
[list EditPrefRegsubUpdate $top]
trace add variable ::eskil($top,prefregexa2) write \
[list EditPrefRegsubUpdate $top]
EditPrefRegsubUpdate $top
}
# This is called when Ok or Apply is pressed.
proc EditPrefPrepOk {top w {keep 0}} {
# Update preference from dialog contents.
set new {}
for {set r 1} {$r <= $::TmpPref(preprocess,n)} {incr r} {
set name $::TmpPref(preprocess,name,$r)
set act $::TmpPref(preprocess,active,$r)
set save $::TmpPref(preprocess,save,$r)
set re $::TmpPref(preprocess,re,$r)
lappend new $name
lappend new [dict create active $act "save" $save preprocess $re]
}
set ::Pref(preprocessn) $new
if {$keep} return
destroy $w
}
# Create a toplevel, even if it exists
proc ToplevelForce {w title} {
destroy $w
ttk::toplevel $w -padx 3 -pady 3
wm title $w $title
}
# Move an item one step up
proc EditPrefPreUp {r} {
puts EditPrefPreUp$r
# Sanity check
if {$r <= 1 || $r > $::TmpPref(preprocess,n)} {
return
}
set p [expr {$r - 1}]
foreach item {name active save re} {
set tmp $::TmpPref(preprocess,$item,$r)
set ::TmpPref(preprocess,$item,$r) $::TmpPref(preprocess,$item,$p)
set ::TmpPref(preprocess,$item,$p) $tmp
}
}
proc EditPrefPreprocessAddItem {w} {
set r $::TmpPref(preprocess,n)
incr r
if {![info exists ::TmpPref(preprocess,name,$r)]} {
set ::TmpPref(preprocess,name,$r) ""
set ::TmpPref(preprocess,active,$r) 0
set ::TmpPref(preprocess,save,$r) 0
set ::TmpPref(preprocess,re,$r) ""
}
ttk::entry $w.fp.ne$r -textvariable ::TmpPref(preprocess,name,$r)
addBalloon $w.fp.ne$r "Name of preprocess item (optional)"
ttk::checkbutton $w.fp.cba$r -text "Active" \
-variable ::TmpPref(preprocess,active,$r)
addBalloon $w.fp.cba$r "Activate item for this session"
ttk::checkbutton $w.fp.cbs$r -text "Save" \
-variable ::TmpPref(preprocess,save,$r)
addBalloon $w.fp.cbs$r "Save item when preferences are saved"
ttk::button $w.fp.be$r -text "Edit" \
-command [list EditPrefRegsub $w $r]
addBalloon $w.fp.be$r "Edit the associated list of regexps"
ttk::button $w.fp.bu$r -image $::img(up) \
-command [list EditPrefPreUp $r]
addBalloon $w.fp.bu$r "Move item up in list"
grid $w.fp.ne$r $w.fp.cba$r $w.fp.cbs$r $w.fp.be$r $w.fp.bu$r -sticky we \
-padx 3 -pady 3
# Make buttons symmetric
grid $w.fp.be$r $w.fp.bu$r -sticky news
set ::TmpPref(preprocess,n) $r
}
proc EditPrefPreprocess {top} {
set w $top.prefpreprocess
# Make a working copy more suitable for GUI connection
set r 0
foreach {name data} $::Pref(preprocessn) {
incr r
set ::TmpPref(preprocess,name,$r) $name
set ::TmpPref(preprocess,active,$r) [dict get $data active]
set ::TmpPref(preprocess,save,$r) [dict get $data save]
set ::TmpPref(preprocess,re,$r) [dict get $data preprocess]
}
# Create one if there is none, to simplify GUI usage
if {$r == 0} {
incr r
}
set ::TmpPref(preprocess,n) 0
set nItems $r
ToplevelForce $w "Preferences: Preprocess"
# Frame for List of preprocessing
ttk::frame $w.fp -padding 3
grid columnconfigure $w.fp 0 -weight 1
for {set r 1} {$r <= $nItems} {incr r} {
EditPrefPreprocessAddItem $w
}
# Frame for action buttons
ttk::frame $w.fa -padding 3
ttk::button $w.fa.b1 -text "Add" \
-command [list EditPrefPreprocessAddItem $w]
grid $w.fa.b1 -sticky we
grid columnconfigure $w.fa {0 2 4} -uniform a
grid columnconfigure $w.fa {1 3} -weight 1
# Frame for dialog Buttons
ttk::frame $w.fb -padding 3
ttk::button $w.fb.b1 -text "Ok" -command [list EditPrefPrepOk $top $w]
ttk::button $w.fb.b2 -text "Apply" -command [list EditPrefPrepOk $top $w 1]
ttk::button $w.fb.b3 -text "Cancel" -command [list destroy $w]
grid $w.fb.b1 x $w.fb.b2 x $w.fb.b3 -sticky we
grid columnconfigure $w.fb {0 2 4} -uniform a
grid columnconfigure $w.fb {1 3} -weight 1
# Top layout
pack $w.fb -side bottom -fill x
pack $w.fa -side bottom -fill x
pack $w.fp -side "top" -fill both -expand 1
}