| 1 | #----------------------------------------------------------------------- |
|---|
| 2 | # TITLE: |
|---|
| 3 | # userprefs.tcl |
|---|
| 4 | # |
|---|
| 5 | # AUTHOR: |
|---|
| 6 | # Will Duquette |
|---|
| 7 | # |
|---|
| 8 | # DESCRIPTION: |
|---|
| 9 | # Notebook application user preferences. |
|---|
| 10 | # |
|---|
| 11 | # LICENSE: |
|---|
| 12 | # Copyright (C) 2002,2003,2004,2005 by William H. Duquette. |
|---|
| 13 | # This file may be used subject to the terms in license.txt. |
|---|
| 14 | |
|---|
| 15 | package require Tk |
|---|
| 16 | package require snit |
|---|
| 17 | |
|---|
| 18 | #----------------------------------------------------------------------- |
|---|
| 19 | # UserPrefs |
|---|
| 20 | |
|---|
| 21 | # prefs could be implemented as an ensemble: a type with no instances but |
|---|
| 22 | # only typemethods. For historical reasons, though, it's been |
|---|
| 23 | # implemented as a normal type with just one instance. |
|---|
| 24 | snit::type ::Notebook::prefsmanager { |
|---|
| 25 | # Preferences array |
|---|
| 26 | variable prefs |
|---|
| 27 | |
|---|
| 28 | # Observers array. index is observer name, value is command to execute. |
|---|
| 29 | variable observers |
|---|
| 30 | |
|---|
| 31 | # System font lists |
|---|
| 32 | variable fonts |
|---|
| 33 | |
|---|
| 34 | # Pseudo-preferences |
|---|
| 35 | # |
|---|
| 36 | # Pseudo-preferences aren't saved to the preferences file. |
|---|
| 37 | variable pseudoprefs { |
|---|
| 38 | defaultscaling |
|---|
| 39 | } |
|---|
| 40 | |
|---|
| 41 | constructor {} { |
|---|
| 42 | # Scaling Preference |
|---|
| 43 | set prefs(defaultscaling) [tk scaling] |
|---|
| 44 | set prefs(scaling) [tk scaling] |
|---|
| 45 | |
|---|
| 46 | # Font preferences |
|---|
| 47 | set prefs(bodytext) {Times 12} |
|---|
| 48 | set prefs(monotext) {Courier 10} |
|---|
| 49 | set prefs(header1text) {Helvetica 16 bold} |
|---|
| 50 | set prefs(header2text) {Helvetica 14 bold} |
|---|
| 51 | set prefs(header3text) {Helvetica 12 bold} |
|---|
| 52 | set prefs(titletext) {Helvetica 20} |
|---|
| 53 | set prefs(smalltext) {Helvetica 8} |
|---|
| 54 | |
|---|
| 55 | # Color preferences |
|---|
| 56 | set prefs(editorfg) black |
|---|
| 57 | set prefs(editorbg) white |
|---|
| 58 | set prefs(normalfg) black |
|---|
| 59 | set prefs(normalbg) white |
|---|
| 60 | set prefs(prefg) black |
|---|
| 61 | set prefs(prebg) white |
|---|
| 62 | set prefs(tclfg) black |
|---|
| 63 | set prefs(tclbg) white |
|---|
| 64 | set prefs(titlefg) blue |
|---|
| 65 | set prefs(titlebg) white |
|---|
| 66 | set prefs(linkfg) blue |
|---|
| 67 | set prefs(linkbg) white |
|---|
| 68 | set prefs(buttonfg) magenta |
|---|
| 69 | set prefs(buttonbg) white |
|---|
| 70 | set prefs(warningfg) red |
|---|
| 71 | set prefs(warningbg) white |
|---|
| 72 | set prefs(searchfg) white |
|---|
| 73 | set prefs(searchbg) red |
|---|
| 74 | |
|---|
| 75 | # Editor preferences |
|---|
| 76 | set prefs(tabwidth) 4 |
|---|
| 77 | set prefs(autowrap) 1 |
|---|
| 78 | set prefs(wrapcolumn) 74 |
|---|
| 79 | set prefs(autoindent) 1 |
|---|
| 80 | |
|---|
| 81 | # Tcl/Tk Preferences |
|---|
| 82 | set prefs(extpath) {} |
|---|
| 83 | |
|---|
| 84 | # Miscellaneous Options |
|---|
| 85 | set prefs(includetour) 1 |
|---|
| 86 | set prefs(editbottom) 0 |
|---|
| 87 | set prefs(displaydirectives) 0 |
|---|
| 88 | set prefs(silentcreation) 0 |
|---|
| 89 | set prefs(showsidebar) 0 |
|---|
| 90 | set prefs(incrementalsearch) 1 |
|---|
| 91 | set prefs(contentsearch) 1 |
|---|
| 92 | |
|---|
| 93 | # Initialize font lists |
|---|
| 94 | set fonts(all) {} |
|---|
| 95 | set fonts(mono) {} |
|---|
| 96 | set fonts(prop) {} |
|---|
| 97 | } |
|---|
| 98 | |
|---|
| 99 | # Register observer. obj is the observing object; command is the |
|---|
| 100 | # command to execute when preferences are saved. |
|---|
| 101 | method register {obj command} { |
|---|
| 102 | set observers($obj) $command |
|---|
| 103 | } |
|---|
| 104 | |
|---|
| 105 | # Unregister observer. obj is the observing object. |
|---|
| 106 | method unregister {obj} { |
|---|
| 107 | unset observers($obj) |
|---|
| 108 | } |
|---|
| 109 | |
|---|
| 110 | # Set a preference variable's value |
|---|
| 111 | method set {var value} { |
|---|
| 112 | # HACK: handle translation of "headertext" to "header[123]text" |
|---|
| 113 | # This handles a preferences change in V2.1.1 |
|---|
| 114 | if {$var eq "headertext"} { |
|---|
| 115 | $self set header1text $value |
|---|
| 116 | $self set header2text $value |
|---|
| 117 | $self set header3text $value |
|---|
| 118 | return |
|---|
| 119 | } |
|---|
| 120 | |
|---|
| 121 | # Retain and save unknown preferences; this means they can |
|---|
| 122 | # switch between this version and a later version with more |
|---|
| 123 | # preferences and not have any trouble. |
|---|
| 124 | set prefs($var) $value |
|---|
| 125 | } |
|---|
| 126 | |
|---|
| 127 | # Get a preference variable's value |
|---|
| 128 | method get {var} { |
|---|
| 129 | if {[info exists prefs($var)]} { |
|---|
| 130 | return $prefs($var) |
|---|
| 131 | } else { |
|---|
| 132 | error "Unknown prefs variable: '$var'" |
|---|
| 133 | } |
|---|
| 134 | } |
|---|
| 135 | |
|---|
| 136 | # Load the preferences from disk. The file name is system-dependent. |
|---|
| 137 | method load {} { |
|---|
| 138 | set fname [PrefFileName] |
|---|
| 139 | |
|---|
| 140 | if {[file exists $fname]} { |
|---|
| 141 | try { |
|---|
| 142 | source [PrefFileName] |
|---|
| 143 | tk scaling $prefs(scaling) |
|---|
| 144 | } catch -msg errmsg { |
|---|
| 145 | msg "Error in user preferences file '$fname'; preferences might not be set. The error was: $errmsg" |
|---|
| 146 | } |
|---|
| 147 | } |
|---|
| 148 | } |
|---|
| 149 | |
|---|
| 150 | # Save the preferences and notify observers. |
|---|
| 151 | method save {} { |
|---|
| 152 | try { |
|---|
| 153 | set f [open [PrefFileName] w] |
|---|
| 154 | |
|---|
| 155 | puts $f "# Notebook [version] Preferences File" |
|---|
| 156 | foreach name [array names prefs] { |
|---|
| 157 | if {[lsearch -exact $pseudoprefs $name] != -1} { |
|---|
| 158 | continue |
|---|
| 159 | } |
|---|
| 160 | puts $f [list prefs set $name $prefs($name)] |
|---|
| 161 | } |
|---|
| 162 | puts $f "# End of preferences" |
|---|
| 163 | close $f |
|---|
| 164 | } catch -msg errmsg { |
|---|
| 165 | msg "Could not save user preferences to [PrefFileName]: $errmsg" |
|---|
| 166 | } |
|---|
| 167 | |
|---|
| 168 | $self NotifyObservers |
|---|
| 169 | } |
|---|
| 170 | |
|---|
| 171 | # Pop up the preferences dialog; create it if it hasn't yet been |
|---|
| 172 | # seen. |
|---|
| 173 | method dialog {} { |
|---|
| 174 | # Create the dialog, if one doesn't exist. |
|---|
| 175 | if {"" == [info commands .prefsdialog]} { |
|---|
| 176 | ::Notebook::prefsdialog .prefsdialog |
|---|
| 177 | } |
|---|
| 178 | |
|---|
| 179 | # Make sure it's visible. |
|---|
| 180 | .prefsdialog show |
|---|
| 181 | } |
|---|
| 182 | |
|---|
| 183 | # Return a list of monospace fonts defined by the system. |
|---|
| 184 | method monofonts {} { |
|---|
| 185 | $self LoadFonts |
|---|
| 186 | return $fonts(mono) |
|---|
| 187 | } |
|---|
| 188 | |
|---|
| 189 | # Return a list of proportional fonts defined by the system. |
|---|
| 190 | method propfonts {} { |
|---|
| 191 | $self LoadFonts |
|---|
| 192 | return $fonts(prop) |
|---|
| 193 | } |
|---|
| 194 | |
|---|
| 195 | # Return a list of *all* fonts defined by the system. |
|---|
| 196 | method fonts {} { |
|---|
| 197 | $self LoadFonts |
|---|
| 198 | return $fonts(all) |
|---|
| 199 | } |
|---|
| 200 | |
|---|
| 201 | #----------------------------------------------------------------------- |
|---|
| 202 | # Private methods and procs |
|---|
| 203 | |
|---|
| 204 | # Determine the preference file name based on the platform |
|---|
| 205 | proc PrefFileName {} { |
|---|
| 206 | global tcl_platform |
|---|
| 207 | global env |
|---|
| 208 | |
|---|
| 209 | # This is the only way to reference Tcl/Tk Aqua as opposed to |
|---|
| 210 | # the X11 version |
|---|
| 211 | if {[tk windowingsystem] eq "aqua"} { |
|---|
| 212 | return [file join $env(HOME) "Library/Preferences/NotebookPrefs"] |
|---|
| 213 | } |
|---|
| 214 | |
|---|
| 215 | switch $tcl_platform(platform) { |
|---|
| 216 | "macintosh" { |
|---|
| 217 | # This is classic Mac only |
|---|
| 218 | return [file join $env(PREF_FOLDER) "Notebook Preferences"] |
|---|
| 219 | } |
|---|
| 220 | "windows" { |
|---|
| 221 | if {[info exists env(HOME)]} { |
|---|
| 222 | return [file join $env(HOME) "notebook.cfg"] |
|---|
| 223 | } else { |
|---|
| 224 | return [file join "C:/" "notebook.cfg"] |
|---|
| 225 | } |
|---|
| 226 | } |
|---|
| 227 | "unix" - |
|---|
| 228 | default { |
|---|
| 229 | if {[info exists env(DOTDIR)]} { |
|---|
| 230 | return "$env(DOTDIR)/.notebookrc" |
|---|
| 231 | } else { |
|---|
| 232 | return "$env(HOME)/.notebookrc" |
|---|
| 233 | } |
|---|
| 234 | } |
|---|
| 235 | } |
|---|
| 236 | } |
|---|
| 237 | |
|---|
| 238 | # Notify all registered observers that preferences have changed. |
|---|
| 239 | method NotifyObservers {} { |
|---|
| 240 | foreach name [array names observers] { |
|---|
| 241 | uplevel #0 $observers($name) |
|---|
| 242 | } |
|---|
| 243 | } |
|---|
| 244 | |
|---|
| 245 | # Load system fonts, if they've not already been loaded. |
|---|
| 246 | method LoadFonts {} { |
|---|
| 247 | if {[llength $fonts(all)] != 0} { |
|---|
| 248 | return |
|---|
| 249 | } |
|---|
| 250 | |
|---|
| 251 | # Get all fonts. |
|---|
| 252 | set fontnames [font families] |
|---|
| 253 | |
|---|
| 254 | # Tcl defines these names on all platforms, so add them to list |
|---|
| 255 | # if they aren't already there. |
|---|
| 256 | foreach name {Courier Times Helvetica} { |
|---|
| 257 | if {[lsearch $fontnames $name] == -1} { |
|---|
| 258 | lappend fontnames $name |
|---|
| 259 | } |
|---|
| 260 | } |
|---|
| 261 | |
|---|
| 262 | # On Tcl/Tk Aqua there are some problematic font names; |
|---|
| 263 | # they all begin with non-alpha characters. |
|---|
| 264 | foreach font $fontnames { |
|---|
| 265 | set initial [string index $font 0] |
|---|
| 266 | if {![string is alpha $initial]} { |
|---|
| 267 | continue |
|---|
| 268 | } |
|---|
| 269 | |
|---|
| 270 | lappend fonts(all) $font |
|---|
| 271 | } |
|---|
| 272 | |
|---|
| 273 | set fonts(all) [lsort $fonts(all)] |
|---|
| 274 | |
|---|
| 275 | # Create lists of monospace and proportional fonts. |
|---|
| 276 | foreach font $fonts(all) { |
|---|
| 277 | if {[font metrics [list $font] -fixed]} { |
|---|
| 278 | lappend fonts(mono) $font |
|---|
| 279 | } else { |
|---|
| 280 | lappend fonts(prop) $font |
|---|
| 281 | } |
|---|
| 282 | } |
|---|
| 283 | } |
|---|
| 284 | } |
|---|
| 285 | |
|---|
| 286 | # Create one instance of this object. |
|---|
| 287 | ::Notebook::prefsmanager create ::Notebook::prefs |
|---|
| 288 | |
|---|
| 289 | namespace eval ::Notebook:: { |
|---|
| 290 | namespace export prefs |
|---|
| 291 | } |
|---|
| 292 | |
|---|
| 293 | |
|---|