Scid  4.7.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
optable.tcl
Go to the documentation of this file.
1 ### optable.tcl: Opening report and theory table generation.
2 ### Part of Scid. Copyright 2001-2003 Shane Hudson.
3 
4 namespace eval ::optable {}
5 array set ::optable::_data {}
6 
7 set ::optable::_data(exclude) "---"
8 set ::optable::_docStart(text) {}
9 set ::optable::_docEnd(text) {}
10 set ::optable::_docStart(ctext) {}
11 set ::optable::_docEnd(ctext) {}
12 set ::optable::_flip 0
13 
14 set ::optable::_docStart(html) {<html>
15  <head>
16  <title>[OprepTitle]</title>
17  <style type="text/css">
18  <!--
19  h1 { color:#990000 }
20  h2 { color:#990000 }
21  h3 { color:#990000 }
22  .player {
23  color:darkblue
24  }
25  .elo {
26  color:green
27  font-style:italic
28  }
29  sup {
30  color:red
31  }
32  -->
33  </style>
34  </head>
35  <body bgcolor="#ffffff">
36 }
37 set ::optable::_docEnd(html) {</body>
38  </html>
39 }
40 
41 set ::optable::_docStart(latex) {\documentclass[10pt,a4paper]{article}
42  % This is a LaTeX file generated by Scid.
43  % You must have the "chess12" package installed to typeset this file.
44 
45  \usepackage{times}
46  \usepackage{a4wide}
47  \usepackage{chess}
48  \usepackage[T1]{fontenc}
49 
50  \setlength{\columnsep}{1cm}
51  \setlength{\parindent}{0pt}
52  \setlength{\parskip}{3pt}
53 
54  \font\F=chessf10
55  \newcommand{\B}{{\F B}}
56  \newcommand{\N}{{\F N}}
57  \newcommand{\R}{{\F R}}
58  \newcommand{\Q}{{\F Q}}
59  \newcommand{\K}{{\F K}}
60  \newcommand{\tspace}{{\vspace{0.08cm}}}
61  \newcommand{\draw}{{\small$\frac{1}{2}$:$\frac{1}{2}$}}
62  \newcommand{\loss}{\mbox{0:1}}
63  \newcommand{\win}{\mbox{1:0}}
64  \newcommand{\notenum}[1]{\hspace{-0.7cm}\makebox[0.55cm][r]{$^{ #1 }$ }\makebox[0.05cm]{}}
65 
66  %\font\Chess=chess10
67  \begin{document}
68  \raggedright
69  \nochess
70 }
71 set ::optable::_docEnd(latex) {
72  \end{document}
73 }
74 
75 proc ::optable::ConfigMenus {{lang ""}} {
76  if {! [winfo exists .oprepWin]} { return}
77  if {$lang == ""} { set lang $::language}
78  set m .oprepWin.menu
79  foreach idx {0 1 2} tag {File Favorites Help} {
80  configMenuText $m $idx Oprep$tag $lang
81  }
82  foreach idx {0 1 2 4 6} tag {Text Html LaTeX Options Close} {
83  configMenuText $m.file $idx OprepFile$tag $lang
84  }
85  foreach idx {0 1 2} tag {Add Edit Generate} {
86  configMenuText $m.favorites $idx OprepFavorites$tag $lang
87  }
88  foreach idx {0 1} tag {Report Index} {
89  configMenuText $m.helpmenu $idx OprepHelp$tag $lang
90  }
91 }
92 
93 proc ::optable::makeReportWin {args} {
94  set ::optable::opReportBase [sc_base current]
95  set showProgress 1
96  set args [linsert $args 0 "args"]
97  if {[lsearch -exact $args "-noprogress"] >= 0} { set showProgress 0}
98  if {$showProgress} {
99  set w .progress
100  toplevel $w -background [ttk::style lookup . -background]
101  wm withdraw $w
102  wm title $w "Scid: Generating Report"
103  bind $w <Visibility> "raiseWin $w"
104 
105  pack [ttk::frame $w.b] -side bottom -fill x
106  set ::optable::_interrupt 0
107  ttk::button $w.b.cancel -text $::tr(Cancel) -command {
108  set ::optable::_interrupt 1
109  progressBarCancel
110  }
111  pack $w.b.cancel -side right -pady 5 -padx 2
112 
113  foreach i {1 2} name { "Searching database for report games" "Generating report information" } {
114  ttk::label $w.text$i -text "$i. $name"
115  pack $w.text$i -side top
116  canvas $w.c$i -width 400 -height 20 -bg white -relief solid -border 1
117  $w.c$i create rectangle 0 0 0 0 -fill blue -outline blue -tags bar
118  $w.c$i create text 395 10 -anchor e -font font_Regular -tags time \
119  -fill black -text "0:00 / 0:00"
120  pack $w.c$i -side top -pady 10
121  }
122  wm resizable $w 0 0
123  # Set up geometry for middle of screen:
124  set x [winfo screenwidth $w]; set x [expr $x - 400]; set x [expr $x / 2]
125  set y [winfo screenheight $w]; set y [expr $y - 20]; set y [expr $y / 2]
126  wm geometry $w +$x+$y
127  wm deiconify $w
128  grab $w.b.cancel
129  progressBarSet $w.c1 401 21
130  }
131 
132  sc_search board RESET Exact false 0
133  set newTreeData [sc_tree search]
134  if {$showProgress} {
135  if {$::optable::_interrupt} {
136  grab release $w.b.cancel
137  destroy $w
138  return
139  }
140  progressBarSet $w.c2 401 21
141  }
142  sc_report opening create $::optable(ExtraMoves) $::optable(MaxGames) $::optable::_data(exclude)
143  if {$showProgress} {
144  grab release $w.b.cancel
145  destroy $w
146  if {$::optable::_interrupt} { return}
147  }
148 
149  set ::optable::_data(tree) $newTreeData
151  set ::optable::_data(bdLaTeX) [sc_pos tex]
152  set ::optable::_data(bdHTML) [sc_pos html]
153  set ::optable::_data(bdLaTeX_flip) [sc_pos tex flip]
154  set ::optable::_data(bdHTML_flip) [sc_pos html -flip 1]
155 
157 
158  set report [::optable::report ctext 1]
159 
160  if {[lsearch -exact $args "-nodisplay"] >= 0} { return}
161 
162  set w .oprepWin
163  if {![winfo exists $w]} {
165  ::setTitle $w "[tr ToolsOpReport]"
166  menu $w.menu
167  ::setMenu $w $w.menu
168 
169  $w.menu add cascade -label OprepFile -menu $w.menu.file
170  $w.menu add cascade -label OprepFavorites -menu $w.menu.favorites
171  $w.menu add cascade -label OprepHelp -menu $w.menu.helpmenu
172  foreach i {file favorites helpmenu} {
173  menu $w.menu.$i -tearoff 0
174  }
175 
176  $w.menu.file add command -label OprepFileText \
177  -command {::optable::saveReport text}
178  $w.menu.file add command -label OprepFileHtml \
179  -command {::optable::saveReport html}
180  $w.menu.file add command -label OprepFileLaTeX \
181  -command {::optable::saveReport latex}
182  $w.menu.file add separator
183  $w.menu.file add command -label OprepFileOptions \
184  -command ::optable::setOptions
185  $w.menu.file add separator
186  $w.menu.file add command -label OprepFileClose \
187  -command "$w.b.close invoke"
188  $w.menu.favorites add command -label OprepFavoritesAdd \
189  -command ::optable::addFavoriteDlg
190  $w.menu.favorites add command -label OprepFavoritesEdit \
191  -command ::optable::editFavoritesDlg
192  $w.menu.favorites add command -label OprepFavoritesGenerate \
193  -command ::optable::generateFavoriteReports
194  $w.menu.favorites add separator
195  $w.menu.helpmenu add command -label OprepHelpReport \
196  -accelerator F1 -command {helpWindow Reports Opening}
197  $w.menu.helpmenu add command -label OprepHelpIndex \
198  -command {helpWindow Index}
199 
201 
202  bind $w <F1> {helpWindow Reports Opening}
203  bind $w <Escape> "$w.b.close invoke"
204  bind $w <Up> "$w.text yview scroll -1 units"
205  bind $w <Down> "$w.text yview scroll 1 units"
206  bind $w <Prior> "$w.text yview scroll -1 pages"
207  bind $w <Next> "$w.text yview scroll 1 pages"
208  bind $w <Key-Home> "$w.text yview moveto 0"
209  bind $w <Key-End> "$w.text yview moveto 0.99"
210 
211  text $w.text -height 30 -width 85 -font font_Small -setgrid 1 \
212  -wrap word -bg white -foreground black -yscrollcommand "$w.ybar set" \
213  -cursor top_left_arrow
214  ::htext::init $w.text
215  ttk::scrollbar $w.ybar -command "$w.text yview"
216  ttk::frame $w.b
217  ttk::button $w.b.previewLaTeX -textvar ::tr(OprepViewLaTeX) \
218  -command ::optable::previewLaTeX
219  ttk::button $w.b.previewHTML -textvar ::tr(OprepViewHTML) \
220  -command ::optable::previewHTML
221  ttk::button $w.b.opts -text [tr OprepFileOptions] -command ::optable::setOptions
222  ttk::label $w.b.lexclude -text "Exclude:"
223  ttk::menubutton $w.b.exclude -textvar ::optable::_data(exclude) -menu $w.b.exclude.m
224  menu $w.b.exclude.m -tearoff 0
225  ttk::button $w.b.update -textvar ::tr(Update) -command {
226  set ::optable::_data(yview) [lindex [.oprepWin.text yview] 0]
227  ::optable::makeReportWin
228  .oprepWin.text yview moveto $::optable::_data(yview)
229  }
230 
231  ttk::button $w.b.mergeGames -textvar ::tr(MergeGames) -command ::optable::mergeGames
232  ttk::button $w.b.help -textvar ::tr(Help) -command {helpWindow Reports Opening}
233  ttk::button $w.b.close -textvar ::tr(Close) -command "focus .; destroy $w"
234  pack $w.b -side bottom -fill x
235  pack $w.ybar -side right -fill y
236  pack $w.text -side left -fill both -expand yes
237  pack $w.b.close $w.b.update -side right -padx 1 -pady 2
238  if {! $::windowsOS} {
239  pack $w.b.previewLaTeX -side left -padx 1 -pady 2
240  } else {
241  pack $w.b.previewHTML -side left -padx 1 -pady 2
242  }
243  pack $w.b.opts $w.b.lexclude $w.b.exclude $w.b.mergeGames -side left -padx 1 -pady 2
246  }
247 
248  catch {destroy $w.text.bd}
249 
250  ::board::new $w.text.bd 30
251 
252  if {$::optable::_flip} { ::board::flip $w.text.bd}
253  $w.text.bd configure -relief solid -borderwidth 1
254  for {set i 0} {$i < 63} {incr i} {
255  ::board::bind $w.text.bd $i <ButtonPress-1> ::optable::flipBoard
256  #::board::bind $w.text.bd $i <ButtonPress-$::MB3> ::optable::resizeBoard
257  }
258  ::board::update $w.text.bd [sc_pos board]
259  $w.b.exclude.m delete 0 end
260  $w.b.exclude.m add radiobutton -label "---" -variable ::optable::_data(exclude) -command "$w.b.update invoke"
261  foreach move $::optable::_data(moves) {
262  $w.b.exclude.m add radiobutton -label $move -variable ::optable::_data(exclude) -command "$w.b.update invoke"
263  }
264  if {[lsearch $::optable::_data(moves) $::optable::_data(exclude)] < 0} {
265  set ::optable::_data(exclude) "---"
266  }
267  busyCursor .
268  $w.text configure -state normal
269  $w.text delete 1.0 end
270  regsub -all "\n" $report "<br>" report
271  ::htext::display $w.text $report
272  $w.text configure -state disabled
273  unbusyCursor .
274 
275  ::notify::DatabaseModified $::curr_db dbfilter
276 }
277 ################################################################################
278 # merges the N best games up to P plies to current game
279 ################################################################################
280 proc ::optable::mergeGames { {game_count 50} {ply 999} } {
281  set base $::optable::opReportBase
282  set games [split [sc_report opening best a $game_count] "\n"]
283  foreach g $games {
284  if {$g == "" } { continue}
285  set res [scan $g "%d: <g_%d>" d1 game_number]
286  if {$res != 2} {
287  if {[info exists game_number]} {
288  tk_messageBox -title "Scid: Error writing report" -type ok -icon warning -message "Error merging game $game_number"
289  } else {
290  tk_messageBox -title "Scid: Error writing report" -type ok -icon warning -message "Error merging game"
291  }
292  break
293  }
294  set err [ catch { sc_game merge $base $game_number $ply} result]
295  if {$err} {
296  tk_messageBox -title "Scid" -type ok -icon info -message "Unable to merge the selected game:\n$result"
297  break
298  }
299  }
300  updateBoard -pgn
301 }
302 ################################################################################
303 #
304 ################################################################################
305 
306 proc ::optable::flipBoard {} {
307  ::board::flip .oprepWin.text.bd
308  set ::optable::_flip [::board::isFlipped .oprepWin.text.bd]
309 }
310 
311 proc ::optable::resizeBoard {} {
312  set bd .oprepWin.text.bd
313  set size [::board::size $bd]
314  if {$size >= 40} { set size 25} else { incr size 5}
315  ::board::resize $bd $size
316 }
317 
318 proc ::optable::setOptions {} {
319  set w .oprepOptions
320  if {[winfo exists $w]} { return}
322  pack [ttk::frame $w.f] -side top -fill x -padx 5
323  set row 0
324  foreach i {Stats Popular AvgPerf Results MovesFrom Themes Endgames} {
325  set yesno($i) 1
326  }
327  set left 0
328  set right 1
329  foreach i {Stats Oldest Newest Popular MostFrequent sep \
330  AvgPerf HighRating sep \
331  Results Shortest sep col \
332  MoveOrders MovesFrom Themes Endgames gap sep \
333  MaxGames ExtraMoves sep} {
334  set from 0; set to 10; set tick 1; set res 1
335 
336  if {$i == "col"} {
337  incr left 4
338  ttk::frame $w.f.colsep$left -width 8
339  grid $w.f.colsep$left -row 0 -column $left
340  incr left
341  set right [expr {$left + 1}]
342  set row 0
343  } elseif {$i == "gap"} {
344  # nothing
345  } elseif {$i == "sep"} {
346  ttk::separator $w.f.fsep$row$left
347  ttk::separator $w.f.tsep$row$left
348  grid $w.f.fsep$row$left -row $row -column $left -sticky we -columnspan 4 -pady 2
349  } elseif {[info exists yesno($i)]} {
350  ttk::checkbutton $w.f.f$i -variable ::optable($i) -onvalue 1 -offvalue 0 -text $::tr(Oprep$i)
351  grid $w.f.f$i -row $row -column $left -sticky w -columnspan 3
352  } else {
353 
354  # Pascal Georges : changed combobox to spinbox to widen choices
355  if {$i == "MaxGames"} {
356  ttk::spinbox $w.f.s$i -textvariable ::optable($i) -from 0 -to 5000 -increment 50 \
357  -state readonly -width 5 -justify right -font font_Small
358  } else {
359  set tmpcombo {}
360  for {set x $from} {$x <= $to} {incr x $res} {
361  lappend tmpcombo $x
362  }
363  ttk::combobox $w.f.s$i -textvariable ::optable($i) -width 2 -values $tmpcombo -justify right -state readonly
364  }
365 
366  ttk::label $w.f.t$i -textvar ::tr(Oprep$i) -font font_Small
367  grid $w.f.s$i -row $row -column $left -sticky w
368  if {$i == "MostFrequent" || $i == "Shortest"} {
369  ttk::checkbutton $w.f.w$i -text $::tr(White) \
370  -variable ::optable(${i}White)
371  ttk::checkbutton $w.f.b$i -text $::tr(Black) \
372  -variable ::optable(${i}Black)
373  grid $w.f.t$i -row $row -column $right -sticky w
374  grid $w.f.w$i -row $row -column 2 -sticky w -padx 5
375  grid $w.f.b$i -row $row -column 3 -sticky w
376  } else {
377  grid $w.f.t$i -row $row -column $right -columnspan 3 -sticky w
378  }
379  }
380  if {$i != "col"} { incr row}
381  }
382  pack [ttk::frame $w.b] -side bottom -fill x
383  dialogbutton $w.b.defaults -textvar ::tr(Defaults) -command {
384  array set ::optable [array get ::optableDefaults]
385  }
386  dialogbutton $w.b.ok -text "OK" -command {
387  destroy .oprepOptions
388  catch {set ::optable::_data(yview) [lindex [.oprepWin.text yview] 0]}
389  ::optable::makeReportWin
390  catch {.oprepWin.text yview moveto $::optable::_data(yview)}
391  }
392  dialogbutton $w.b.cancel -textvar ::tr(Cancel) -command {
393  array set ::optable [array get ::optable::backup]
394  destroy .oprepOptions
395  }
396  packbuttons left $w.b.defaults
397  packdlgbuttons $w.b.cancel $w.b.ok
398  array set ::optable::backup [array get ::optable]
399  wm resizable $w 0 0
400  wm title $w "Scid: [tr ToolsOpReport]: [tr OprepFileOptions]"
401  bind $w <Escape> "$w.b.cancel invoke"
402 }
403 
404 # previewLaTeX:
405 # Saves the report to a temporary file, runs latex on it, then
406 # "dvips" to produce PostScript, and "ghostview" to display it.
407 #
408 proc ::optable::previewLaTeX {} {
409  busyCursor .
410  set tmpdir $::scidLogDir
411  set tmpfile "TempOpeningReport"
412  set fname [file join $tmpdir $tmpfile]
413  catch {exec /bin/sh -c "rm $fname.*"}
414  if {[catch {set tempfile [open $fname.tex w]}]} {
415  tk_messageBox -title "Scid: Error writing report" -type ok -icon warning \
416  -message "Unable to write the file: $fname.tex"
417  }
418  # Add the "batchmode" command to the top of the file to prevent latex
419  # pausing for input on errors:
420  puts $tempfile "\\batchmode"
421  puts $tempfile [::optable::report latex 1 $::optable::_flip]
422  close $tempfile
423  if {! [catch {exec /bin/sh -c "cd $tmpdir; latex '$tmpfile.tex'" >& /dev/null}]} {
424  if {[catch {exec /bin/sh -c "cd $tmpdir; dvips '$tmpfile.dvi'" >& /dev/null}]} {
425  tk_messageBox -title "Scid" -icon warning -type ok \
426  -message "Unable to run \"dvips\" to convert the report to PostScript."
427  } else {
428  if {[catch {exec /bin/sh -c "ghostview '$fname.ps'" >& /dev/null &}]} {
429  tk_messageBox -title "Scid" -icon warning -type ok \
430  -message "Unable to run \"xdvi\" to view the report."
431  }
432  }
433  } else {
434  tk_messageBox -title "Scid: Errors producing report" -type ok \
435  -icon warning \
436  -message "Errors running latex on the file: $fname.tex\n\nSee $fname.log for details."
437  }
438  unbusyCursor .
439 }
440 
441 # previewHTML:
442 # Saves the report to a temporary file, and invokes the user's web
443 # browser to display it.
444 #
445 proc ::optable::previewHTML {} {
446  busyCursor .
447  set tmpdir $::scidLogDir
448  set tmpfile "TempOpeningReport"
449  set fname [file join $tmpdir $tmpfile]
450  if {[catch {set tempfile [open $fname.html w]}]} {
451  tk_messageBox -title "Scid: Error writing report" -type ok -icon warning \
452  -message "Unable to write the file: $fname.html"
453  }
454  puts $tempfile [::optable::report html 1 $::optable::_flip]
455  close $tempfile
456  if {[string match $::tcl_platform(os) "Windows NT"]} {
457  catch {exec $::env(COMSPEC) /c start $fname.html &}
458  } else {
459  catch {exec start $fname.html &}
460  }
461  unbusyCursor .
462 }
463 
464 # saveReport:
465 # Saves the current opening report to a file.
466 # "fmt" is the format: text, html or latex.
467 # "type" is the report type: report, table, or both.
468 #
469 proc ::optable::saveReport {fmt} {
470  set t [tk_dialog .dialog "Scid: Select report type" \
471  "Select the report type. You may save a full report (which includes the theory table), a compact report (with no theory table), or just the theory table by itself." \
472  "" 0 "Full report" "Compact report" \
473  "Theory table" "Cancel"]
474  if {$t == 3} { return}
475  set default ".txt"
476  set ftype {
477  { "Text files" {".txt"} }
478  { "All files" {"*"} }
479  }
480  if {$fmt == "latex"} {
481  set default ".tex"
482  set ftype {
483  { "LaTeX files" {".tex" ".ltx"} }
484  { "All files" {"*"} }
485  }
486  } elseif {$fmt == "html"} {
487  set default ".html"
488  set ftype {
489  { "HTML files" {".html" ".htm"} }
490  { "All files" {"*"} }
491  }
492  }
493 
494  set fname [tk_getSaveFile -initialdir [pwd] -filetypes $ftype \
495  -defaultextension $default -title "Scid: Save opening report"]
496  if {$fname == ""} { return}
497 
498  busyCursor .
499  if {[catch {set tempfile [open $fname w]}]} {
500  tk_messageBox -title "Scid: Error writing report" -type ok -icon warning \
501  -message "Unable to write the file: $fname\n\n"
502  } else {
503  if {$t == 2} {
504  set report [::optable::table $fmt]
505  } elseif {$t == 1} {
506  set report [::optable::report $fmt 0 $::optable::_flip]
507  } else {
508  set report [::optable::report $fmt 1 $::optable::_flip]
509  }
510  if {$::hasEncoding && $::langEncoding($::language) != ""} {
511  catch {set report [encoding convertto $::langEncoding($::language) $report]}
512  }
513  puts $tempfile $report
514  close $tempfile
515  }
516  unbusyCursor .
517 }
518 
519 proc ::optable::create {} {
520  set ::optable::_data(tree) [sc_tree search]
522  set ::optable::_data(bdLaTeX) [sc_pos tex]
523  set ::optable::_data(bdHTML) [sc_pos html]
524  set ::optable::_data(bdLaTeX_flip) [sc_pos tex flip]
525  set ::optable::_data(bdHTML_flip) [sc_pos html -flip 1]
526  sc_report opening create $::optable(ExtraMoves) $::optable(MaxGames)
528 }
529 
530 # latexifyTree
531 # Convert the plain text tree output used for text/html reports
532 # to a table for LaTeX output.
533 #
534 proc ::optable::latexifyTree {} {
535  set ::optable::_data(moves) {}
536  if {! [info exists ::optable::_data(tree)]} { return}
537  set tree [split $::optable::_data(tree) "\n"]
538  set ltree "\\begin{tabular}{rllr@{:}rrrrrr}\n\\hline\n"
539  append ltree " & Move & ECO & \\multicolumn{2}{c}{Frequency}"
540  append ltree " & Score & \$\\mu\$Elo & Perf & \$\\mu\$Year & \\% Draws \\\\ \n"
541  append ltree "\\hline\n"
542  set len [llength $tree]
543  set done 0
544  for {set i 1} {$i < $len} {incr i} {
545  set line [lindex $tree $i]
546  if {[string index $line 0] == "_"} {
547  append ltree "\\hline\n"
548  continue
549  }
550  if {[string length $line] == 0} { continue}
551  set num [string range $line 0 1]
552  set move [string range $line 4 9]
553  set eco [string range $line 11 15]
554  set freq [string range $line 17 23]
555  set fpct [string range $line 25 29]
556  set score [string range $line 33 37]
557  set avElo [string range $line 41 44]
558  set perf [string range $line 47 50]
559  set avYear [string range $line 53 56]
560  set pctDraw [string range $line 59 61]
561  set mv [string trim $move]
562  regsub K $move {{\\K}} move
563  regsub Q $move {{\\Q}} move
564  regsub R $move {{\\R}} move
565  regsub B $move {{\\B}} move
566  regsub N $move {{\\N}} move
567  if {[string index $line 0] == "T"} {
568  append ltree "\\multicolumn{2}{l}{Total}"
569  } else {
570  append ltree " $num & $move "
571  lappend ::optable::_data(moves) $mv
572  }
573  append ltree " & $eco & $freq & $fpct\\% & $score\\%"
574  append ltree " & $avElo & $perf & $avYear & $pctDraw\\% \\\\ \n"
575  }
576  append ltree "\\hline\n"
577  append ltree "\\end{tabular}\n"
578  set ::optable::_data(latexTree) $ltree
579 }
580 
581 proc ::optable::setupRatios {} {
582  set r [sc_filter freq [sc_base current] tree date 0000.00.00]
583  if {[lindex $r 0] == 0} {
584  set ::optable::_data(ratioAll) 0
585  } else {
586  set ::optable::_data(ratioAll) \
587  [expr {int(double([lindex $r 1]) / double([lindex $r 0]))}]
588  }
589  foreach {start end} {1800 1899 1900 1949 1950 1969 1970 1979
590  1980 1989 1990 1999 2000 2009} {
591  set r [sc_filter freq [sc_base current] tree date $start.00.00 $end.12.31]
592  set filter [lindex $r 0]
593  set all [lindex $r 1]
594  if {$filter == 0} {
595  set ::optable::_data(range$start) "---"
596  } else {
597  set ::optable::_data(range$start) \
598  [expr {int(double($all) / double($filter))}]
599  }
600  }
601  foreach y {1 5 10} {
602  set year "[expr [::utils::date::today year]-$y]"
603  append year ".[::utils::date::today month].[::utils::date::today day]"
604  set r [sc_filter freq [sc_base current] tree date $year]
605  set filter [lindex $r 0]
606  set all [lindex $r 1]
607  if {$filter == 0} {
608  set ::optable::_data(ratio$y) 0
609  } else {
610  set ::optable::_data(ratio$y) \
611  [expr {int(double($all) / double($filter))}]
612  }
613  if {$::optable::_data(ratio$y) == 0} {
614  set r 1.0
615  } else {
616  set r [expr {double($::optable::_data(ratioAll))}]
617  set r [expr {$r / double($::optable::_data(ratio$y))}]
618  }
619  set ::optable::_data(delta$y) [expr {int(($r - 1.0) * 100.0 + 0.5)}]
620  }
621 }
622 
623 proc ::optable::_percent {x fmt} {
624  set p "%"
625  if {$fmt == "latex"} { set p "\\%"}
626  return "[expr $x / 10][sc_info decimal][expr $x % 10]$p"
627 }
628 
629 proc ::optable::results {reportType fmt} {
630  set s {}
631  set n "\n"; set next " "; set p "%"
632  set white "1-0"; set draw "=-="; set black "0-1"
633 
634  if {$fmt == "latex"} {
635  set next " & "; set n "\\\\\n"; set p "\\%"
636  set white "\\win"; set draw "\\draw"; set black "\\loss"
637  append s "\\begin{tabular}{lccccccc}\n"
638  }
639 
640  if {$fmt == "html"} { append s "<pre>\n"}
641  if {$fmt == "ctext"} { append s "<tt>"}
642  if {$fmt == "latex"} { append s "\\hline\n"}
643 
644  set lenReport [string length $::tr(OprepReportGames)]
645  set lenAll [string length $::tr(OprepAllGames)]
646  set len [expr {($lenReport > $lenAll) ? $lenReport : $lenAll}]
647  set score [::utils::string::Capital $::tr(score)]
648  set slen [string length $score]
649  if {$slen < 7} { set slen 7}
650 
651  append s " [::utils::string::Pad {} $len] $next"
652  append s "[::utils::string::PadRight $score $slen] $next"
653  if {$fmt == "latex"} {
654  append s "\\multicolumn{3}{c}{$::tr(OprepLength)} & "
655  append s "\\multicolumn{3}{c}{$::tr(OprepFrequency)} $n "
656  } else {
657  append s "[::utils::string::PadCenter $::tr(OprepLength) 19] $next"
658  append s "[::utils::string::PadCenter $::tr(OprepFrequency) 22] $n"
659  }
660 
661  append s " [::utils::string::Pad {} $len] $next"
662  append s "[::utils::string::PadRight {} $slen] $next"
663  append s "[::utils::string::PadRight $white 5] $next"
664  append s "[::utils::string::PadRight $draw 5] $next"
665  append s "[::utils::string::PadRight $black 5] $next"
666  append s "[::utils::string::PadRight $white 5] $next"
667  append s "[::utils::string::PadRight $draw 5] $next"
668  append s "[::utils::string::PadRight $black 5] $n"
669  if {$fmt == "latex"} { append s "\\hline\n"}
670 
671  set sc [sc_report $reportType score]
672  set wlen [sc_report $reportType avgLength 1]
673  set dlen [sc_report $reportType avgLength =]
674  set blen [sc_report $reportType avgLength 0]
675  set wf [sc_report $reportType freq 1]
676  set df [sc_report $reportType freq =]
677  set bf [sc_report $reportType freq 0]
678 
679  append s " [::utils::string::Pad $::tr(OprepReportGames) $len] $next"
680  append s "[::utils::string::PadRight [::optable::_percent [lindex $sc 0] $fmt] $slen] $next"
681  append s "[::utils::string::PadRight [lindex $wlen 0] 5] $next"
682  append s "[::utils::string::PadRight [lindex $dlen 0] 5] $next"
683  append s "[::utils::string::PadRight [lindex $blen 0] 5] $next"
684  append s "[::utils::string::PadRight [::optable::_percent [lindex $wf 0] $fmt] 6] $next"
685  append s "[::utils::string::PadRight [::optable::_percent [lindex $df 0] $fmt] 6] $next"
686  append s "[::utils::string::PadRight [::optable::_percent [lindex $bf 0] $fmt] 6] $n"
687 
688  append s " [::utils::string::Pad $::tr(OprepAllGames) $len] $next"
689  append s "[::utils::string::PadRight [::optable::_percent [lindex $sc 1] $fmt] $slen] $next"
690  append s "[::utils::string::PadRight [lindex $wlen 1] 5] $next"
691  append s "[::utils::string::PadRight [lindex $dlen 1] 5] $next"
692  append s "[::utils::string::PadRight [lindex $blen 1] 5] $next"
693  append s "[::utils::string::PadRight [::optable::_percent [lindex $wf 1] $fmt] 6] $next"
694  append s "[::utils::string::PadRight [::optable::_percent [lindex $df 1] $fmt] 6] $next"
695  append s "[::utils::string::PadRight [::optable::_percent [lindex $bf 1] $fmt] 6] $n"
696 
697  if {$fmt == "latex"} { append s "\\hline\n\\end{tabular}\n"}
698  if {$fmt == "html"} { append s "</pre>\n"}
699  if {$fmt == "ctext"} { append s "</tt>"}
700 
701  return $s
702 }
703 
704 proc ::optable::stats {fmt} {
705  global stats
706  set s {}
707  set all $::tr(OprepStatAll)
708  set both $::tr(OprepStatBoth)
709  set since $::tr(OprepStatSince)
710  set games [::utils::string::Capital $::tr(games)]
711  set score [::utils::string::Capital $::tr(score)]
712 
713  set alen [string length $all]
714  set blen [expr {[string length $both] + 6}]
715  set slen [expr {[string length $since] + 11}]
716  set len $alen
717  if {$len < $blen} { set len $blen}
718  if {$len < $slen} { set len $slen}
719 
720  set ratings 0
721  set years 0
722  set rlist [lsort -decreasing [array names stats r*]]
723  set ylist [lsort [array names stats y*]]
724  foreach i $rlist { if {$stats($i)} { set ratings 1}}
725  foreach i $ylist { if {$stats($i)} { set years 1}}
726 
727  if {$fmt == "latex"} {
728  append s "\\begin{tabular}{l r r r r r @{.} l}\n\\hline\n"
729  append s " & $games & \\win & \\draw & \\loss & "
730  append s "\\multicolumn{2}{c}{$score} \\tspace \\\\ \\hline \n"
731  scan [sc_filter stats all] "%u%u%u%u%u%\[.,\]%u" g w d l p c x
732  append s "$all & $g & $w & $d & $l & $p&$x\\% \\\\\n"
733 
734  if {$ratings} {
735  append s "\\hline\n"
736  foreach i $rlist {
737  if {$stats($i)} {
738  set elo [string range $i 1 end]
739  scan [sc_filter stats elo $elo] "%u%u%u%u%u%\[.,\]%u" g w d l p c x
740  append s "$both $elo+ & $g & $w & $d & $l & $p&$x\\% \\\\\n"
741  }
742  }
743  }
744  if {$years} {
745  append s "\\hline\n"
746  foreach i $ylist {
747  if {$stats($i)} {
748  set year [string range $i 1 end]
749  scan [sc_filter stats year $year] "%u%u%u%u%u%\[.,\]%u" g w d l p c x
750  append s "$since $year.01.01 & $g & $w & $d & $l & $p&$x\\% \\\\\n"
751  }
752  }
753  }
754  append s "\\hline\n\\end{tabular}\n"
755  return $s
756  }
757 
758  # For non-LaTeX format, just display in plain text:
759  if {$fmt == "html"} { append s "<pre>\n"}
760  if {$fmt == "ctext"} { append s "<tt>"}
761  set stat ""
762  append s " [::utils::string::Pad $stat [expr $len - 4]] [::utils::string::PadRight $games 10]"
763  append s " 1-0 =-= 0-1 [::utils::string::PadRight $score 8]\n"
764  append s "-----------------------------------------------------------"
765  append s "\n [::utils::string::Pad $all $len]" [sc_filter stats all]
766 
767  if {$ratings} {
768  append s "\n"
769  foreach i $rlist {
770  if {$stats($i)} {
771  set elo [string range $i 1 end]
772  set stat "$both $elo+"
773  append s "\n [::utils::string::Pad $stat $len]" [sc_filter stats elo $elo]
774  }
775  }
776  }
777  if {$years} {
778  append s "\n"
779  foreach i $ylist {
780  if {$stats($i)} {
781  set year [string range $i 1 end]
782  set stat "$since $year.01.01"
783  append s "\n [::utils::string::Pad $stat $len]" [sc_filter stats year $year]
784  }
785  }
786  }
787  append s "\n-----------------------------------------------------------\n"
788  if {$fmt == "html"} { append s "</pre>\n"}
789  if {$fmt == "ctext"} { append s "</tt>"}
790  return $s
791 }
792 
793 proc ::optable::_reset {} {
794  set ::optable::_data(sec) 0
795  set ::optable::_data(subsec) 0
796 }
797 
798 proc ::optable::_title {} {
799  set fmt $::optable::_data(fmt)
800  set title $::tr(OprepTitle)
801  if {$fmt == "latex"} {
802  return "\\begin{center}{\\LARGE \\bf $title}\\end{center}\n\n"
803  } elseif {$fmt == "html"} {
804  return "<h1><center>$title</center></h1>\n\n"
805  } elseif {$fmt == "ctext"} {
806  return "<h1><center>$title</center></h1>\n\n"
807  }
808  set r "--------------------------------------------------------------"
809  append r "\n [string toupper $title]\n"
810  append r "--------------------------------------------------------------"
811  append r "\n\n"
812  return $r
813 }
814 
815 proc ::optable::_sec {text} {
816  set fmt $::optable::_data(fmt)
817  incr ::optable::_data(sec)
818  set ::optable::_data(subsec) 0
819  if {$fmt == "latex"} {
820  return "\n\n\\section{$text}\n"
821  } elseif {$fmt == "html"} {
822  return "\n<h2>$::optable::_data(sec). $text</h2>\n"
823  } elseif {$fmt == "ctext"} {
824  return "<h4>$::optable::_data(sec). $text</h4>"
825  }
826  set line "$::optable::_data(sec). [string toupper $text]"
827  set underline "-----------------------------------------------------"
828  return "\n\n$line\n[string range $underline 1 [string length $line]]\n"
829 }
830 
831 proc ::optable::_subsec {text} {
832  set fmt $::optable::_data(fmt)
833  incr ::optable::_data(subsec)
834  if {$fmt == "latex"} {
835  return "\n\\subsection{$text}\n\n"
836  } elseif {$fmt == "html"} {
837  return "\n<h3>$::optable::_data(sec).$::optable::_data(subsec) $text</h3>\n\n"
838  } elseif {$fmt == "ctext"} {
839  return "\n<maroon><b>$::optable::_data(sec).$::optable::_data(subsec) $text</b></maroon>\n\n"
840  }
841  return "\n$::optable::_data(sec).$::optable::_data(subsec) $text\n\n"
842 }
843 ################################################################################
844 # report:
845 # Produces a report in the appropriate format. If "withTable" is true,
846 # the theory table is also included.
847 ################################################################################
848 proc ::optable::report {fmt withTable {flipPos 0}} {
849  global tr
850  sc_report opening format $fmt
851  set fmt [string tolower $fmt]
852  set ::optable::_data(fmt) $fmt
854 
855  # numRows: the number of rows to show in the theory table.
856  # If it is zero, the number of rows if decided according to the
857  # number of games in the report.
858  set numRows 0
859 
860  # Specify whether a theory table is to be printed, so note numbers
861  # can be generated and displayed if necessary:
862  sc_report opening notes $withTable $numRows
863 
864  set n "\n"; set p "\n\n"; set preText ""; set postText ""
865  set percent "%"; set bullet " * "
866  if {$fmt == "latex"} {
867  set n "\\\\\n"; set p "\n\n"
868  #set preText "{\\samepage\\begin{verbatim}\n"
869  #set postText "\\end{verbatim}\n}\n"
870  set percent "\\%"; set bullet "\\hspace{0.5cm}\$\\bullet\$"
871  } elseif {$fmt == "html"} {
872  set n "<br>\n"; set p "<p>\n\n"
873  set preText "<pre>\n"; set postText "</pre>\n"
874  } elseif {$fmt == "ctext"} {
875  set preText "<tt>"; set postText "</tt>"
876  }
877 
878  # Generate the report:
879  set games $tr(games)
880  set moves $tr(moves)
881  set counts [sc_report opening count]
882  set rgames [lindex $counts 0]
883  set tgames [lindex $counts 1]
884 
885  set r {}
886  append r $::optable::_docStart($fmt)
887  set title $::tr(OprepTitle)
888  set r [string map [list "\[OprepTitle\]" $title] $r]
889  append r [::optable::_title]
890  append r "$tr(Database): [file tail [sc_base filename $::curr_db]] "
891  append r "([::utils::thousands [sc_base numGames $::curr_db]] $games)$n"
892  append r "$tr(OprepReport): [::trans [sc_report opening line]] ("
893  if {$fmt == "ctext"} {
894  append r "<darkblue><run sc_report opening select all 0; ::windows::stats::Refresh>"
895  }
896  append r "$rgames"
897  if {$fmt == "ctext"} { append r "</run></darkblue>"; }
898  append r " $games)$n"
899  set eco [sc_report opening eco]
900  if {$eco != ""} {
901  append r "$tr(ECO): $eco$n"
902  }
903 
904  append r "$::tr(OprepGenerated) Scid $::scidVersion, [::utils::date::today]\n"
905  if {$fmt == "latex"} {
906  if {$flipPos} {
907  append r $::optable::_data(bdLaTeX_flip)
908  } else {
909  append r $::optable::_data(bdLaTeX)
910  }
911  append r {$$\showboard$$}
912  } elseif {$fmt == "html"} {
913  if {$flipPos} {
914  append r $::optable::_data(bdHTML_flip)
915  } else {
916  append r $::optable::_data(bdHTML)
917  }
918  } elseif {$fmt == "ctext"} {
919  append r "\n<center><window .oprepWin.text.bd></center>\n"
920  }
921  if {$rgames == 0} {
922  append r $::optable::_docEnd($fmt)
923  return $r
924  }
925 
926  if {$::optable(Stats) > 0 ||
927  $::optable(Oldest) > 0 ||
928  $::optable(Newest) > 0 ||
929  $::optable(Popular) > 0 ||
930  ($::optable(MostFrequent) > 0 &&
931  ($::optable(MostFrequentWhite) || $::optable(MostFrequentBlack)))} {
932  append r [::optable::_sec $tr(OprepStatsHist)]
933  }
934  if {$::optable(Stats)} {
935  append r [::optable::_subsec $tr(OprepStats)]
936  append r [::optable::stats $fmt]
937  }
938  if {$::optable(Oldest) > 0} {
939  append r [::optable::_subsec $tr(OprepOldest)]
940  append r [sc_report opening best o $::optable(Oldest)]
941  }
942  if {$::optable(Newest) > 0} {
943  append r [::optable::_subsec $tr(OprepNewest)]
944  append r [sc_report opening best n $::optable(Newest)]
945  }
946 
947  if {$::optable(Popular) > 0} {
948  append r [::optable::_subsec $tr(OprepPopular)]
949  set next ""
950  if {$fmt == "latex"} { set next " & "}
951 
952  # A table showing popularity by year ranges:
953  if {$fmt == "latex"} {
954  append r "\\begin{tabular}{lccccccc}\n\\hline\n"
955  } else {
956  append r $preText
957  }
958 
959  set sYear $tr(Year)
960  set sEvery [::utils::string::Capital $tr(OprepEvery)]
961  regsub "%u" $sEvery X sEvery
962  set len [string length $sYear]
963  if {[string length $sEvery] > $len} { set len [string length $sEvery]}
964  append r [::utils::string::Pad $tr(Year) $len]
965  foreach range {1800-99 1900-49 1950-69 1970-79 1980-89 1990-99 2000-09} {
966  append r $next
967  append r [::utils::string::PadCenter $range 8]
968  }
969 
970  append r $n
971  append r [::utils::string::Pad $sEvery $len]
972  foreach y {1800 1900 1950 1970 1980 1990 2000} {
973  append r $next
974  append r [::utils::string::PadCenter $::optable::_data(range$y) 8]
975  }
976  append r $n
977  if {$fmt == "latex"} {
978  append r "\\hline\n\\end{tabular}\n"
979  } else {
980  append r $postText
981  }
982 
983  append r "\n"
984 
985  # A table showing popularity in the last 1/5/10 years:
986  if {$fmt == "latex"} {
987  append r "\\begin{tabular}{lrr}\n"
988  }
989 
990  foreach y {All 10 5 1} {
991  if {$fmt == "ctext"} { append r "<tt>"}
992  append r $tr(OprepFreq$y)
993  if {$fmt == "ctext"} { append r "</tt>"}
994  append r $next
995  append r [format $tr(OprepEvery) $::optable::_data(ratio$y)]
996  if {$y != "All"} {
997  append r $next
998  set d $::optable::_data(delta$y)
999  if {$d > 0} {
1000  append r " ([format $tr(OprepUp) $d $percent])"
1001  } elseif {$d < 0} {
1002  append r " ([format $tr(OprepDown) [expr 0- $d] $percent])"
1003  } else {
1004  append r " ($tr(OprepSame))"
1005  }
1006  }
1007  append r "$n"
1008  }
1009  if {$fmt == "latex"} {
1010  append r "\\end{tabular}\n"
1011  }
1012  }
1013 
1014  if {$::optable(MostFrequent) > 0 && $::optable(MostFrequentWhite)} {
1015  append r [::optable::_subsec "$tr(OprepMostFrequent) ($tr(White))"]
1016  append r [sc_report opening players white $::optable(MostFrequent)]
1017  }
1018  if {$::optable(MostFrequent) > 0 && $::optable(MostFrequentBlack)} {
1019  append r [::optable::_subsec "$tr(OprepMostFrequent) ($tr(Black))"]
1020  append r [sc_report opening players black $::optable(MostFrequent)]
1021  }
1022 
1023  if {$::optable(AvgPerf) || $::optable(HighRating)} {
1024  append r [::optable::_sec $tr(OprepRatingsPerf)]
1025  }
1026  if {$::optable(AvgPerf)} {
1027  append r [::optable::_subsec $tr(OprepAvgPerf)]
1028  set e [sc_report opening elo white]
1029  set welo [lindex $e 0]; set wng [lindex $e 1]
1030  set bpct [lindex $e 2]; set bperf [lindex $e 3]
1031  set e [sc_report opening elo black]
1032  set belo [lindex $e 0]; set bng [lindex $e 1]
1033  set wpct [lindex $e 2]; set wperf [lindex $e 3]
1034  append r "$tr(OprepWRating): $welo ($wng $games); "
1035  append r "$tr(OprepWPerf): $wperf ($wpct$percent vs $belo)$n"
1036  append r "$tr(OprepBRating): $belo ($bng $games); "
1037  append r "$tr(OprepBPerf): $bperf ($bpct$percent vs $welo)$n"
1038  }
1039 
1040  if {$::optable(HighRating) > 0} {
1041  append r [::optable::_subsec $tr(OprepHighRating)]
1042  append r [sc_report opening best a $::optable(HighRating)]
1043  }
1044 
1045  if {$::optable(Results) ||
1046  ($::optable(Shortest) > 0 &&
1047  ($::optable(ShortestBlack) || $::optable(ShortestBlack)))} {
1048  append r [::optable::_sec $tr(OprepTrends)]
1049  }
1050 
1051  if {$::optable(Results)} {
1052  append r [::optable::_subsec $::tr(OprepResults)]
1053  append r [::optable::results opening $fmt]
1054  }
1055 
1056  if {$::optable(Shortest) > 0 && $::optable(ShortestWhite)} {
1057  append r [::optable::_subsec "$tr(OprepShortest) ($tr(White))"]
1058  append r [sc_report opening best w $::optable(Shortest)]
1059  }
1060  if {$::optable(Shortest) > 0 && $::optable(ShortestBlack)} {
1061  append r [::optable::_subsec "$tr(OprepShortest) ($tr(Black))"]
1062  append r [sc_report opening best b $::optable(Shortest)]
1063  }
1064 
1065  if {$::optable(MoveOrders) > 0 ||
1066  $::optable(MovesFrom) > 0 ||
1067  $::optable(Themes) > 0 ||
1068  $::optable(Endgames) > 0} {
1069  append r [::optable::_sec $tr(OprepMovesThemes)]
1070  }
1071  if {$::optable(MoveOrders) > 0} {
1072  append r [::optable::_subsec $tr(OprepMoveOrders)]
1073  set nOrders [sc_report opening moveOrders 0]
1074  set maxOrders $::optable(MoveOrders)
1075  if {$nOrders == 1} {
1076  append r $tr(OprepMoveOrdersOne)
1077  } elseif {$nOrders <= $maxOrders} {
1078  append r [format $tr(OprepMoveOrdersAll) $nOrders]
1079  } else {
1080  append r [format $tr(OprepMoveOrdersMany) $nOrders $maxOrders]
1081  }
1082  append r $n
1083  append r [::trans [sc_report opening moveOrders $maxOrders]]
1084  }
1085  if {$::optable(MovesFrom)} {
1086  append r [::optable::_subsec $tr(OprepMovesFrom)]
1087  if {$fmt == "latex"} {
1088  append r $::optable::_data(latexTree)
1089  } else {
1090  append r $preText
1091  append r $::optable::_data(tree)
1092  append r $postText
1093  }
1094  }
1095 
1096  if {$::optable(Themes) > 0} {
1097  append r [::optable::_subsec $tr(OprepThemes)]
1098  append r [sc_report opening themes $tr(OprepThemeDescription:) \
1099  $tr(OprepThemeSameCastling:) $tr(OprepThemeOppCastling:) \
1100  $tr(OprepThemeKPawnStorm:) $tr(OprepThemeQueenswap:) \
1101  $tr(OprepTheme1BishopPair:) \
1102  $tr(OprepThemeWIQP:) $tr(OprepThemeBIQP:) \
1103  $tr(OprepThemeWP567:) $tr(OprepThemeBP234:) \
1104  $tr(OprepThemeOpenCDE:)]
1105  }
1106 
1107  if {$::optable(Endgames) > 0} {
1108  append r [::optable::_subsec $tr(OprepEndgames)]
1109  append r "$tr(OprepEndClass:)$n"
1110  append r [sc_report opening endmat]
1111  }
1112 
1113  if {$withTable && $::optable(MaxGames) > 0} {
1114  set sec [::optable::_sec $tr(OprepTheoryTable)]
1115  set comment ""
1116  if {$tgames > $::optable(MaxGames)} {
1117  set comment [format $tr(OprepTableComment) $::optable(MaxGames)]
1118  }
1119  append r [sc_report opening print $numRows $sec $comment]
1120  # puts [sc_report opening print $numRows $sec $comment]
1121  }
1122 
1123  append r $::optable::_docEnd($fmt)
1124 
1125  # Eszet (ss) characters seem to be mishandled by LaTeX, even with
1126  # the font encoding package, so convert them explicitly:
1127  if {$fmt == "latex"} { regsub -all ß $r {{\\ss}} r}
1128 
1129  return $r
1130 }
1131 
1132 # table:
1133 # Produces only the ECO table, not any other part of the report.
1134 #
1135 proc ::optable::table {fmt} {
1136  sc_report opening format $fmt
1137  set ::optable::_data(fmt) $fmt
1138  set r {}
1139  append r $::optable::_docStart($fmt)
1140  set r [string map [list "\[OprepTitle\]" $::tr(OprepTitle)] $r]
1141  append r [sc_report opening print]
1142  append r $::optable::_docEnd($fmt)
1143  return $r
1144 }
1145 
1146 
1147 set reportFavorites {}
1148 
1149 # updateFavoritesMenu
1150 # Update the Favorites menu in the report window, adding a
1151 # command for each favorite report position.
1152 #
1153 proc ::optable::updateFavoritesMenu {} {
1154  set m .oprepWin.menu.favorites
1155  $m delete 3 end
1156  $m add separator
1157  foreach entry $::reportFavorites {
1158  set name [lindex $entry 0]
1159  set moves [lindex $entry 1]
1160  $m add command -label $name \
1161  -command "importMoveList [list $moves]; ::optable::makeReportWin"
1162  }
1163  if {[llength $::reportFavorites] == 0} {
1164  $m entryconfigure 1 -state disabled
1165  $m entryconfigure 2 -state disabled
1166  } else {
1167  $m entryconfigure 1 -state normal
1168  $m entryconfigure 2 -state normal
1169  }
1170 }
1171 
1172 # favoriteReportNames
1173 # Return a list of the favorite report names.
1174 #
1175 proc ::optable::favoriteReportNames {} {
1176  set reportNames {}
1177  foreach entry $::reportFavorites {
1178  lappend reportNames [lindex $entry 0]
1179  }
1180  return $reportNames
1181 }
1182 
1183 # addFavoriteDlg
1184 # Adds the current position to the opening report favorites list.
1185 #
1186 proc ::optable::addFavoriteDlg {} {
1187  set w .addFavoriteDlg
1189  wm title $w "Scid: Add Opening Report Favorite"
1190  ttk::label $w.name -text "Enter a name for the opening report of this position:"
1191  pack $w.name -side top
1192  # label $w.name2 -text "(Use letters, digits, spaces and underscores only)"
1193  # pack $w.name2 -side top
1194  ttk::entry $w.e -width 40
1195  pack $w.e -side top -fill x -padx 2
1197  ttk::label $w.old -text "Existing favorite report names:"
1198  pack $w.old -side top
1199  pack [ttk::frame $w.existing] -side top -fill x -padx 2
1200  text $w.existing.list -width 30 -height 10 -background gray90 \
1201  -yscrollcommand [list $w.existing.ybar set]
1202  ttk::scrollbar $w.existing.ybar -command [list $w.existing.list yview]
1203  pack $w.existing.ybar -side right -fill y
1204  pack $w.existing.list -side left -fill both -expand yes
1205  foreach entry $::reportFavorites {
1206  $w.existing.list insert end "[lindex $entry 0]\n"
1207  }
1208  $w.existing.list configure -state disabled
1210  ttk::frame $w.b
1211  pack $w.b -side bottom -fill x
1212  ttk::button $w.b.ok -text OK -command ::optable::addFavoriteOK
1213  ttk::button $w.b.cancel -text $::tr(Cancel) -command "grab release $w; destroy $w"
1214  packdlgbuttons $w.b.cancel $w.b.ok
1215  focus $w.e
1216  grab $w
1217 }
1218 
1219 proc ::optable::addFavoriteOK {} {
1220  global reportFavorites
1221  set w .addFavoriteDlg
1222  set reportName [$w.e get]
1223  set err ""
1224  if {$reportName == ""} {
1225  set err "The report name must not be empty."
1226  } elseif {[lsearch -exact [::optable::favoriteReportNames] $reportName] >= 0} {
1227  set err "That name is already used for another favorite report position."
1228  } else {
1229  lappend reportFavorites [list $reportName [sc_game moves]]
1232  grab release $w
1233  destroy $w
1234  return
1235  }
1236  tk_messageBox -title Scid -icon info -type ok -message $err
1237 }
1238 
1239 set reportFavoritesName ""
1240 
1241 # editFavoritesDlg
1242 # Open the dialog box for editing the list of opening report
1243 # favorite positions.
1244 #
1245 proc ::optable::editFavoritesDlg {} {
1246  global reportFavorites reportFavoritesTemp reportFavoritesName
1247  set w .editFavoritesDlg
1248  if {[winfo exists $w]} { return}
1249 
1250  set ::reportFavoritesTemp $::reportFavorites
1252  wm title $w "Scid: [tr OprepFavoritesEdit]"
1253  # wm transient $w .
1254  bind $w <F1> {helpWindow Reports Opening}
1255  ttk::entry $w.e -width 60 \
1256  -textvariable reportFavoritesName -exportselection 0
1257  bind $w.e <FocusIn> "$w.e configure -background lightYellow"
1258  bind $w.e <FocusOut> "$w.e configure -background white"
1259 
1260  trace variable reportFavoritesName w ::optable::editFavoritesRefresh
1261  pack $w.e -side top -fill x
1262  pack [ttk::frame $w.b] -side bottom -fill x
1263  autoscrollframe $w.f listbox $w.f.list -width 50 -height 10 \
1264  -fg black -bg white -exportselection 0 -font font_Small -setgrid 1
1265  pack $w.f -side top -fill both -expand yes
1266  bind $w.f.list <<ListboxSelect>> ::optable::editFavoritesSelect
1267  foreach entry $::reportFavoritesTemp {
1268  set name [lindex $entry 0]
1269  set moves [lindex $entry 1]
1270  $w.f.list insert end "$name \[$moves\]"
1271  }
1272  ttk::button $w.b.delete -text $::tr(Delete) -command ::optable::editFavoritesDelete
1273  ttk::button $w.b.up -image tb_up -command {::optable::editFavoritesMove up}
1274  ttk::button $w.b.down -image tb_down -command {::optable::editFavoritesMove down}
1275  ttk::button $w.b.ok -text "OK" -command ::optable::editFavoritesOK
1276  ttk::button $w.b.cancel -text $::tr(Cancel) -command {
1277  catch {grab release .editFavoritesDlg}
1278  destroy .editFavoritesDlg
1279  }
1280  pack $w.b.delete $w.b.up $w.b.down -side left -padx 2 -pady 2
1281  packdlgbuttons $w.b.cancel $w.b.ok
1282  set editFavoritesName ""
1283 
1284  wm withdraw $w
1285  update idletasks
1286  set x [expr {[winfo screenwidth $w]/2 - [winfo reqwidth $w]/2 \
1287  - [winfo vrootx .]}]
1288  set y [expr {[winfo screenheight $w]/2 - [winfo reqheight $w]/2 \
1289  - [winfo vrooty .]}]
1290  wm geom $w +$x+$y
1291  wm protocol $w WM_DELETE_WINDOW [list $w.b.cancel invoke]
1292  wm deiconify $w
1293  update
1294  catch {grab $w}
1295 }
1296 
1297 proc ::optable::editFavoritesRefresh {args} {
1298  global reportFavoritesTemp reportFavoritesName
1299  set list .editFavoritesDlg.f.list
1300  set sel [lindex [$list curselection] 0]
1301  if {$sel == ""} { return}
1302  set name $reportFavoritesName
1303  set e [lindex $reportFavoritesTemp $sel]
1304  set moves [lindex $e 1]
1305  set e [lreplace $e 0 0 $name]
1306  set reportFavoritesTemp [lreplace $reportFavoritesTemp $sel $sel $e]
1307  $list insert $sel "$name \[$moves\]"
1308  $list delete [expr $sel + 1]
1309  $list selection clear 0 end
1310  $list selection set $sel
1311 }
1312 
1313 proc ::optable::editFavoritesSelect {} {
1314  set list .editFavoritesDlg.f.list
1315  set sel [lindex [$list curselection] 0]
1316  if {$sel == ""} {
1317  set ::reportFavoritesName ""
1318  return
1319  }
1320  if {$sel >= [llength $::reportFavoritesTemp]} {
1321  $list selection clear 0 end
1322  set ::reportFavoritesName ""
1323  return
1324  }
1325  set e [lindex $::reportFavoritesTemp $sel]
1326  set ::reportFavoritesName [lindex $e 0]
1327 }
1328 
1329 proc ::optable::editFavoritesDelete {} {
1330  global reportFavoritesTemp
1331  set w .editFavoritesDlg
1332  set list $w.f.list
1333  set sel [lindex [$list curselection] 0]
1334  if {$sel == ""} { return}
1335  set reportFavoritesTemp [lreplace $reportFavoritesTemp $sel $sel]
1336  $list selection clear 0 end
1337  $list delete $sel
1338  set ::reportFavoritesName ""
1339 
1340 }
1341 
1342 proc ::optable::editFavoritesMove {dir} {
1343  global reportFavoritesTemp
1344  set w .editFavoritesDlg
1345  set list $w.f.list
1346  set sel [lindex [$list curselection] 0]
1347  if {$sel == ""} { return}
1348  set e [lindex $reportFavoritesTemp $sel]
1349  set name [lindex $e 0]
1350  set moves [lindex $e 1]
1351  set text "$name \[$moves\]"
1352 
1353  set newsel $sel
1354  if {$dir == "up"} {
1355  incr newsel -1
1356  if {$newsel < 0} { return}
1357  } else {
1358  incr newsel
1359  if {$newsel >= [$list index end]} { return}
1360  }
1361  set reportFavoritesTemp [lreplace $reportFavoritesTemp $sel $sel]
1362  set reportFavoritesTemp [linsert $reportFavoritesTemp $newsel $e]
1363  $list selection clear 0 end
1364  $list delete $sel
1365  $list insert $newsel $text
1366  $list selection set $newsel
1367 }
1368 
1369 proc ::optable::editFavoritesOK {} {
1370  set w .editFavoritesDlg
1371  catch {grab release $w}
1372  destroy $w
1373  set ::reportFavorites $::reportFavoritesTemp
1376 }
1377 
1378 proc ::optable::favoritesFilename {} {
1379  return [scidConfigFile reports]
1380 }
1381 
1382 proc ::optable::saveFavorites {} {
1383  set fname [::optable::favoritesFilename]
1384  if {[catch {open $fname w} f]} {
1385  # tk_messageBox ...
1386  return
1387  }
1388  puts $f "# Scid opening report favorites file"
1389  puts $f ""
1390  puts $f "set reportFavorites [list $::reportFavorites]"
1391  close $f
1392 }
1393 
1394 proc ::optable::loadFavorites {} {
1395  global reportFavorites
1396  set fname [::optable::favoritesFilename]
1397  catch {source $fname}
1398 }
1399 
1401 
1402 set reportFormat html
1403 set reportType full
1404 
1405 proc ::optable::generateFavoriteReports {} {
1406  global reportFavorites
1407  if {[llength $reportFavorites] == 0} {
1408  tk_messageBox -title "Scid" -type ok -icon info \
1409  -message "You have no favorite report positions."
1410  return
1411  }
1412  set ::reportDir $::initialDir(report)
1413 
1414  set w .reportFavoritesDlg
1415  if {[winfo exists $w]} { return}
1417  wm title $w "Scid: Generate Reports..."
1418  pack [ttk::label $w.typelabel -text "Select the report type:" -font font_Bold] -side top -anchor w
1419  pack [ttk::frame $w.type] -side top -anchor w
1420  ttk::radiobutton $w.type.full -text "Full" -variable reportType -value full
1421  ttk::radiobutton $w.type.compact -text "Compact (no theory table)" -variable reportType -value compact
1422  ttk::radiobutton $w.type.theory -text "Theory table only" -variable reportType -value theory
1423  pack $w.type.full $w.type.compact $w.type.theory -side left -padx 5
1425  pack [ttk::label $w.fmtlabel -text "Select the report file format:" -font font_Bold] -side top -anchor w
1426  pack [ttk::frame $w.fmt] -side top -anchor w
1427  ttk::radiobutton $w.fmt.text -text "Plain text (.txt)" -variable reportFormat -value text
1428  ttk::radiobutton $w.fmt.html -text "HTML" -variable reportFormat -value html
1429  ttk::radiobutton $w.fmt.latex -text "LaTeX" -variable reportFormat -value latex
1430  pack $w.fmt.text $w.fmt.html $w.fmt.latex -side left -padx 5
1432  pack [ttk::frame $w.dir] -side top
1433  ttk::label $w.dir.label -text "Save reports in the folder: " -font font_Bold
1434  ttk::entry $w.dir.entry -textvariable ::reportDir
1435  ttk::button $w.dir.choose -text $::tr(Browse...) -command {
1436  set tmpdir [tk_chooseDirectory -parent .reportFavoritesDlg \
1437  -title "Scid: Choose Report Folder"]
1438  if {$tmpdir != ""} {
1439  set ::reportDir [file nativename $tmpdir]
1440  }
1441  }
1442  pack $w.dir.label -side left
1443  pack $w.dir.choose -side right -pady 3
1444  pack $w.dir.entry -side left -fill x -padx 5
1446  pack [ttk::frame $w.b] -side bottom -fill x
1447  ttk::button $w.b.ok -text "OK"\
1448  -command "::optable::reportFavoritesOK; grab release $w; destroy $w; ::optable::makeReportWin"
1449  ttk::button $w.b.cancel -text $::tr(Cancel) -command "grab release $w; destroy $w"
1450  packdlgbuttons $w.b.cancel $w.b.ok
1451  grab $w
1452 }
1453 
1454 proc ::optable::reportFavoritesOK {} {
1455  global reportDir reportFormat reportType
1456  set ::initialDir(report) $reportDir
1457  set fmt $reportFormat
1458  switch $reportFormat {
1459  "html" { set suffix ".html"}
1460  "text" { set suffix ".txt"}
1461  "latex" { set suffix "tex"}
1462  }
1463 
1464  set w .reportsProgress
1465  toplevel $w
1466  wm withdraw $w
1467  wm title $w "Scid: Generating Reports"
1468  bind $w <Visibility> "raiseWin $w"
1469  pack [ttk::label $w.t -width 40 -text "Generating reports. Please wait..." -font font_Bold] -side top -pady 5
1470  pack [ttk::label $w.report] -side top -pady 5
1472  wm deiconify $w
1473  grab $w
1474  update
1475 
1476  set count 0
1477  set total [llength $::reportFavorites]
1478  foreach entry $::reportFavorites {
1479  set name [lindex $entry 0]
1480  set moves [lindex $entry 1]
1481  set fname [file join $reportDir "$name$suffix"]
1482  if {[catch {open $fname w} f]} {
1483  tk_messageBox -title "Scid" -icon warning -type ok \
1484  -message "Unable to write file: $fname\n$f"
1485  grab release $w
1486  destroy $w
1487  return
1488  }
1489  incr count
1490  $w.report configure -text "$count / $total: $name$suffix"
1491  update
1492  sc_game push
1493  sc_move addSan $moves
1494  ::optable::makeReportWin -nodisplay -noprogress
1495  if {$reportType == "theory"} {
1496  set report [::optable::table $fmt]
1497  } elseif {$reportType == "compact"} {
1498  set report [::optable::report $fmt 0 $::optable::_flip]
1499  } else {
1500  set report [::optable::report $fmt 1 $::optable::_flip]
1501  }
1502  if {$::hasEncoding && $::langEncoding($::language) != ""} {
1503  catch {set report [encoding convertto $::langEncoding($::language) $report]}
1504  }
1505  sc_game pop
1506  puts $f $report
1507  close $f
1508  }
1509  grab release $w
1510  destroy $w
1511 }
1512 
1513 # end of optable.tcl