1: # diodisplay.tcl -- 2: 3: # Copyright 2002-2004 The Apache Software Foundation 4: 5: # Licensed under the Apache License, Version 2.0 (the "License"); 6: # you may not use this file except in compliance with the License. 7: # You may obtain a copy of the License at 8: 9: # http://www.apache.org/licenses/LICENSE-2.0 10: 11: # Unless required by applicable law or agreed to in writing, software 12: # distributed under the License is distributed on an "AS IS" BASIS, 13: # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14: # See the License for the specific language governing permissions and 15: # limitations under the License. 16: # 17: # $Id: diodisplay.tcl,v 1.19 2005/01/12 17:41:22 karl Exp $ 18: # 19: 20: package require Itcl 21: package require DIO 22: package require form 23: 24: package provide DIODisplay 1.0 25: 26: catch { ::itcl::delete class DIODisplay } 27: 28: ::itcl::class ::DIODisplay { 29: constructor {args} { 30: eval configure $args 31: load_response 32: 33: if {[lempty $DIO]} { 34: return -code error "You must specify a DIO object" 35: } 36: 37: if {[lempty $form]} { 38: set form [namespace which [::form #auto -defaults response]] 39: } 40: 41: set document [env DOCUMENT_NAME] 42: 43: if {[info exists response(num)] \ 44: && ![lempty $response(num)]} { 45: set pagesize $response(num) 46: } 47: 48: read_css_file 49: } 50: 51: destructor { 52: if {$cleanup} { do_cleanup } 53: } 54: 55: method destroy {} { 56: ::itcl::delete object $this 57: } 58: 59: # 60: # configvar - a convenient helper for creating methods that can 61: # set and fetch one of the object's variables 62: # 63: method configvar {varName string} { 64: if {[lempty $string]} { return [set $varName] } 65: configure -$varName $string 66: } 67: 68: # 69: # is_function - return true if name is known to be a function 70: # such as Search List Add Edit Delete Details Main Save DoDelete Cancel 71: # etc. 72: # 73: method is_function {name} { 74: if {[lsearch $functions $name] > -1} { return 1 } 75: if {[lsearch $allfunctions $name] > -1} { return 1 } 76: return 0 77: } 78: 79: # 80: # do_cleanup - clean up our field subobjects, DIO objects, forms, and the 81: # like. 82: # 83: method do_cleanup {} { 84: ## Destroy all the fields created. 85: foreach field $allfields { catch { $field destroy } } 86: 87: ## Destroy the DIO object. 88: catch { $DIO destroy } 89: 90: ## Destroy the form object. 91: catch { $form destroy } 92: } 93: 94: # 95: # handle_error - emit an error message 96: # 97: method handle_error {error} { 98: puts "<B>An error has occurred processing your request</B>" 99: puts "<PRE>" 100: puts "$error" 101: puts "" 102: puts "$::errorInfo" 103: puts "</PRE>" 104: } 105: 106: # 107: # read_css_file - parse and read in a CSS file so we can 108: # recognize CSS info and emit it in appropriate places 109: # 110: method read_css_file {} { 111: if {[lempty $css]} { return } 112: if {[catch {open [virtual_filename $css]} fp]} { return } 113: set contents [read $fp] 114: close $fp 115: array set tmpArray $contents 116: foreach class [array names tmpArray] { 117: set cssArray([string toupper $class]) $tmpArray($class) 118: } 119: } 120: 121: # 122: # get_css_class - figure out which CSS class we want to use. 123: # If class exists, we use that. If not, we use default. 124: # 125: method get_css_class {tag default class} { 126: 127: # if tag.class exists, use that 128: if {[info exists cssArray([string toupper $tag.$class])]} { 129: return $class 130: } 131: 132: # if .class exists, use that 133: if {[info exists cssArray([string toupper .$class])]} { 134: return $class 135: } 136: 137: # use the default 138: return $default 139: } 140: 141: # 142: # parse_css_class - given a class and the name of an array, parse 143: # the named CSS class (read from the style sheet) and return it as 144: # key-value pairs in the named array. 145: # 146: method parse_css_class {class arrayName} { 147: 148: # if we don't have an entry for the specified glass, give up 149: if {![info exists cssArray($class)]} { 150: return 151: } 152: 153: # split CSS entry on semicolons, for each one... 154: upvar 1 $arrayName array 155: foreach line [split $cssArray($class) \;] { 156: 157: # trim leading and trailing spaces 158: set line [string trim $line] 159: 160: # split the line on a colon into property and value 161: lassign [split $line :] property value 162: 163: # map the property to space-trimmed lowercase and 164: # space-trim the value, then store in the passed array 165: set property [string trim [string tolower $property]] 166: set value [string trim $value] 167: set array($property) $value 168: } 169: } 170: 171: # 172: # button_image_src - return the value of the image-src element in 173: # the specified class (from the CSS style sheet), or an empty 174: # string if there isn't one. 175: # 176: method button_image_src {class} { 177: set class [string toupper input.$class] 178: parse_css_class $class array 179: if {![info exists array(image-src)]} { 180: return 181: } 182: return $array(image-src) 183: } 184: 185: # state - return a list of name-value pairs that represents the current 186: # state of the query, which can be used to properly populate links 187: # outside DIOdisplay. 188: method state {} { 189: set state {} 190: foreach fld {mode query by how sort num page} { 191: if [info exists response($fld)] { 192: lappend state $fld $response($fld) 193: } 194: } 195: return $state 196: } 197: 198: method show {} { 199: 200: # if there's a mode in the response array, use that, else set 201: # mode to Main 202: set mode Main 203: if {[info exists response(mode)]} { 204: set mode $response(mode) 205: } 206: 207: # if there is a style sheet defined, emit HTML to reference it 208: if {![lempty $css]} { 209: puts "<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"$css\">" 210: } 211: 212: # put out the table header 213: puts {<TABLE WIDTH="100%" CLASS="DIO">} 214: puts "<TR>" 215: puts {<TD VALIGN="center" CLASS="DIO">} 216: 217: # if mode isn't Main and persistentmain is set (the default), 218: # run Main 219: if {$mode != "Main" && $persistentmain} { 220: Main 221: } 222: 223: if {![is_function $mode]} { 224: puts "In-valid function" 225: return 226: } 227: 228: if {[catch "$this $mode" error]} { 229: handle_error $error 230: } 231: 232: puts "</TD>" 233: puts "</TR>" 234: puts "</TABLE>" 235: 236: if {$cleanup} { destroy } 237: } 238: 239: method showview {} { 240: puts {<TABLE CLASS="DIOView">} 241: set row 0 242: foreach field $fields { 243: $field showview [lindex {"" "Alt"} $row] 244: set row [expr 1 - $row] 245: } 246: puts "</TABLE>" 247: } 248: 249: # 250: # showform_prolog - emit a form for inserting a new record 251: # 252: # response(by) will contain whatever was in the "where" field 253: # response(query) will contain whatever was in the "is" field 254: # 255: method showform_prolog {{args ""}} { 256: get_field_values array 257: 258: eval $form start $args 259: foreach fld [array names hidden] { 260: $form hidden $fld -value $hidden($fld) 261: } 262: $form hidden mode -value Save 263: $form hidden DIODfromMode -value $response(mode) 264: $form hidden DIODkey -value [$DIO makekey array] 265: puts {<TABLE CLASS="DIOForm">} 266: } 267: 268: method showform_epilog {} { 269: set save [button_image_src DIOFormSaveButton] 270: set cancel [button_image_src DIOFormCancelButton] 271: 272: puts "</TABLE>" 273: 274: puts "<TABLE>" 275: puts "<TR>" 276: puts "<TD>" 277: if {![lempty $save]} { 278: $form image save -src $save -class DIOFormSaveButton 279: } else { 280: $form submit save.x -value "Save" -class DIOFormSaveButton 281: } 282: puts "</TD>" 283: puts "<TD>" 284: if {![lempty $cancel]} { 285: $form image cancel -src $cancel -class DIOFormSaveButton 286: } else { 287: $form submit cancel.x -value "Cancel" -class DIOFormCancelButton 288: } 289: puts "</TD>" 290: puts "</TR>" 291: puts "</TABLE>" 292: 293: $form end 294: } 295: 296: # 297: # showform - emit a form for inserting a new record 298: # 299: # response(by) will contain whatever was in the "where" field 300: # response(query) will contain whatever was in the "is" field 301: # 302: method showform {} { 303: showform_prolog 304: 305: # emit each field 306: foreach field $fields { 307: showform_field $field 308: } 309: 310: showform_epilog 311: } 312: 313: # showform_field - emit the form field for the specified field using 314: # the showform method of the field. If the user has typed something 315: # into the search field and it matches the fields being emitted, 316: # use that value as the default 317: # 318: method showform_field {field} { 319: if {[info exists response(by)] && $response(by) == [$field text]} { 320: if {![$field readonly] && $response(query) != ""} { 321: $field value $response(query) 322: } 323: } 324: $field showform 325: } 326: 327: method page_buttons {end {count 0}} { 328: if {$pagesize <= 0} { return } 329: 330: if {![info exists response(page)]} { set response(page) 1 } 331: 332: set pref DIO$end 333: if {!$count} { 334: set count [$DIOResult numrows] 335: } 336: 337: set pages [expr ($count + $pagesize - 1) / $pagesize] 338: 339: if {$pages <= 1} { 340: return 341: } 342: 343: set first [expr $response(page) - 4] 344: if {$first > $pages - 9} { 345: set first [expr $pages - 9] 346: } 347: if {$first > 1} { 348: lappend pagelist 1 1 349: if {$first > 3} { 350: lappend pagelist ".." 0 351: } elseif {$first > 2} { 352: lappend pagelist 2 2 353: } 354: } else { 355: set first 1 356: } 357: set last [expr $response(page) + 4] 358: if {$last < 9} { 359: set last 9 360: } 361: if {$last > $pages} { 362: set last $pages 363: } 364: for {set i $first} {$i <= $last} {incr i} { 365: lappend pagelist $i $i 366: } 367: if {$last < $pages} { 368: if {$last < $pages - 2} { 369: lappend pagelist ".." 0 370: } elseif {$last < $pages - 1} { 371: incr last 372: lappend pagelist $last $last 373: } 374: lappend pagelist $pages $pages 375: } 376: 377: foreach {n p} $pagelist { 378: if {$p == 0 || $p == $response(page)} { 379: lappend navbar $n 380: } else { 381: set html {<A HREF="} 382: append html "$document?mode=$response(mode)" 383: foreach var {query by how sort num} { 384: if {[info exists response($var)]} { 385: append html "&$var=$response($var)" 386: } 387: } 388: foreach fld [array names hidden] { 389: append html "&$fld=$hidden($fld)" 390: } 391: append html "&page=$p\">$n</A>" 392: lappend navbar $html 393: } 394: } 395: 396: if {"$end" == "Bottom"} { 397: puts "<BR/>" 398: } 399: set class [get_css_class TABLE DIONavButtons ${pref}NavButtons] 400: puts "<TABLE WIDTH=\"100%\" CLASS=\"$class\">" 401: puts "<TR>" 402: puts "<TD>" 403: if {"$end" == "Top"} { 404: puts "$count rows, go to page" 405: } else { 406: puts "Go to page" 407: } 408: foreach link $navbar { 409: puts "$link " 410: } 411: puts "</TD>" 412: if {"$end" == "Top" && $pages>10} { 413: set f [::form #auto] 414: $f start 415: foreach fld [array names hidden] { 416: $f hidden $fld -value $hidden($fld) 417: } 418: foreach fld {mode query by how sort num} { 419: if [info exists response($fld)] { 420: $f hidden $fld -value $response($fld) 421: } 422: } 423: puts "<TD ALIGN=RIGHT>" 424: puts "Jump directly to" 425: $f text page -size 4 -value $response(page) 426: $f submit submit -value "Go" 427: puts "</TD>" 428: $f end 429: } 430: puts "</TR>" 431: puts "</TABLE>" 432: if {"$end" == "Top"} { 433: puts "<BR/>" 434: } 435: } 436: 437: 438: method rowheader {{total 0}} { 439: set fieldList $fields 440: if {![lempty $rowfields]} { set fieldList $rowfields } 441: 442: set rowcount 0 443: 444: puts <P> 445: 446: if {$topnav} { page_buttons Top $total } 447: 448: puts {<TABLE BORDER WIDTH="100%" CLASS="DIORowHeader">} 449: puts "<TR CLASS=DIORowHeader>" 450: foreach field $fieldList { 451: set text [$field text] 452: set sorting $allowsort 453: ## If sorting is turned off, or this field is not in the 454: ## sortfields, we don't display the sort option. 455: if {$sorting && ![lempty $sortfields]} { 456: if {[lsearch $sortfields $field] < 0} { 457: set sorting 0 458: } 459: } 460: if {$sorting && [info exists response(sort)]} { 461: if {"$response(sort)" == "$field"} { 462: set sorting 0 463: } 464: } 465: 466: if {!$sorting} { 467: set html $text 468: } else { 469: set html {<A HREF="} 470: append html "$document?mode=$response(mode)" 471: foreach var {query by how num} { 472: if {[info exists response($var)]} { 473: append html "&$var=$response($var)" 474: } 475: } 476: foreach fld [array names hidden] { 477: append html "&$fld=$hidden($fld)" 478: } 479: append html "&sort=$field\">$text</A>" 480: } 481: set class [get_css_class TH DIORowHeader DIORowHeader-$field] 482: puts "<TH CLASS=\"$class\">$html</TH>" 483: } 484: 485: if {![lempty $rowfunctions] && "$rowfunctions" != "-"} { 486: puts {<TH CLASS="DIORowHeaderFunctions">Functions</TH>} 487: } 488: puts "</TR>" 489: } 490: 491: method showrow {arrayName} { 492: upvar 1 $arrayName a 493: 494: incr rowcount 495: set alt "" 496: if {$alternaterows && ![expr $rowcount % 2]} { set alt Alt } 497: 498: set fieldList $fields 499: if {![lempty $rowfields]} { set fieldList $rowfields } 500: 501: puts "<TR>" 502: foreach field $fieldList { 503: set class [get_css_class TD DIORowField$alt DIORowField$alt-$field] 504: set text "" 505: if {[info exists a($field)]} { 506: set text $a($field) 507: if [info exists filters($field)] { 508: set text [$filters($field) $text] 509: } 510: } 511: if ![string length $text] { 512: set text " " 513: } 514: puts "<TD CLASS=\"$class\">$text</TD>" 515: } 516: 517: if {![lempty $rowfunctions] && "$rowfunctions" != "-"} { 518: set f [::form #auto] 519: puts "<TD NOWRAP CLASS=\"DIORowFunctions$alt\">" 520: $f start 521: foreach fld [array names hidden] { 522: $f hidden $fld -value $hidden($fld) 523: } 524: $f hidden query -value [$DIO makekey a] 525: if {[llength $rowfunctions] > 1} { 526: $f select mode -values $rowfunctions -class DIORowFunctionSelect$alt 527: $f submit submit -value "Go" -class DIORowFunctionButton$alt 528: } else { 529: set func [lindex $rowfunctions 0] 530: $f hidden mode -value $func 531: $f submit submit -value $func -class DIORowFunctionButton$alt 532: } 533: puts "</TD>" 534: $f end 535: } 536: 537: puts "</TR>" 538: } 539: 540: method rowfooter {{total 0}} { 541: puts "</TABLE>" 542: 543: if {$bottomnav} { page_buttons Bottom $total } 544: } 545: 546: ## Define a new function. 547: method function {name} { 548: lappend allfunctions $name 549: } 550: 551: ## Define a field in the object. 552: method field {name args} { 553: import_keyvalue_pairs data $args 554: lappend fields $name 555: lappend allfields $name 556: 557: set class DIODisplayField 558: if {[info exists data(type)]} { 559: if {![lempty [::itcl::find classes *DIODisplayField_$data(type)]]} { 560: set class DIODisplayField_$data(type) 561: } 562: 563: } 564: 565: eval $class $name -name $name -display $this -form $form $args 566: set FieldTextMap([$name text]) $name 567: } 568: 569: method fetch {key arrayName} { 570: upvar 1 $arrayName $arrayName 571: set result [$DIO fetch $key $arrayName] 572: set error [$DIO errorinfo] 573: if {![lempty $error]} { return -code error $error } 574: return $result 575: } 576: 577: method store {arrayName} { 578: upvar 1 $arrayName array 579: set result [$DIO store array] 580: set error [$DIO errorinfo] 581: if {![lempty $error]} { return -code error $error } 582: return $result 583: } 584: 585: method delete {key} { 586: set result [$DIO delete $key] 587: set error [$DIO errorinfo] 588: if {![lempty $error]} { return -code error $error } 589: return $result 590: } 591: 592: method pretty_fields {list} { 593: foreach field $list { 594: lappend fieldList [$field text] 595: } 596: return $fieldList 597: } 598: 599: method set_field_values {arrayName} { 600: upvar 1 $arrayName array 601: 602: # for all the elements in the specified array, try to invoke 603: # the element as an object, invoking the method "value" to 604: # set the value to the specified value 605: foreach var [array names array] { 606: #if {[catch { $var value $array($var) } result] == 1} {} 607: if {[catch { $var configure -value $array($var) } result] == 1} { 608: } 609: } 610: } 611: 612: method get_field_values {arrayName} { 613: upvar 1 $arrayName array 614: 615: foreach field $allfields { 616: 617: # for some reason the method for getting the value doesn't 618: # work for boolean values, which inherit DIODisplayField, 619: # something to do with configvar 620: #set array($field) [$field value] 621: set array($field) [$field cget -value] 622: } 623: } 624: 625: method DisplayRequest {query} { 626: set DIOResult [eval $DIO search -select "count(*)" $query] 627: if [$DIOResult numrows] { 628: $DIOResult next -array a 629: set total $a(count) 630: } else { 631: set total 0 632: } 633: $DIOResult destroy 634: set DIOResult "" 635: 636: append query [sql_order_by_syntax] 637: append query [sql_limit_syntax] 638: set DIOResult [eval $DIO search $query] 639: 640: if {[$DIOResult numrows] <= 0} { 641: puts "Could not find any matching records." 642: $DIOResult destroy 643: set DIOResult "" 644: return 645: } 646: 647: rowheader $total 648: 649: $DIOResult forall -array a { 650: showrow a 651: } 652: 653: rowfooter $total 654: 655: $DIOResult destroy 656: set DIOResult "" 657: } 658: 659: method Main {} { 660: puts "<TABLE BORDER=0 WIDTH=100% CLASS=DIOForm><TR>" 661: 662: set selfunctions {} 663: foreach f $functions { 664: if {"$f" != "List"} { 665: lappend selfunctions $f 666: } else { 667: set f [::form #auto] 668: $f start 669: foreach fld [array names hidden] { 670: $f hidden $fld -value $hidden($fld) 671: } 672: $f hidden mode -value "List" 673: $f hidden query -value "" 674: puts "<TD CLASS=DIOForm ALIGN=CENTER VALIGN=MIDDLE WIDTH=0%>" 675: $f submit submit -value "Show All" -class DIORowFunctionButton 676: puts "</TD>" 677: $f end 678: } 679: } 680: 681: puts "<TD CLASS=DIOForm VALIGN=MIDDLE WIDTH=100%>" 682: $form start 683: puts " " 684: 685: foreach fld [array names hidden] { 686: $form hidden $fld -value $hidden($fld) 687: } 688: 689: if {[llength $selfunctions] > 1} { 690: $form select mode -values $selfunctions -class DIOMainFunctionsSelect 691: puts "where" 692: } else { 693: puts "Where" 694: } 695: 696: set useFields $fields 697: if {![lempty $searchfields]} { set useFields $searchfields } 698: 699: $form select by -values [pretty_fields $useFields] \ 700: -class DIOMainSearchBy 701: 702: if [string match {[Ss]earch} $selfunctions] { 703: $form select how -values {"=" "<" "<=" ">" ">="} 704: } else { 705: puts "is" 706: } 707: 708: if [info exists response(query)] { 709: $form text query -value $response(query) -class DIOMainQuery 710: } else { 711: $form text query -value "" -class DIOMainQuery 712: } 713: 714: if {[llength $selfunctions] > 1} { 715: $form submit submit -value "GO" -class DIOMainSubmitButton 716: } else { 717: $form hidden mode -value $selfunctions 718: $form submit submit -value $selfunctions -class DIOMainSubmitButton 719: } 720: puts "</TD></TR>" 721: 722: if {![lempty $numresults]} { 723: puts "<TR><TD CLASS=DIOForm>Results per page: " 724: $form select num -values $numresults -class DIOMainNumResults 725: puts "</TD></TR>" 726: } 727: 728: $form end 729: puts "</TABLE>" 730: } 731: 732: method sql_order_by_syntax {} { 733: if {[info exists response(sort)] && ![lempty $response(sort)]} { 734: return " ORDER BY $response(sort)" 735: } 736: 737: if {![lempty $defaultsortfield]} { 738: return " ORDER BY $defaultsortfield" 739: } 740: } 741: 742: method sql_limit_syntax {} { 743: if {$pagesize <= 0} { return } 744: 745: set offset "" 746: if {[info exists response(page)]} { 747: set offset [expr ($response(page) - 1) * $pagesize] 748: } 749: return [$DIO sql_limit_syntax $pagesize $offset] 750: } 751: 752: 753: method Search {} { 754: set searchField $FieldTextMap($response(by)) 755: 756: set what $response(query) 757: if {[info exists response(how)] && [string length $response(how)]} { 758: set what "$response(how)$what" 759: } 760: 761: DisplayRequest "-$searchField $what" 762: } 763: 764: method List {} { 765: DisplayRequest "" 766: } 767: 768: method Add {} { 769: showform 770: } 771: 772: method Edit {} { 773: if {![fetch $response(query) array]} { 774: puts "That record does not exist in the database." 775: return 776: } 777: 778: set_field_values array 779: 780: showform 781: } 782: 783: ## 784: ## When we save, we want to set all the fields' values and then get 785: ## them into a new array. We do this because we want to clean any 786: ## unwanted variables out of the array but also because some fields 787: ## have special handling for their values, and we want to make sure 788: ## we get the right value. 789: ## 790: method Save {} { 791: if {[info exists response(cancel.x)]} { 792: Cancel 793: return 794: } 795: 796: ## We need to see if the key exists. If they are adding a new 797: ## entry, we just want to see if the key exists. If they are 798: ## editing an entry, we need to see if they changed the keyfield 799: ## while editing. If they didn't change the keyfield, there's no 800: ## reason to check it. 801: if {$response(DIODfromMode) == "Add"} { 802: set key [$DIO makekey response] 803: fetch $key a 804: } else { 805: set key $response(DIODkey) 806: set newkey [$DIO makekey response] 807: 808: ## If we have a new key, and the newkey doesn't exist in the 809: ## database, we are moving this record to a new key, so we 810: ## need to delete the old key. 811: if {$key != $newkey} { 812: if {![fetch $newkey a]} { 813: delete $key 814: } 815: } 816: } 817: 818: if {[array exists a]} { 819: puts "That record already exists in the database." 820: return 821: } 822: 823: set_field_values response 824: get_field_values storeArray 825: store storeArray 826: headers redirect $document 827: } 828: 829: method Delete {} { 830: if {![fetch $response(query) array]} { 831: puts "That record does not exist in the database." 832: return 833: } 834: 835: if {!$confirmdelete} { 836: DoDelete 837: return 838: } 839: 840: puts "<CENTER>" 841: puts {<TABLE CLASS="DIODeleteConfirm">} 842: puts "<TR>" 843: puts {<TD COLSPAN=2 CLASS="DIODeleteConfirm">} 844: puts "Are you sure you want to delete this record from the database?" 845: puts "</TD>" 846: puts "</TR>" 847: puts "<TR>" 848: puts {<TD ALIGN="center" CLASS="DIODeleteConfirmYesButton">} 849: set f [::form #auto] 850: $f start 851: foreach fld [array names hidden] { 852: $f hidden $fld -value $hidden($fld) 853: } 854: $f hidden mode -value DoDelete 855: $f hidden query -value $response(query) 856: $f submit submit -value Yes -class DIODeleteConfirmYesButton 857: $f end 858: puts "</TD>" 859: puts {<TD ALIGN="center" CLASS="DIODeleteConfirmNoButton">} 860: set f [::form #auto] 861: $f start 862: foreach fld [array names hidden] { 863: $f hidden $fld -value $hidden($fld) 864: } 865: $f submit submit -value No -class "DIODeleteConfirmNoButton" 866: $f end 867: puts "</TD>" 868: puts "</TR>" 869: puts "</TABLE>" 870: puts "</CENTER>" 871: } 872: 873: method DoDelete {} { 874: delete $response(query) 875: 876: headers redirect $document 877: } 878: 879: method Details {} { 880: if {![fetch $response(query) array]} { 881: puts "That record does not exist in the database." 882: return 883: } 884: 885: set_field_values array 886: 887: showview 888: } 889: 890: method Cancel {} { 891: headers redirect $document 892: } 893: 894: ### 895: ## Define variable functions for each variable. 896: ### 897: 898: method fields {{list ""}} { 899: if {[lempty $list]} { return $fields } 900: foreach field $list { 901: if {[lsearch $allfields $field] < 0} { 902: return -code error "Field $field does not exist." 903: } 904: } 905: set fields $list 906: } 907: 908: method searchfields {{list ""}} { 909: if {[lempty $list]} { return $searchfields } 910: foreach field $list { 911: if {[lsearch $allfields $field] < 0} { 912: return -code error "Field $field does not exist." 913: } 914: } 915: set searchfields $list 916: } 917: 918: method rowfields {{list ""}} { 919: if {[lempty $list]} { return $rowfields } 920: foreach field $list { 921: if {[lsearch $allfields $field] < 0} { 922: return -code error "Field $field does not exist." 923: } 924: } 925: set rowfields $list 926: } 927: 928: method filter {field {value ""}} { 929: if [string length $value] { 930: set filters($field) [uplevel 1 [list namespace which $value]] 931: } else { 932: if [info exists filters($field)] { 933: return $filters($field) 934: } else { 935: return "" 936: } 937: } 938: } 939: 940: method hidden {name {value ""}} { 941: if [string length $value] { 942: set hidden($name) $value 943: } else { 944: if [info exists hidden($name)] { 945: return $hidden($name) 946: } else { 947: return "" 948: } 949: } 950: } 951: 952: method DIO {{string ""}} { configvar DIO $string } 953: method DIOResult {{string ""}} { configvar DIOResult $string } 954: 955: method title {{string ""}} { configvar title $string } 956: method functions {{string ""}} { configvar functions $string } 957: method pagesize {{string ""}} { configvar pagesize $string } 958: method form {{string ""}} { configvar form $string } 959: method cleanup {{string ""}} { configvar cleanup $string } 960: method confirmdelete {{string ""}} { configvar confirmdelete $string } 961: 962: method css {{string ""}} { configvar css $string } 963: method persistentmain {{string ""}} { configvar persistentmain $string } 964: method alternaterows {{string ""}} { configvar alternaterows $string } 965: method allowsort {{string ""}} { configvar allowsort $string } 966: method sortfields {{string ""}} { configvar sortfields $string } 967: method topnav {{string ""}} { configvar topnav $string } 968: method bottomnav {{string ""}} { configvar bottomnav $string } 969: method numresults {{string ""}} { configvar numresults $string } 970: method defaultsortfield {{string ""}} { configvar defaultsortfield $string } 971: 972: method rowfunctions {{string ""}} { configvar rowfunctions $string } 973: 974: ## OPTIONS ## 975: 976: public variable DIO "" 977: public variable DIOResult "" 978: 979: public variable title "" 980: public variable fields "" 981: public variable searchfields "" 982: public variable functions "Search List Add Edit Delete Details" 983: public variable pagesize 25 984: public variable form "" 985: public variable cleanup 1 986: public variable confirmdelete 1 987: 988: public variable css "diodisplay.css" { 989: if {![lempty $css]} { 990: catch {unset cssArray} 991: read_css_file 992: } 993: } 994: 995: public variable persistentmain 1 996: public variable alternaterows 1 997: public variable allowsort 1 998: public variable sortfields "" 999: public variable topnav 1 1000: public variable bottomnav 1 1001: public variable numresults "" 1002: public variable defaultsortfield "" 1003: 1004: public variable rowfields "" 1005: public variable rowfunctions "Details Edit Delete" 1006: 1007: public variable response 1008: public variable cssArray 1009: public variable document "" 1010: public variable allfields "" 1011: public variable FieldTextMap 1012: public variable allfunctions { 1013: Search 1014: List 1015: Add 1016: Edit 1017: Delete 1018: Details 1019: Main 1020: Save 1021: DoDelete 1022: Cancel 1023: } 1024: 1025: private variable rowcount 1026: private variable filters 1027: private variable hidden 1028: 1029: } ; ## ::itcl::class DIODisplay 1030: 1031: catch { ::itcl::delete class ::DIODisplayField } 1032: 1033: # 1034: # DIODisplayField object -- defined for each field we're displaying 1035: # 1036: ::itcl::class ::DIODisplayField { 1037: 1038: constructor {args} { 1039: ## We want to simulate Itcl's configure command, but we want to 1040: ## check for arguments that are not variables of our object. If 1041: ## they're not, we save them as arguments to the form when this 1042: ## field is displayed. 1043: import_keyvalue_pairs data $args 1044: foreach var [array names data] { 1045: if {![info exists $var]} { 1046: lappend formargs -$var $data($var) 1047: } else { 1048: set $var $data($var) 1049: } 1050: } 1051: 1052: # if text (field description) isn't set, prettify the actual 1053: # field name and use that 1054: if {[lempty $text]} { set text [pretty [split $name _]] } 1055: } 1056: 1057: destructor { 1058: 1059: } 1060: 1061: method destroy {} { 1062: ::itcl::delete object $this 1063: } 1064: 1065: # 1066: # get_css_class - ask the parent DIODIsplay object to look up 1067: # a CSS class entry 1068: # 1069: method get_css_class {tag default class} { 1070: return [$display get_css_class $tag $default $class] 1071: } 1072: 1073: # 1074: # get_css_tag -- set tag to select or textarea if type is select 1075: # or textarea, else to input 1076: # 1077: method get_css_tag {} { 1078: switch -- $type { 1079: "select" { 1080: set tag select 1081: } 1082: "textarea" { 1083: set tag textarea 1084: } 1085: default { 1086: set tag input 1087: } 1088: } 1089: } 1090: 1091: # 1092: # pretty -- prettify a list of words by uppercasing the first letter 1093: # of each word 1094: # 1095: method pretty {string} { 1096: set words "" 1097: foreach w $string { 1098: lappend words \ 1099: [string toupper [string index $w 0]][string range $w 1 end] 1100: } 1101: return [join $words " "] 1102: } 1103: 1104: method configvar {varName string} { 1105: if {[lempty $string]} { return [set $varName] } 1106: configure -$varName $string 1107: } 1108: 1109: # 1110: # showview - emit a table row of either DIOViewRow, DIOViewRowAlt, 1111: # DIOViewRow-fieldname (this object's field name), or 1112: # DIOViewRowAlt-fieldname, a table data field of either 1113: # DIOViewHeader or DIOViewHeader-fieldname, and then a 1114: # value of class DIOViewField or DIOViewField-fieldname 1115: # 1116: method showview {{alt ""}} { 1117: set class [get_css_class TR DIOViewRow$alt DIOViewViewRow$alt-$name] 1118: puts "<TR CLASS=\"$class\">" 1119: 1120: set class [get_css_class TD DIOViewHeader DIOViewHeader-$name] 1121: puts "<TD CLASS=\"$class\">$text:</TD>" 1122: 1123: set class [get_css_class TD DIOViewField DIOViewField-$name] 1124: puts "<TD CLASS=\"$class\">$value</TD>" 1125: 1126: puts "</TR>" 1127: } 1128: 1129: # 1130: # showform -- like showview, creates a table row and table data, but 1131: # if readonly isn't set, emits a form field corresponding to the type 1132: # of this field 1133: # 1134: method showform {} { 1135: puts "<TR>" 1136: 1137: set class [get_css_class TD DIOFormHeader DIOFormHeader-$name] 1138: puts "<TD CLASS=\"$class\">$text:</TD>" 1139: 1140: set class [get_css_class TD DIOFormField DIOFormField-$name] 1141: puts "<TD CLASS=\"$class\">" 1142: if {$readonly} { 1143: puts "$value" 1144: } else { 1145: set tag [get_css_tag] 1146: set class [get_css_class $tag DIOFormField DIOFormField-$name] 1147: 1148: if {$type == "select"} { 1149: $form select $name -values $values -class $class 1150: } else { 1151: eval $form $type $name -value [list $value] $formargs -class $class 1152: } 1153: } 1154: puts "</TD>" 1155: puts "</TR>" 1156: } 1157: 1158: # methods that give us method-based access to get and set the 1159: # object's variables... 1160: method display {{string ""}} { configvar display $string } 1161: method form {{string ""}} { configvar form $string } 1162: method formargs {{string ""}} { configvar formargs $string } 1163: method name {{string ""}} { configvar name $string } 1164: method text {{string ""}} { configvar text $string } 1165: method type {{string ""}} { configvar type $string } 1166: method value {{string ""}} { configvar value $string } 1167: method readonly {{string ""}} { configvar readonly $string } 1168: 1169: public variable display "" 1170: public variable form "" 1171: public variable formargs "" 1172: 1173: # values - for fields of type "select" only, the values that go in 1174: # the popdown (or whatever) selector 1175: public variable values "" 1176: 1177: # name - the field name 1178: public variable name "" 1179: 1180: # text - the description text for the field. if not specified, 1181: # it's constructed from a prettified version of the field name 1182: public variable text "" 1183: 1184: # value - the default value of the field 1185: public variable value "" 1186: 1187: # type - the data type of the field 1188: public variable type "text" 1189: 1190: # readonly - if 1, we don't allow the value to be changed 1191: public variable readonly 0 1192: 1193: } ; ## ::itcl::class DIODisplayField 1194: 1195: catch { ::itcl::delete class ::DIODisplayField_boolean } 1196: 1197: # 1198: # DIODisplayField_boolen -- superclass of DIODisplayField that overrides 1199: # a few methods to specially handle booleans 1200: # 1201: ::itcl::class ::DIODisplayField_boolean { 1202: inherit ::DIODisplayField 1203: 1204: constructor {args} {eval configure $args} { 1205: eval configure $args 1206: } 1207: 1208: method add_true_value {string} { 1209: lappend trueValues $string 1210: } 1211: 1212: # 1213: # showform -- emit a form field for a boolean 1214: # 1215: method showform {} { 1216: puts "<TR>" 1217: 1218: set class [get_css_class TD DIOFormHeader DIOFormHeader-$name] 1219: puts "<TD CLASS=\"$class\">$text:</TD>" 1220: 1221: set class [get_css_class TD DIOFormField DIOFormField-$name] 1222: puts "<TD CLASS=\"$class\">" 1223: if {$readonly} { 1224: if {[boolean_value]} { 1225: puts $true 1226: } else { 1227: puts $false 1228: } 1229: } else { 1230: if {[boolean_value]} { 1231: $form default_value $name $true 1232: } else { 1233: $form default_value $name $false 1234: } 1235: eval $form radiobuttons $name \ 1236: -values [list "$true $false"] $formargs 1237: } 1238: puts "</TD>" 1239: puts "</TR>" 1240: } 1241: 1242: # 1243: # showview -- emit a view for a boolean 1244: # 1245: method showview {{alt ""}} { 1246: set class [get_css_class TR DIOViewRow$alt DIOViewRow$alt-$name] 1247: puts "<TR CLASS=\"$class\">" 1248: 1249: set class [get_css_class TD DIOViewHeader DIOViewHeader-$name] 1250: puts "<TD CLASS=\"$class\">$text:</TD>" 1251: 1252: set class [get_css_class TD DIOViewField DIOViewField-$name] 1253: puts "<TD CLASS=\"$class\">" 1254: if {[boolean_value]} { 1255: puts $true 1256: } else { 1257: puts $false 1258: } 1259: puts "</TD>" 1260: 1261: puts "</TR>" 1262: } 1263: 1264: # 1265: # boolean_value -- return 1 if value is found in the values list, else 0 1266: # 1267: method boolean_value {} { 1268: set val [string tolower $value] 1269: if {[lsearch -exact $values $val] > -1} { return 1 } 1270: return 0 1271: } 1272: 1273: method value {{string ""}} { configvar value $string } 1274: 1275: public variable true "Yes" 1276: public variable false "No" 1277: public variable values "1 y yes t true on" 1278: 1279: public variable value "" { 1280: if {[boolean_value]} { 1281: set value $true 1282: } else { 1283: set value $false 1284: } 1285: } 1286: 1287: } ; ## ::itcl::class ::DIODisplayField_boolean 1288: 1289: |