3 proc separatorToChar {separator} {
7 default {
return $separator}
11 proc separatorFromChar {separatorChar} {
12 switch $separatorChar {
14 " " {
return "<space>"}
15 default {
return $separatorChar}
19 proc loadDialogFromSpec {} {
21 set csvParms(url) [minsky.value.csvDialog.url]
22 set csvParms(separator) [
separatorFromChar [minsky.value.csvDialog.spec.separator]]
23 set csvParms(decSeparator) [minsky.value.csvDialog.spec.decSeparator]
24 set csvParms(escape) [minsky.value.csvDialog.spec.escape]
25 set csvParms(quote) [minsky.value.csvDialog.spec.quote]
26 set csvParms(mergeDelimiters) [minsky.value.csvDialog.spec.mergeDelimiters]
27 set csvParms(missingValue) [minsky.value.csvDialog.spec.missingValue]
28 set csvParms(duplicateKeyValue) [minsky.value.csvDialog.spec.duplicateKeyAction]
29 set csvParms(horizontalDimension) [minsky.value.csvDialog.spec.horizontalDimName]
30 set csvParms(horizontalType) [minsky.value.csvDialog.spec.horizontalDimension.type]
31 set csvParms(horizontalFormat) [minsky.value.csvDialog.spec.horizontalDimension.units]
34 proc CSVImportDialog {} {
35 if {[
llength [
info commands minsky.canvas.item.valueId]]==0}
return 36 getValue [minsky.canvas.item.valueId]
37 global workDir csvParms dataImportDialog
39 if {![
winfo exists .wiring.csvImport]} {
40 toplevel .wiring.csvImport
41 minsky.canvas.item.deleteCallback "destroy .wiring.csvImport"
42 if {$dataImportDialog} {
bind .wiring.csvImport <Destroy> "canvas.deleteItem; set dataImportDialog 0"}
45 frame .wiring.csvImport.fileUrl
46 button .wiring.csvImport.fileUrl.file -text "File" -command {
47 set csvParms(url) [tk_getOpenFile -filetypes {{CSV {.csv}} {All {.*}}} -initialdir $workDir]
48 .wiring.csvImport.fileUrl.load invoke
49 raise .wiring.csvImport
51 label .wiring.csvImport.fileUrl.orUrl -text "or URL"
52 entry .wiring.csvImport.fileUrl.url -textvariable csvParms(url) -width 100
53 button .wiring.csvImport.fileUrl.load -text "Load" -command {
54 if {[minsky.value.csvDialog.url]!=$csvParms(url)} {
55 minsky.value.csvDialog.url $csvParms(url)
56 minsky.value.csvDialog.guessSpecAndLoadFile
59 minsky.value.csvDialog.loadFile
61 minsky.value.csvDialog.requestRedraw
62 # update to calculate tableWidth
64 .wiring.csvImport.hscroll configure -to [expr int([minsky.value.csvDialog.tableWidth])]
66 bind .wiring.csvImport.fileUrl.url <Key-Return> ".wiring.csvImport.fileUrl.load invoke"
68 pack .wiring.csvImport.fileUrl.file .wiring.csvImport.fileUrl.orUrl \
69 .wiring.csvImport.fileUrl.url .wiring.csvImport.fileUrl.load -side left
70 pack .wiring.csvImport.fileUrl
73 frame .wiring.csvImport.delimiters
74 label .wiring.csvImport.delimiters.columnarLabel -text "Columnar"
75 ttk::checkbutton .wiring.csvImport.delimiters.columnar -variable csvParms(columnar) -command {
76 minsky.value.csvDialog.spec.columnar $csvParms(columnar)
77 minsky.value.csvDialog.requestRedraw
79 label .wiring.csvImport.delimiters.separatorLabel -text Separator
80 ttk::combobox .wiring.csvImport.delimiters.separatorValue -values {
81 "," ";" "<tab>" "<space>"} -textvariable csvParms(separator) -width 5
82 bind .wiring.csvImport.delimiters.separatorValue <<ComboboxSelected>> {
83 minsky.value.csvDialog.spec.separator [separatorToChar $csvParms(separator)]}
84 label .wiring.csvImport.delimiters.decSeparatorLabel -text "Decimal Separator"
85 ttk::combobox .wiring.csvImport.delimiters.decSeparatorValue -values {
86 "." ","} -textvariable csvParms(decSeparator) -width 5
87 bind .wiring.csvImport.delimiters.decSeparatorValue <<ComboboxSelected>> {
88 minsky.value.csvDialog.spec.decSeparator $csvParms(decSeparator)}
89 label .wiring.csvImport.delimiters.escapeLabel -text Escape
90 ttk::combobox .wiring.csvImport.delimiters.escapeValue -values {
91 "\\"} -textvariable csvParms(escape) -width 5
92 bind .wiring.csvImport.delimiters.escapeValue <<ComboboxSelected>> {
93 minsky.value.csvDialog.spec.escape $csvParms(escape)}
94 label .wiring.csvImport.delimiters.quoteLabel -text Quote
95 ttk::combobox .wiring.csvImport.delimiters.quoteValue -values {
96 "'" "\"" } -textvariable csvParms(quote) -width 5
97 bind .wiring.csvImport.delimiters.quoteValue <<ComboboxSelected>> {
98 minsky.value.csvDialog.spec.quote $csvParms(quote)}
99 label .wiring.csvImport.delimiters.mergeLabel -text "Merge Delimiters"
100 ttk::checkbutton .wiring.csvImport.delimiters.mergeValue -variable csvParms(mergeDelimiters) -command {
101 minsky.value.csvDialog.spec.mergeDelimiters $csvParms(mergeDelimiters)
103 label .wiring.csvImport.delimiters.missingLabel -text "Missing Value"
104 ttk::combobox .wiring.csvImport.delimiters.missingValue \
105 -textvariable csvParms(missingValue) -values {nan 0} -width 5
106 bind .wiring.csvImport.delimiters.missingValue <<ComboboxSelected>> {
107 minsky.value.csvDialog.spec.missingValue $csvParms(missingValue)}
109 label .wiring.csvImport.delimiters.colWidthLabel -text "Col Width"
110 spinbox .wiring.csvImport.delimiters.colWidth -from 10 -to 500 -increment 10 \
111 -width 5 -command {adjustColWidth %s} -validate key -validatecommand {adjustColWidth %P}
112 .wiring.csvImport.delimiters.colWidth set 50
114 pack .wiring.csvImport.delimiters.columnarLabel .wiring.csvImport.delimiters.columnar \
115 .wiring.csvImport.delimiters.separatorLabel .wiring.csvImport.delimiters.separatorValue \
116 .wiring.csvImport.delimiters.decSeparatorLabel .wiring.csvImport.delimiters.decSeparatorValue \
117 .wiring.csvImport.delimiters.escapeLabel .wiring.csvImport.delimiters.escapeValue \
118 .wiring.csvImport.delimiters.quoteLabel .wiring.csvImport.delimiters.quoteValue \
119 .wiring.csvImport.delimiters.mergeLabel .wiring.csvImport.delimiters.mergeValue \
120 .wiring.csvImport.delimiters.missingLabel .wiring.csvImport.delimiters.missingValue \
121 .wiring.csvImport.delimiters.colWidthLabel .wiring.csvImport.delimiters.colWidth -side left
123 pack .wiring.csvImport.delimiters
126 frame .wiring.csvImport.horizontalName
127 label .wiring.csvImport.horizontalName.duplicateKeyLabel -text "Duplicate Key Action"
128 ttk::combobox .wiring.csvImport.horizontalName.duplicateKeyValue \
129 -textvariable csvParms(duplicateKeyValue) \
130 -values {throwException sum product min max av} -width 15
131 bind .wiring.csvImport.horizontalName.duplicateKeyValue <<ComboboxSelected>> {
132 minsky.value.csvDialog.spec.duplicateKeyAction $csvParms(duplicateKeyValue)}
133 label .wiring.csvImport.horizontalName.text -text "Horizontal dimension"
134 entry .wiring.csvImport.horizontalName.value -width 30 -textvariable csvParms(horizontalDimension)
135 label .wiring.csvImport.horizontalName.typeLabel -text "Type"
136 ttk::combobox .wiring.csvImport.horizontalName.type \
137 -textvariable csvParms(horizontalType) \
138 -values {string value time} -width 15 -state readonly
139 bind .wiring.csvImport.horizontalName.type <<ComboboxSelected>> {
140 minsky.value.csvDialog.spec.horizontalDimension.type $csvParms(horizontalType)
141 dimFormatPopdown .wiring.csvImport.horizontalName.format $csvParms(horizontalType) {
142 minsky.value.csvDialog.spec.horizontalDimension.units [.wiring.csvImport.horizontalName.format get]
145 label .wiring.csvImport.horizontalName.formatLabel -text "Format"
146 ttk::combobox .wiring.csvImport.horizontalName.format \
147 -textvariable csvParms(horizontalFormat) -width 15
148 bind .wiring.csvImport.horizontalName.format <<ComboboxSelected>> {
149 minsky.value.csvDialog.spec.horizontalDimension.units $csvParms(horizontalFormat)}
151 pack .wiring.csvImport.horizontalName.duplicateKeyLabel .wiring.csvImport.horizontalName.duplicateKeyValue -side left
152 pack .wiring.csvImport.horizontalName.text .wiring.csvImport.horizontalName.value -side left
153 pack .wiring.csvImport.horizontalName
154 pack .wiring.csvImport.horizontalName.typeLabel .wiring.csvImport.horizontalName.type .wiring.csvImport.horizontalName.formatLabel .wiring.csvImport.horizontalName.format -side left
156 image create cairoSurface csvDialogTable -surface minsky.value.csvDialog
157 label .wiring.csvImport.table -image csvDialogTable -width 800 -height 300
158 pack .wiring.csvImport.table -fill both -expand 1 -side top
160 scale .wiring.csvImport.hscroll -orient horiz -from -100 -to 1000 -showvalue 0 -command scrollTable
161 pack .wiring.csvImport.hscroll -fill x -expand 1 -side top
165 global csvImportFailed
166 set csvImportFailed 0
167 .wiring.csvImport.buttonBar.ok configure -command csvImportDialogOK -text Import
168 bind .wiring.csvImport.table <Configure> "minsky.value.csvDialog.requestRedraw"
169 bind .wiring.csvImport.table <Button-1> {csvImportButton1 %x %y}
170 bind .wiring.csvImport.table <ButtonRelease-1> {csvImportButton1Up %x %y %X %Y}
171 bind .wiring.csvImport.table <B1-Motion> {
172 minsky.value.csvDialog.xoffs [expr $csvImportPanX+%x];
174 set row [minsky.value.csvDialog.rowOver %y]
175 if {$row>=4} {minsky.value.csvDialog.spec.headerRow [expr $row-4]}
176 minsky.value.csvDialog.flashNameRow [expr $row==3]
178 minsky.value.csvDialog.requestRedraw
182 if [
string length [minsky.value.csvDialog.url]] {
183 set workDir [
file dirname [minsky.value.csvDialog.url]]
185 .wiring.csvImport.delimiters.colWidth set [minsky.value.csvDialog.colWidth]
186 wm deiconify .wiring.csvImport
187 raise .wiring.csvImport
188 minsky.value.csvDialog.requestRedraw
191 proc csvImportDialogOK {} {
192 global csvParms dataImportDialog
193 minsky.value.csvDialog.spec.horizontalDimName $csvParms(horizontalDimension)
194 set csvImportFailed [
catch {loadVariableFromCSV minsky.value.csvDialog.spec "$csvParms(url)"} err]
195 if $csvImportFailed {
196 toplevel .csvImportError
197 label .csvImportError.errMsg -text $err
198 label .csvImportError.msg -text "Would you like to generate a report?"
199 pack .csvImportError.errMsg .csvImportError.msg -side top
200 buttonBar .csvImportError "global csvParms; doReport {$csvParms(url)}"
201 .csvImportError.buttonBar.ok configure -text "Yes"
202 .csvImportError.buttonBar.cancel configure -text "No"
204 if {$dataImportDialog} {
205 minsky.canvas.item.name [
file rootname [
file tail [minsky.value.csvDialog.url]]]
207 bind .wiring.csvImport <Destroy> ""
209 set dataImportDialog 0
216 proc doReport {inputFname} {
218 set fname [
tk_getSaveFile -defaultextension .csv -initialfile [
file rootname $inputFname]-error-report.csv -initialdir $workDir]
219 if [
string length $fname] {
220 eval minsky.value.csvDialog.reportFromFile {$inputFname} {$fname}
226 minsky.value.csvDialog.xoffs [
expr -$v]
227 minsky.value.csvDialog.requestRedraw
230 proc adjustColWidth {w} {
231 minsky.value.csvDialog.colWidth $w
232 minsky.value.csvDialog.requestRedraw
236 proc csvImportButton1 {x y} {
237 global csvImportPanX mouseSave movingHeader
238 set csvImportPanX [
expr [minsky.value.csvDialog.xoffs]-$x]
239 set movingHeader [
expr [minsky.value.csvDialog.rowOver $y]-4 == [minsky.value.csvDialog.spec.headerRow]]
240 set mouseSave "$x $y"
243 proc closeCombo setter {
244 eval $setter \[.wiring.csvImport.text.combo get\]
245 wm withdraw .wiring.csvImport.text
246 minsky.value.csvDialog.requestRedraw
249 proc setupCombo {getter setter title configure X Y} {
250 wm title .wiring.csvImport.text $title
251 eval .wiring.csvImport.text.combo configure $configure
252 .wiring.csvImport.text.combo set $getter
253 bind .wiring.csvImport.text.combo <<ComboboxSelected>> "closeCombo $setter"
254 bind .wiring.csvImport.text.combo <Return> "closeCombo $setter"
255 wm deiconify .wiring.csvImport.text
256 wm geometry .wiring.csvImport.text +$X+$Y
257 raise .wiring.csvImport.text
260 proc csvImportButton1Up {x y X Y} {
261 global mouseSave csvParms movingHeader
263 if {![
winfo exists .wiring.csvImport.text.combo]} {
264 toplevel .wiring.csvImport.text
265 ttk::combobox .wiring.csvImport.text.combo -values {"string" "value" "time"} -state readonly
266 pack .wiring.csvImport.text.combo
267 wm withdraw .wiring.csvImport.text
270 set col [minsky.value.csvDialog.columnOver $x]
271 set row [minsky.value.csvDialog.rowOver $y]
272 if {abs([
lindex $mouseSave 0]-$x)==0 && abs([
lindex $mouseSave 1]-$y)==0} {
274 switch [minsky.value.csvDialog.rowOver $y] {
275 0 {minsky.value.csvDialog.spec.toggleDimension $col
276 minsky.value.csvDialog.requestRedraw
279 if {$col<[minsky.value.csvDialog.spec.dimensions.size]} {
280 setupCombo [[minsky.value.csvDialog.spec.dimensions.@elem $col].type] \
281 "minsky.value.csvDialog.spec.dimensions($col).type" \
282 "Dimension type" {-values {"string" "value" "time"} -state readonly} $X $Y
286 if {$col<[minsky.value.csvDialog.spec.dimensions.size]} {
288 setupCombo [[minsky.value.csvDialog.spec.dimensions.@elem $col].units] \
289 "minsky.value.csvDialog.spec.dimensions($col).units" \
290 "Dimension units/format" "-values $units -state normal" $X $Y
291 dimFormatPopdown .wiring.csvImport.text.combo [[minsky.value.csvDialog.spec.dimensions.@elem $col].type] "minsky.value.csvDialog.spec.dimensions($col).units \[.wiring.csvImport.text.combo get\]"
294 3 {
if {$col<[minsky.value.csvDialog.spec.dimensions.size]} {
295 setupCombo [[minsky.value.csvDialog.spec.dimensionNames.@elem $col]] \
296 "minsky.value.csvDialog.spec.dimensionNames($col)" \
297 "Dimension name" "-values \"[minsky.value.csvDialog.headerForCol $col]\" -state normal" $X $Y
300 minsky.value.csvDialog.spec.setDataArea [
expr $row-4] $col
301 minsky.value.csvDialog.requestRedraw
305 if {$movingHeader && $row==3} {
307 set oldHeaderRow [
expr [minsky.value.csvDialog.rowOver [
lindex $mouseSave 1]]-4]
308 minsky.value.csvDialog.copyHeaderRowToDimNames $oldHeaderRow
309 minsky.value.csvDialog.spec.headerRow $oldHeaderRow
310 minsky.value.csvDialog.flashNameRow 0
311 minsky.value.csvDialog.requestRedraw