5748831 [rkeene@sledge /home/rkeene/projects/rivet-cgi/packages/dio]$ cat -n diodisplay.tcl
   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&nbsp;"
 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 "&nbsp;"
 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 "&nbsp;"
 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: 
5748832 [rkeene@sledge /home/rkeene/projects/rivet-cgi/packages/dio]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2005-01-12 17:41:22