6a3d1cca54abfac5bab97af3a4eb6e6ca462fb0f
[banana.git] / banana / tree.inc.php
1 <?php
2 /********************************************************************************
3 * include/tree.inc.php : thread tree
4 * -----------------------
5 *
6 * This file is part of the banana distribution
7 * Copyright: See COPYING files that comes with this distribution
8 ********************************************************************************/
9
10
11 define('BANANA_TREE_VERSION', '0.1.2');
12
13 /**
14 * Class representing a thread tree
15 */
16 class BananaTree
17 {
18 /** Tree cache
19 */
20 static private $cache = array();
21
22 /** Tree format
23 */
24 public $version;
25
26 /** Last update timestamp
27 */
28 public $time = 0;
29
30 /** Data
31 */
32 public $data = array();
33
34 /** Data caching
35 */
36 private $urls = array();
37 private $title = array();
38
39 private $displaid = null;
40
41 /** Construct a new tree from a given root
42 */
43 public function __construct(BananaSpoolHead &$root)
44 {
45 if (empty($root->children)) {
46 $this->data = null;
47 } else {
48 $this->data =& $this->builder($root);
49 }
50 $this->time = time();
51 $this->version = BANANA_TREE_VERSION;
52 $this->saveToFile($root->id);
53 }
54
55 private function &builder(BananaSpoolHead &$head)
56 {
57 $array = array(array($head->id));
58 $this->urls[$head->id] = banana_entities(Banana::$page->makeURL(array('group' => Banana::$group,
59 'artid' => $head->id)));
60 $this->title[$head->id] = banana_entities($head->name . ', ' . Banana::$spool->formatDate($head));
61 foreach ($head->children as $key=>&$msg) {
62 $tree =& $this->builder($msg);
63 $last = $key == count($head->children) - 1;
64 foreach ($tree as $kt=>&$line) {
65 if ($kt === 0 && $key === 0 && !$last) {
66 $array[0] = array_merge($array[0], array(array('+', $msg->id)), $line);
67 } else if($kt === 0 && $key === 0) {
68 $array[0] = array_merge($array[0], array(array('-', $msg->id)), $line);
69 } else if ($kt === 0 && $last) {
70 $array[] = array_merge(array(' ', array('`', $msg->id)), $line);
71 } else if ($kt === 0) {
72 $array[] = array_merge(array(' ', array('t', $msg->id)), $line);
73 } else if ($last) {
74 $array[] = array_merge(array(' ', ' '), $line);
75 } else {
76 $array[] = array_merge(array(' ', array('|', $head->children[$key+1]->id)), $line);
77 }
78 }
79 unset($tree);
80 }
81 return $array;
82 }
83
84 /** Save the content of the tree into a file
85 */
86 private function saveToFile($id)
87 {
88 file_put_contents(BananaTree::filename($id), serialize($this));
89 }
90
91 /** Create a reference to a tree image.
92 */
93 static private function makeTreeImg($img, $alt)
94 {
95 return Banana::$page->makeImg(Array('img' => $img, 'alt' => $alt, 'height' => 18, 'width' => 14));
96 }
97
98 /** Add an entry to the static tree association table.
99 */
100 static private function addTreeKind(array& $tree, $ascii, $img)
101 {
102 $tree[$ascii] = array(self::makeTreeImg($img . Banana::$tree_unread, $ascii),
103 self::makeTreeImg($img . Banana::$tree_read, $ascii));
104 }
105
106 /** Return html to display the tree
107 */
108 public function &show()
109 {
110 if (!is_null($this->displaid) || is_null($this->data)) {
111 return $this->displaid;
112 }
113 static $t_e, $tree;
114 //$u_h, $u_ht, $u_vt, $u_l, $u_f, $r_h, $r_ht, $r_vt, $r_l, $r_f;
115 if (!isset($t_e)) {
116 $t_e = self::makeTreeImg('e', ' ');
117 $tree = array();
118 self::addTreeKind($tree, '+', 'p2');
119 self::addTreeKind($tree, '-', 'm2');
120 self::addTreeKind($tree, '|', 'l2');
121 self::addTreeKind($tree, '`', 'a2');
122 self::addTreeKind($tree, 't', 't2');
123 }
124 $text = '<div class="tree">';
125 foreach ($this->data as &$line) {
126 $text .= '<div style="height: 18px">';
127 foreach ($line as &$item) {
128 if ($item == ' ') {
129 $text .= $t_e;
130 } else if (is_array($item)) {
131 $head =& Banana::$spool->overview[$item[1]];
132 $text .= $tree[$item[0]][$head->isread ? 1 : 0];
133 } else {
134 $head =& Banana::$spool->overview[$item];
135 $text .= '<span style="background-color: ' . $head->color . '; text-decoration: none" title="'
136 . $this->title[$item] . '"><input type="radio" name="banana_tree" value="' . $head->id . '"';
137 if (Banana::$msgshow_javascript) {
138 $text .= ' onchange="window.location=\'' . $this->urls[$item] . '\'"';
139 } else {
140 $text .= ' disabled="disabled"';
141 }
142 if (Banana::$artid == $item) {
143 $text .= ' checked="checked"';
144 }
145 $text .= '/></span>';
146 }
147 }
148 $text .= "</div>\n";
149 }
150 $text .= '</div>';
151 $this->displaid =& $text;
152 return $text;
153 }
154
155 /** Get filename
156 */
157 static private function filename($id)
158 {
159 static $host;
160 if (!isset($host)) {
161 $host = parse_url(Banana::$page->makeURL(array()), PHP_URL_HOST);
162 }
163 return BananaSpool::getPath('tree_' . $id . '_' . $host);
164 }
165
166 /** Read a tree from a file
167 */
168 static private function &readFromFile($id)
169 {
170 $tree = null;
171 $file = BananaTree::filename($id);
172 if (!file_exists($file)) {
173 return $tree;
174 }
175 $tree = unserialize(file_get_contents($file));
176 if ($tree->version != BANANA_TREE_VERSION) {
177 $tree = null;
178 }
179 return $tree;
180 }
181
182 /** Build a tree for the given id
183 */
184 static public function &build($id)
185 {
186 $root =& Banana::$spool->root($id);
187 if (!isset(BananaTree::$cache[$root->id])) {
188 $tree =& BananaTree::readFromFile($root->id);
189 if (is_null($tree) || $tree->time < $root->time) {
190 $tree = new BananaTree($root);
191 }
192 BananaTree::$cache[$root->id] =& $tree;
193 }
194 return BananaTree::$cache[$root->id];
195 }
196
197 /** Kill the file associated to the given id
198 */
199 static public function kill($id)
200 {
201 @unlink(BananaTree::filename($id));
202 }
203 }
204 // vim:set et sw=4 sts=4 ts=4 enc=utf-8:
205 ?>