]> git.phdru.name Git - bookmarks_db.git/blob - bkmk_objects.py
Renamed parse_html modules to bkmk_ph_* to avoid name clashes.
[bookmarks_db.git] / bkmk_objects.py
1 """Objects to represent bookmarks.html structure
2
3 This file is a part of Bookmarks database and Internet robot.
4 """
5
6 __version__ = "$Revision$"[11:-2]
7 __revision__ = "$Id$"[5:-2]
8 __date__ = "$Date$"[7:-2]
9 __author__ = "Oleg Broytman <phd@phdru.name>"
10 __copyright__ = "Copyright (C) 2000-2011 PhiloSoft Design"
11 __license__ = "GNU GPL"
12
13 __all__ = ['Folder', 'Bookmark', 'Ruler', 'Walker', 'Writer', 'Robot',
14     'InverseLinker', 'Linear', 'make_linear', 'make_tree', 'break_tree',
15     'quote_title', 'unquote_title',
16 ]
17
18
19 import os, cgi
20 BKMK_FORMAT = os.environ.get("BKMK_FORMAT", "MOZILLA")
21
22
23 class Folder(list):
24    isFolder = 1
25    isBookmark = 0
26
27    def __init__(self, add_date=None, comment='', last_modified=None):
28       super(Folder, self).__init__()
29       self.comment = comment
30       self.add_date = add_date
31       self.last_modified = last_modified
32
33    def walk_depth(self, walker, level=0):
34       if hasattr(self, "header"): # root folder
35          prune = 0
36          walker.root_folder(self)
37       else:
38          prune = walker.prune_folder(self)
39          if not prune:
40             walker.start_folder(self, level)
41
42       if not prune:
43          for object in self:
44             if object.isFolder:
45                object.walk_depth(walker, level+1)
46             elif object.isBookmark:
47                walker.bookmark(object, level)
48             else:
49                walker.ruler(object, level)
50
51          walker.end_folder(self, level)
52
53
54 class Bookmark:
55    isFolder = 0
56    isBookmark = 1
57
58    def __init__(self, href, add_date, last_visit=None, last_modified=None,
59          keyword=None, comment='', icon_href=None, icon=None, charset=None):
60       self.href = href
61       self.add_date = add_date
62       self.last_visit = last_visit
63       self.last_modified = last_modified
64       self.keyword = keyword
65       self.comment = comment
66       self.icon_href = icon_href
67       self.icon = icon
68       self.charset = charset
69
70
71 class Ruler:
72    isFolder = 0
73    isBookmark = 0
74
75
76 class Walker:
77    """
78       Interface class. Any instance that will be passed to Folder.walk_depth
79       may be derived from this class. It is not mandatory - unlike Java
80       Python does not require interface classes; but it is convenient to have
81       some methods predefined to no-op, in case you do not want to
82       provide end_folder etc.
83    """
84
85    def root_folder(self, r):
86       pass
87
88    def start_folder(self, f, level):
89       pass
90
91    def end_folder(self, f, level):
92       pass
93
94    def bookmark(self, b, level):
95       pass
96
97    def ruler(self, r, level):
98       pass
99
100    def prune_folder(self, folder):
101       return 0
102
103
104 class Writer(Walker):
105    def __init__(self, outfile, prune=None):
106       self.outfile = outfile
107       self.prune = prune
108
109    def prune_folder(self, folder):
110       return self.prune == folder.name
111
112
113 class Robot:
114    def __init__(self, log):
115       self.log = log
116
117    def stop(self):
118       pass # Nothing to do on cleanup
119
120
121 # Helper class to make inverese links (nodes linked to their parent)
122 class InverseLinker(Walker):
123    def root_folder(self, r):
124       self.parent_stack = [r]
125
126    def start_folder(self, f, level):
127       f.parent = self.parent_stack[-1]
128       self.parent_stack.append(f) # Push the folder onto the stack of parents
129
130    def end_folder(self, f, level):
131       del self.parent_stack[-1]   # Pop off the stack
132
133    def bookmark(self, b, level):
134       b.parent = self.parent_stack[-1]
135
136    def ruler(self, r, level):
137       r.parent = self.parent_stack[-1]
138
139
140 # Helper class to make linear represenatation of the tree
141 class Linear(Walker):
142    def root_folder(self, r):
143       r.linear = [r]
144       self.linear = r.linear
145
146    def add_object(self, object):
147       self.linear.append(object)
148
149    def start_folder(self, f, level):
150       self.add_object(f)
151
152    def bookmark(self, b, level):
153       self.add_object(b)
154
155    def ruler(self, r, level):
156       self.add_object(r)
157
158
159 # Helper - make linked linear represenatation of the tree, suitable to be stored in sequential storage
160 def make_linear(root_folder):
161    linker = InverseLinker()
162    root_folder.walk_depth(linker)
163
164    linear = Linear()
165    root_folder.walk_depth(linear)
166
167
168 # Helper, opposite of make_linear - make a tree from the linked linear representation
169 def make_tree(linear):
170    root_folder = linear[0]
171    del linear[0]
172
173    for object in linear:
174       object.parent.append(object)
175
176    return root_folder
177
178 def break_tree(linear):
179    del linear[0]
180
181    for object in linear:
182       del object.parent
183
184
185 def quote_title(title):
186    if BKMK_FORMAT == "MOZILLA":
187       title = title.replace("'", "&#39;")
188    return title
189
190 def unquote_title(title):
191    if BKMK_FORMAT == "MOZILLA":
192       from HTMLParser import HTMLParser
193       title = HTMLParser().unescape(title.replace("&amp;", '&'))
194       title = title.replace("&#39;", "'")
195    return title