1# 2# tk/validation.rb - validation support module for entry, spinbox, and so on 3# 4require 'tk' 5 6module Tk 7 module ValidateConfigure 8 def self.__def_validcmd(scope, klass, keys=nil) 9 keys = klass._config_keys unless keys 10 keys.each{|key| 11 eval("def #{key}(*args, &b) 12 __validcmd_call(#{klass.name}, '#{key}', *args, &b) 13 end", scope) 14 } 15 end 16 17 def __validcmd_call(klass, key, *args, &b) 18 return cget(key) if args.empty? && !b 19 20 cmd = (b)? proc(&b) : args.shift 21 22 if cmd.kind_of?(klass) 23 configure(key, cmd) 24 elsif !args.empty? 25 configure(key, [cmd, args]) 26 else 27 configure(key, cmd) 28 end 29 end 30 31 def __validation_class_list 32 # maybe need to override 33 [] 34 end 35 36 def __get_validate_key2class 37 k2c = {} 38 __validation_class_list.each{|klass| 39 klass._config_keys.each{|key| 40 k2c[key.to_s] = klass 41 } 42 } 43 k2c 44 end 45 46 def __conv_vcmd_on_hash_kv(keys) 47 key2class = __get_validate_key2class 48 49 keys = _symbolkey2str(keys) 50 key2class.each{|key, klass| 51 if keys[key].kind_of?(Array) 52 cmd, *args = keys[key] 53 #keys[key] = klass.new(cmd, args.join(' ')) 54 keys[key] = klass.new(cmd, *args) 55 # elsif keys[key].kind_of?(Proc) || keys[key].kind_of?(Method) 56 elsif TkComm._callback_entry?(keys[key]) 57 keys[key] = klass.new(keys[key]) 58 end 59 } 60 keys 61 end 62 63 def create_self(keys) 64 super(__conv_vcmd_on_hash_kv(keys)) 65 end 66 private :create_self 67 68 def configure(slot, value=TkComm::None) 69 if slot.kind_of?(Hash) 70 super(__conv_vcmd_on_hash_kv(slot)) 71 else 72 super(__conv_vcmd_on_hash_kv(slot=>value)) 73 end 74 self 75 end 76=begin 77 def configure(slot, value=TkComm::None) 78 key2class = __get_validate_key2class 79 80 if slot.kind_of?(Hash) 81 slot = _symbolkey2str(slot) 82 key2class.each{|key, klass| 83 if slot[key].kind_of?(Array) 84 cmd, *args = slot[key] 85 slot[key] = klass.new(cmd, args.join(' ')) 86 elsif slot[key].kind_of?(Proc) || slot[key].kind_of?(Method) 87 slot[key] = klass.new(slot[key]) 88 end 89 } 90 super(slot) 91 92 else 93 slot = slot.to_s 94 if (klass = key2class[slot]) 95 if value.kind_of?(Array) 96 cmd, *args = value 97 value = klass.new(cmd, args.join(' ')) 98 elsif value.kind_of?(Proc) || value.kind_of?(Method) 99 value = klass.new(value) 100 end 101 end 102 super(slot, value) 103 end 104 105 self 106 end 107=end 108 end 109 110 module ItemValidateConfigure 111 def self.__def_validcmd(scope, klass, keys=nil) 112 keys = klass._config_keys unless keys 113 keys.each{|key| 114 eval("def item_#{key}(id, *args, &b) 115 __item_validcmd_call(#{klass.name}, '#{key}', id, *args, &b) 116 end", scope) 117 } 118 end 119 120 def __item_validcmd_call(tagOrId, klass, key, *args, &b) 121 return itemcget(tagid(tagOrId), key) if args.empty? && !b 122 123 cmd = (b)? proc(&b) : args.shift 124 125 if cmd.kind_of?(klass) 126 itemconfigure(tagid(tagOrId), key, cmd) 127 elsif !args.empty? 128 itemconfigure(tagid(tagOrId), key, [cmd, args]) 129 else 130 itemconfigure(tagid(tagOrId), key, cmd) 131 end 132 end 133 134 def __item_validation_class_list(id) 135 # maybe need to override 136 [] 137 end 138 139 def __get_item_validate_key2class(id) 140 k2c = {} 141 __item_validation_class_list(id).each{|klass| 142 klass._config_keys.each{|key| 143 k2c[key.to_s] = klass 144 } 145 } 146 end 147 148 def __conv_item_vcmd_on_hash_kv(keys) 149 key2class = __get_item_validate_key2class(tagid(tagOrId)) 150 151 keys = _symbolkey2str(keys) 152 key2class.each{|key, klass| 153 if keys[key].kind_of?(Array) 154 cmd, *args = keys[key] 155 #keys[key] = klass.new(cmd, args.join(' ')) 156 keys[key] = klass.new(cmd, *args) 157 # elsif keys[key].kind_of?(Proc) || keys[key].kind_of?(Method) 158 elsif TkComm._callback_entry?(keys[key]) 159 keys[key] = klass.new(keys[key]) 160 end 161 } 162 keys 163 end 164 165 def itemconfigure(tagOrId, slot, value=TkComm::None) 166 if slot.kind_of?(Hash) 167 super(__conv_item_vcmd_on_hash_kv(slot)) 168 else 169 super(__conv_item_vcmd_on_hash_kv(slot=>value)) 170 end 171 self 172 end 173=begin 174 def itemconfigure(tagOrId, slot, value=TkComm::None) 175 key2class = __get_item_validate_key2class(tagid(tagOrId)) 176 177 if slot.kind_of?(Hash) 178 slot = _symbolkey2str(slot) 179 key2class.each{|key, klass| 180 if slot[key].kind_of?(Array) 181 cmd, *args = slot[key] 182 slot[key] = klass.new(cmd, args.join(' ')) 183 elsif slot[key].kind_of?(Proc) || slot[key].kind_of?(Method) 184 slot[key] = klass.new(slot[key]) 185 end 186 } 187 super(slot) 188 189 else 190 slot = slot.to_s 191 if (klass = key2class[slot]) 192 if value.kind_of?(Array) 193 cmd, *args = value 194 value = klass.new(cmd, args.join(' ')) 195 elsif value.kind_of?(Proc) || value.kind_of?(Method) 196 value = klass.new(value) 197 end 198 end 199 super(slot, value) 200 end 201 202 self 203 end 204=end 205 end 206end 207 208class TkValidateCommand 209 include TkComm 210 extend TkComm 211 212 class ValidateArgs < TkUtil::CallbackSubst 213 KEY_TBL = [ 214 [ ?d, ?n, :action ], 215 [ ?i, ?x, :index ], 216 [ ?s, ?e, :current ], 217 [ ?v, ?s, :type ], 218 [ ?P, ?e, :value ], 219 [ ?S, ?e, :string ], 220 [ ?V, ?s, :triggered ], 221 [ ?W, ?w, :widget ], 222 nil 223 ] 224 225 PROC_TBL = [ 226 [ ?n, TkComm.method(:number) ], 227 [ ?s, TkComm.method(:string) ], 228 [ ?w, TkComm.method(:window) ], 229 230 [ ?e, proc{|val| 231 #enc = Tk.encoding 232 enc = ((Tk.encoding)? Tk.encoding : Tk.encoding_system) 233 if enc 234 Tk.fromUTF8(TkComm::string(val), enc) 235 else 236 TkComm::string(val) 237 end 238 } 239 ], 240 241 [ ?x, proc{|val| 242 idx = TkComm::number(val) 243 if idx < 0 244 nil 245 else 246 idx 247 end 248 } 249 ], 250 251 nil 252 ] 253 254=begin 255 # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) 256 KEY_TBL.map!{|inf| 257 if inf.kind_of?(Array) 258 inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) 259 inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) 260 end 261 inf 262 } 263 264 PROC_TBL.map!{|inf| 265 if inf.kind_of?(Array) 266 inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) 267 end 268 inf 269 } 270=end 271 272 _setup_subst_table(KEY_TBL, PROC_TBL); 273 274 # 275 # NOTE: The order of parameters which passed to callback procedure is 276 # <extra_arg>, <extra_arg>, ... , <subst_arg>, <subst_arg>, ... 277 # 278 279 #def self._get_extra_args_tbl 280 # # return an array of convert procs 281 # [] 282 #end 283 284 def self.ret_val(val) 285 (val)? '1': '0' 286 end 287 end 288 289 ############################################### 290 291 def self._config_keys 292 # array of config-option key (string or symbol) 293 ['vcmd', 'validatecommand', 'invcmd', 'invalidcommand'] 294 end 295 296 def _initialize_for_cb_class(klass, cmd = Proc.new, *args) 297 extra_args_tbl = klass._get_extra_args_tbl 298 299 if args.compact.size > 0 300 args.map!{|arg| klass._sym2subst(arg)} 301 args = args.join(' ') 302 keys = klass._get_subst_key(args) 303 if cmd.kind_of?(String) 304 id = cmd 305 elsif cmd.kind_of?(TkCallbackEntry) 306 @id = install_cmd(cmd) 307 else 308 @id = install_cmd(proc{|*arg| 309 ex_args = [] 310 extra_args_tbl.reverse_each{|conv| ex_args << conv.call(arg.pop)} 311 klass.ret_val(cmd.call( 312 *(ex_args.concat(klass.scan_args(keys, arg))) 313 )) 314 }) + ' ' + args 315 end 316 else 317 keys, args = klass._get_all_subst_keys 318 if cmd.kind_of?(String) 319 id = cmd 320 elsif cmd.kind_of?(TkCallbackEntry) 321 @id = install_cmd(cmd) 322 else 323 @id = install_cmd(proc{|*arg| 324 ex_args = [] 325 extra_args_tbl.reverse_each{|conv| ex_args << conv.call(arg.pop)} 326 klass.ret_val(cmd.call( 327 *(ex_args << klass.new(*klass.scan_args(keys, arg))) 328 )) 329 }) + ' ' + args 330 end 331 end 332 end 333 334 def initialize(cmd = Proc.new, *args) 335 _initialize_for_cb_class(self.class::ValidateArgs, cmd, *args) 336 end 337 338 def to_eval 339 @id 340 end 341end 342 343module TkValidation 344 include Tk::ValidateConfigure 345 346 class ValidateCmd < TkValidateCommand 347 module Action 348 Insert = 1 349 Delete = 0 350 Others = -1 351 Focus = -1 352 Forced = -1 353 Textvariable = -1 354 TextVariable = -1 355 end 356 end 357 358 ##################################### 359 360 def __validation_class_list 361 super() << ValidateCmd 362 end 363 364 Tk::ValidateConfigure.__def_validcmd(binding, ValidateCmd) 365 366=begin 367 def validatecommand(cmd = Proc.new, args = nil) 368 if cmd.kind_of?(ValidateCmd) 369 configure('validatecommand', cmd) 370 elsif args 371 configure('validatecommand', [cmd, args]) 372 else 373 configure('validatecommand', cmd) 374 end 375 end 376=end 377# def validatecommand(*args, &b) 378# __validcmd_call(ValidateCmd, 'validatecommand', *args, &b) 379# end 380# alias vcmd validatecommand 381 382=begin 383 def invalidcommand(cmd = Proc.new, args = nil) 384 if cmd.kind_of?(ValidateCmd) 385 configure('invalidcommand', cmd) 386 elsif args 387 configure('invalidcommand', [cmd, args]) 388 else 389 configure('invalidcommand', cmd) 390 end 391 end 392=end 393# def invalidcommand(*args, &b) 394# __validcmd_call(ValidateCmd, 'invalidcommand', *args, &b) 395# end 396# alias invcmd invalidcommand 397end 398