Ideally the Outline as a hierarchy of database queries functionality would be integrated with software such as tkoutline. For an initial prototype, I wrote a script that can be run as a separate process that will convert a tkoutline data file containing rules and properties into another tkoutline file with all the rules and queries applied.
Eventually, I hope to write code that will run from within tkoutline and automatically refresh the outline based on changes to rules and facts.
In order to use the following script the SWI prolog interpreter [1] needs to be installed and the script should be modified to point to the location of your interpreter. Another requirement is that you make sense of my gibberish instructions. Good luck.
To test it out, create an outline with tkoutline that looks like the following:
[-] Node with derived children . # Nodes beginning with "#" are ignored . # If a node starts with ":", then all the following text should be valid prolog facts or clauses [-] # The prolog fact or clause is first run through Tcl variable and function substitution . # The tcl variables "tree" and "node" are made available for substitution . # The variable "parent" is also made available as a convenient shortcut to [$tree parent $node] . # See tcllib tree manpages for more details . # The following prolog says to make any node with the project=tkoutline be a child of the above parent . :child($parent,Y):-project(Y,tkoutline). [-] Node with explicit children [-] child1 [-] child1.1 . :project($parent,tkoutline). [-] child2 . :project($parent, 'Just for fun').
When run through the script later in this page, the above outline will be transformed into the following intermediate prolog facts/clauses:
child(root,node1). description(node1,'Node with derived children'). child(node1,Y):-project(Y,tkoutline). child(root,node11). description(node11,'Node with explicit children'). child(node11,node12). description(node12,'child1'). child(node12,node14). description(node14,'child1\.1'). project(node14,tkoutline). child(node11,node13). description(node13,'child2'). project(node13, 'Just for fun').
The script will continue and generate a tkoutline file for the following outline:
[-] Node with derived children . child1.1 [-] Node with explicit children [-] child1 . child1.1 . child2
Here is the script
package require tcllib
package require struct
# Returns a script that will regenerate the given node and its descendents
# Swiped from texttree.tcl
proc nodeToScript {tree node} {
set script "\$t insert [$tree parent $node] [expr [$tree index $node] + 1] $node\n"
append script "\$t set $node [list [$tree set $node]]\n"
append script "\$t set $node -key expand 1\n"
foreach child [$tree children $node] {
append script [nodeToScript $tree $child]
}
return $script
}
# Returns a script that will regenerate the given tree
# Swiped from texttree.tcl
proc treeToScript {tree} {
set script "set t \[::struct::tree]\n"
append script "\$t set root -key expand 1\n"
foreach child [$tree children root] {
append script [nodeToScript $tree $child]
}
# Last line of the script returns the name of the tree
append script "return \$t\n";
return $script
}
# Converts the given tree to prolog facts and clauses
#
# Foreach node "c" a fact is asserted relating that node to its
# parent node "p" -- child(p,c).
#
# The data for each node is related to its node id, "n" by the fact
# description(n,data).
#
# If the first character of a node's data is "#", then the node is ignored
#
# If the first character of a node's data is ":", then Tcl substitution
# is performed on the node's data and the result is assert in the
# Prolog database.
proc treeToProlog {tree} {
set output {}
$tree walk root -command {
set tree %t
set node %n
if {$node != "root"} {
set data [$tree set $node]
set parent [$tree parent $node]
switch -- [string index $data 0] {
":" {
catch {subst -nobackslash [string range $data 1 end]} result
append output "$result\n"
}
"#" {}
default {
append output "child($parent,$node).\n"
append output "description($node,'[string map {' \\' . \\.} $data]').\n"
}
}
}
}
return $output
}
# Converts the given graph into a tree
proc graphToTree {graph graphNode tree treeNode} {
foreach child [$graph nodes -out $graphNode] {
set n [$tree insert $treeNode [$tree numchildren $treeNode]]
$tree set $n [$graph node set $child]
graphToTree $graph $child $tree $n
}
return
}
# Prolog code snippet that will output Tcl code that will create
# a graph from a prolog database.
set prologToTclGraph {
nodeData(Node,Data):-
description(Node,Data).
nodeData(Node,Node).
% Display Tcl graph code for a single node
writeNode(Node):-
writef('$g node insert {%w}\n', [Node]),
nodeData(Node,Data),
writef('$g node set {%w} {%w}\n',[Node,Data]).
% Display Tcl code for a list of nodes
writeNodes([]).
writeNodes([H|T]):-
writeNode(H),
writeNodes(T).
% Display Tcl code to create arcs connecting nodes
writeArcs(_,[]).
writeArcs(Parent,[H|T]):-
writef('$g arc insert {%w} {%w}\n', [Parent,H]),
clause(childGoal(H,X),Body),
findall(X,Body,Children),
writeArcs(H,Children),
writeArcs(Parent,T).
node(X):-child(_,X).
% Defines the child predicate as the default parent/child relationship
% Each node can define it's own predicate to override this
childGoal(X,Y):-child(X,Y).
% The main entry point
main:-
write_ln('set g [::struct::graph]'),
writeNode(root),
setof(X, node(X), Nodes),
writeNodes(Nodes),
clause(childGoal(root,X),Body),
findall(X,Body,Children),
writeArcs(root,Children),
write_ln('set g').
}
#
# Main code
#
# Input argument should be the filename of a tkoutline file
set tree [source [lindex $argv 0]]
# The location of the prolog interpreter
set prologPath d:/apps/prolog/bin
set prologExe $prologPath/plcon
# Convert the tree to prolog facts and clauses and append the
# above prolog code
set prologScript "[treeToProlog $tree]\n$prologToTclGraph"
# Write the prolog code to a temporary file
set f [open "temp.pro" w]
puts $f $prologScript
close $f
# Invoke the prolog interpreter and evaluate the result
set graphScript [exec $prologExe -s temp.pro -t main 2>@ stderr]
set graph [eval $graphScript]
# Convert the graph to a tree and write it to stdout
set tree [struct::tree]
graphToTree $graph root $tree root
puts [treeToScript $tree]
# It is up to the user to redirect the result into a file and
# load it into tkoutline. | Updated 8 Jan 2002, 03:23 GMT Search - Recent Changes - Reference - About WiKit - Go to Tkoutline - Help |