Thumbnail file hits. Based on a patch from D Bera
[beagle.git] / bludgeon / FileModel.cs
blob523bb8b2b837dc803191cf6ebc4305c91186deeb
2 using System;
3 using System.Collections;
4 using System.IO;
6 using Beagle.Util;
7 using Beagle;
9 namespace Bludgeon {
11 public class FileModel {
13 // Properties of the root directory:
14 // name contains full path of BEAGLE_HOME
15 // parent is null
16 // body is null
17 // children is non-null
19 // Properties of a non-root directory:
20 // name is a token
21 // parent is non-null
22 // body is null
23 // children is non-null
25 // Properties of a file:
26 // name is a token
27 // parent is non-null, and is a directory
28 // body is non-null
29 // children is null
31 private string name = null;
32 private FileModel parent = null;
33 private string [] body = null;
34 private Hashtable children = null;
36 //////////////////////////////////////////////////////////////
38 public bool IsRoot {
39 get { return parent == null; }
42 public bool IsDirectory {
43 get { return body == null; }
46 public bool IsFile {
47 get { return body != null; }
50 public string Name {
51 get { return name; }
54 public string FullName {
55 get { return IsRoot ? Name : Path.Combine (parent.FullName, name); }
58 public Uri Uri {
59 get { return UriFu.PathToFileUri (FullName); }
62 public string [] Body {
63 get { return body; }
66 public ICollection Children {
67 get { return children.Values; }
70 public int Size {
71 get {
72 if (IsFile)
73 return 1;
74 int sum = 0;
75 if (IsDirectory)
76 sum = 1; // count ourselves
77 foreach (FileModel child in children.Values)
78 sum += child.Size;
79 return sum;
83 //////////////////////////////////////////////////////////////
85 private void RecursiveListAdd (ArrayList list, bool add_dirs, bool add_files)
87 if ((add_dirs && IsDirectory) || (add_files && IsFile))
88 list.Add (this);
89 if (children != null)
90 foreach (FileModel file in children.Values)
91 file.RecursiveListAdd (list, add_files, add_files);
94 public ArrayList GetDescendants ()
96 ArrayList list = new ArrayList ();
97 RecursiveListAdd (list, true, true);
98 list.RemoveAt (0); // remove ourselves
99 return list;
102 public ArrayList GetFileDescendants ()
104 ArrayList list = new ArrayList ();
105 RecursiveListAdd (list, false, true);
106 list.RemoveAt (0); // remove ourselves
107 return list;
110 public ArrayList GetDirectoryDescendants ()
112 ArrayList list = new ArrayList ();
113 RecursiveListAdd (list, true, false);
114 list.RemoveAt (0); // remove ourselves
115 return list;
118 //////////////////////////////////////////////////////////////
120 static Random random = new Random ();
122 public FileModel PickDescendant ()
124 ArrayList all;
125 all = GetDescendants ();
126 if (all.Count == 0)
127 return null;
128 return all [random.Next (all.Count)] as FileModel;
131 public FileModel PickFileDescendant ()
133 ArrayList all;
134 all = GetFileDescendants ();
135 if (all.Count == 0)
136 return null;
137 return all [random.Next (all.Count)] as FileModel;
140 public FileModel PickDirectoryDescendant ()
142 ArrayList all;
143 all = GetDirectoryDescendants ();
144 if (all.Count == 0)
145 return null;
146 return all [random.Next (all.Count)] as FileModel;
149 //////////////////////////////////////////////////////////////
151 public bool BodyContains (string token)
153 if (body == null)
154 return false;
156 // FIXME: Do a binary search (or something smarter)
157 // instead
158 for (int i = 0; i < body.Length; ++i)
159 if (body [i] == token)
160 return true;
161 return false;
164 public bool Contains (string token)
166 return name == token || BodyContains (token);
169 //////////////////////////////////////////////////////////////
171 private FileModel () { }
173 public static FileModel NewRoot ()
175 FileModel root = new FileModel ();
176 root.name = PathFinder.HomeDir;
177 root.children = new Hashtable ();
178 return root;
181 // Creates a randomly-named new directory.
182 // Avoid name collisions with existing files.
183 public FileModel NewDirectory ()
185 if (! IsDirectory)
186 throw new ArgumentException ("parent must be a directory");
188 // no more names left
189 if (children.Count == Token.Count)
190 return null;
192 FileModel child;
193 child = new FileModel ();
194 child.name = PickName (this);
195 child.children = new Hashtable ();
197 child.parent = this;
198 children [child.name] = child;
200 // Actually create the directory
201 Directory.CreateDirectory (child.FullName);
203 return child;
206 public FileModel NewFile ()
208 if (! IsDirectory)
209 throw new ArgumentException ("parent must be a directory");
211 // no more names left
212 if (children.Count == Token.Count)
213 return null;
215 FileModel child;
216 child = new FileModel ();
217 child.name = PickName (this);
218 child.body = NewBody (10);
220 child.parent = this;
221 children [child.name] = child;
223 // Create the file
224 child.Write ();
226 return child;
229 //////////////////////////////////////////////////////////////
231 public void Grow (int depth)
233 const int num_dirs = 2;
234 const int num_files = 5;
236 if (depth > 0) {
237 for (int i = 0; i < num_dirs; ++i) {
238 FileModel file;
239 file = NewDirectory ();
240 if (file != null)
241 file.Grow (depth - 1);
245 for (int i = 0; i < num_files; ++i)
246 NewFile ();
249 //////////////////////////////////////////////////////////////
251 public void Delete ()
253 if (IsRoot)
254 throw new Exception ("Can't delete the root!");
256 if (IsDirectory)
257 Directory.Delete (FullName, true); // recursive
258 else
259 File.Delete (FullName);
261 parent.children.Remove (name);
262 parent = null;
266 //////////////////////////////////////////////////////////////
268 static private string PickName (FileModel p)
270 string pick;
271 do {
272 pick = Token.GetRandom ();
273 } while (p.children.Contains (pick));
274 return pick;
277 static private string [] NewBody (int size)
279 string [] body;
280 body = new string [size];
281 for (int i = 0; i < size; ++i)
282 body [i] = Token.GetRandom ();
283 Array.Sort (body);
284 return body;
287 private void Write ()
289 TextWriter writer;
290 writer = new StreamWriter (FullName);
291 for (int i = 0; i < body.Length; ++i)
292 writer.WriteLine (body [i]);
293 writer.Close ();
296 //////////////////////////////////////////////////////////////
299 // Code to determine a a file will match a particular query
302 private bool MatchesQueryPart (QueryPart abstract_part)
304 bool is_match;
305 is_match = false;
307 if (abstract_part is QueryPart_Text) {
308 QueryPart_Text part;
309 part = abstract_part as QueryPart_Text;
311 if ((part.SearchTextProperties && Name == part.Text)
312 || (part.SearchFullText && BodyContains (part.Text)))
313 is_match = true;
315 } else if (abstract_part is QueryPart_Or) {
316 QueryPart_Or part;
317 part = abstract_part as QueryPart_Or;
319 foreach (QueryPart sub_part in part.SubParts) {
320 if (MatchesQueryPart (sub_part)) {
321 is_match = true;
322 break;
325 } else if (abstract_part is QueryPart_Property) {
326 QueryPart_Property part;
327 part = abstract_part as QueryPart_Property;
329 if (part.Key == "beagle:MimeType") {
330 if (part.Value == "inode/directory")
331 is_match = IsDirectory;
332 else if (part.Value == "text/plain")
333 is_match = IsFile;
334 else
335 is_match = false;
336 } else if (part.Key == "beagle:ExactFilename") {
337 is_match = (Name == part.Value);
338 } else {
339 throw new Exception ("Unsupported property " + part.Key);
341 } else {
342 throw new Exception ("Unsupported part");
345 if (abstract_part.Logic == QueryPartLogic.Prohibited)
346 is_match = ! is_match;
348 return is_match;
351 public bool MatchesQuery (Query query)
353 // We assume the root node never matches any query.
354 if (IsRoot)
355 return false;
357 foreach (QueryPart part in query.Parts) {
358 if (! MatchesQueryPart (part))
359 return false;
362 return true;
365 private void RecursiveQueryCheck (ArrayList match_list, Query query)
367 if (MatchesQuery (query))
368 match_list.Add (this);
370 if (children != null)
371 foreach (FileModel file in children.Values)
372 file.RecursiveQueryCheck (match_list, query);
375 public ArrayList GetMatchingDescendants (Query query)
377 ArrayList match_list;
378 match_list = new ArrayList ();
379 RecursiveQueryCheck (match_list, query);
380 return match_list;