collection.py :  » Network » Grail-Internet-Browser » grail-0.6 » bookmarks » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Network » Grail Internet Browser 
Grail Internet Browser » grail 0.6 » bookmarks » collection.py
"""Bookmark-node manager.

The bookmark node manager supports requesting subsets of the bookmark
collection by URI components.  This is useful for locating a node in the
database which needs to be updated when the user interface successfully
'visits' a node and needs to update the last-visited and last-modified
information.

This class is also used to generate new ID values for nodes.
"""
__version__ = '$Revision: 1.6 $'

import copy
import nodes                            # sibling
import search                           # sibling sub-package
import string
import urlparse
import walker                           # sibling


class NodeIDError(Exception):
    """Raised when a node with a duplicate ID is added."""
    pass


def _parse_uri(uri):
    """Normalize a URI in parsed form (similar to urlparse() result)."""
    uri = list(urlparse.urlparse(uri))
    if uri[0] == "http":
        host = uri[1]
        if host[-3:] == ":80":
            host = host[:-3]
        uri[1] = string.lower(host)
    else:
        uri[1] = string.lower(uri[1])
    return tuple(uri)


class Collection:
    def __init__(self, root=None):
        self.set_root(root)

    def get_root(self):
        return self.__root

    def set_root(self, root):
        self.__root = root
        if root is None:
            maps = {}, {}, {}
        else:
            maps = self.build_info(root)
        self.__node_map, self.__id_map, self.__ref_map = maps

    def get_type_counts(self):
        root = self.get_root()
        count_map = {}
        queue = root.children()
        while queue:
            node = queue[0]
            del queue[0]
            nodetype = node.get_nodetype()
            count_map[nodetype] = count_map.get(nodetype, 0) + 1
            if nodetype == "Folder":
                queue[len(queue):] = node.children()
        return count_map

    def copytree(self, startnode=None):
        if startnode is None:
            startnode = self.__root
        walker = CopyWalker(startnode)
        walker.walk()
        class Object:
            pass
        coll = Object()
        coll.__class__ = Collection
        coll.__root = walker.get_new_root()
        coll.__node_map, coll.__id_map, coll.__ref_map = walker.get_new_info()
        return coll

    def merge_node(self, node, folder):
        node_map, id_map, ref_map = self.build_info(node)
        d = self.__id_map.copy()
        d.update(id_map)
        if len(d) != (len(id_map) + len(self.__id_map)):
            id_map, ref_map = self.relabel_tree(node, id_map, ref_map)
        self.__id_map.update(id_map)
        self.__ref_map.update(ref_map)
        folder.append_child(node)

    def relabel_tree(self, node, id_map, ref_map):
        """Relabel the IDs of a tree to not conflict with the existing root.
        This should be used to prepare for a merger."""
        need_ids = []
        queue = [node]
        while queue:
            node = queue.pop()
            nodetype = node.get_nodetype()
            if hasattr(node, "id"):
                id = node.id()
                if self.__id_map.has_key(id):
                    # this node must be relabeled:
                    new_id = self.new_id()
                    while id_map.has_key(new_id):
                        new_id = self.new_id()
                    node.set_id(new_id)
                    del id_map[id]
                    id_map[new_id] = node
                    if ref_map.has_key(id):
                        ref_map[new_id] = ref_map[id]
                        del ref_map[id]
            if hasattr(node, "children"):
                queue[len(queue):] = node.children()
        return id_map, ref_map

    __next_id = 1
    __id_format = "bkmk.%s"
    def new_id(self):
        i = self.__next_id
        while 1:
            id = self.__id_format % i
            i = i + 1
            if not self.__id_map.has_key(id):
                break
        self.__next_id = i
        return id

    def build_info(self, node):
        node_map = {}
        id_map = {}
        ref_map = {}
        need_ids = []
        queue = [node]
        while queue:
            node = queue[0]
            del queue[0]
            nodetype = node.get_nodetype()
            if nodetype == "Bookmark":
                id = node.id()
                if id_map.has_key(id):
                    raise NodeIDError("duplicate ID found: " + `id`)
                if id:
                    id_map[id] = node
                    if id in need_ids:
                        need_ids.remove(id)
                uri = node.uri()
                key = urlparse.urlunparse(_parse_uri(uri)[:3] + ('', '', ''))
                try:
                    node_map[key].append(node)
                except KeyError:
                    node_map[key] = [node]
            elif nodetype == "Folder":
                id = node.id()
                if id_map.has_key(id):
                    raise NodeIDError("duplicate ID found: " + `id`)
                if id:
                    id_map[id] = node
                    if id in need_ids:
                        need_ids.remove(id)
                # add child nodes to the end of the queue
                queue[len(queue):] = node.children()
            elif nodetype == "Alias":
                idref = node.idref()
                if not id_map.has_key(idref):
                    need_ids.append(idref)
                try:
                    ref_map[idref].append(node)
                except KeyError:
                    ref_map[idref] = [node]
        if need_ids:
            raise NodeIDError("Could not locate IDs", need_ids)
        return node_map, id_map, ref_map

    def add_Bookmark(self, node):
        self.add_Folder(node)
        key = self.__make_node_key(node)
        try:
            self.__node_map[key].append(node)
        except KeyError:
            self.__node_map[key] = [node]

    def add_Folder(self, node):
        id = node.id()
        if self.__id_map.has_key(id):
            raise NodeIDError("node ID already in ID map")
        if id is not None:
            self.__id_map[id] = node

    def del_node(self, node):
        try:
            self.__node_map[self.__make_node_key(node)].remove(node)
        except (KeyError, ValueError, AttributeError):
            pass
        try:
            del self.__id_map[node.id()]
        except (KeyError, AttributeError):
            pass

    def get_node_by_id(self, id):
        try:
            return self.__id_map[id]
        except KeyError:
            return None

    def get_bookmarks_by_uri(self, uri):
        parsed = _parse_uri(uri)
        uri = urlparse.urlunparse(parsed[:3] + ('', '', ''))
        try:
            return tuple(self.__node_map[uri])
        except KeyError:
            return ()

    def __make_node_key(self, node):
        parsed = _parse_uri(node.uri())[:3] + ('', '', '')
        return urlparse.urlunparse(parsed)


class CopyWalker(walker.TreeWalker):
    def __init__(self, root=None):
        walker.TreeWalker.__init__(self, root)
        self.__node_map = {}
        self.__id_map = {}
        self.__ref_map = {}
        self.__needed_ids = []
        self.__parents = []
        self.__new_root = None

    def get_new_info(self):
        return (self.__node_map, self.__id_map, self.__ref_map)

    def get_new_root(self):
        if self.__parents:
            raise RuntimeError, \
                  "cannot retrieve new root before walk is complete"
        if self.__needed_ids:
            raise RuntimeError, \
                  "copied tree cannot resolve all referenced IDs: " \
                  + string.join(self.__needed_ids)
        return self.__new_root

    def add_node(self, node):
        if self.__new_root is None:
            self.__new_root = node
        else:
            self.__parents[-1].append_child(node)

    def add_describable(self, node, old_node):
        id = old_node.id()
        if id:
            node.set_id(id)
            self.__id_map[id] = node
            if self.__ref_map.has_key(id):
                for alias in self.__ref_map[id]:
                    alias.set_refnode(node)
            if id in self.__needed_ids:
                self.__needed_ids.remove(id)
        node.set_add_date(old_node.add_date())
        node.set_title(old_node.title())
        node.set_description(old_node.description())
        node.set_info(copy.deepcopy(old_node.info()))

    def start_Alias(self, node):
        idref = node.idref()
        if self.__id_map.has_key(idref):
            new_node = nodes.Alias(self.__id_map[idref])
        else:
            new_node = nodes.Alias()
            if idref not in self.__needed_ids:
                self.__needed_ids.append(idref)
        if self.__ref_map.has_key(idref):
            L = self.__ref_map[idref]
        else:
            L = self.__ref_map[idref] = []
        L.append(new_node)
        self.add_node(new_node)

    def start_Bookmark(self, node):
        new_node = nodes.Bookmark()
        self.add_node(new_node)
        self.add_describable(new_node, node)
        uri = node.uri()
        new_node.set_uri(uri)
        new_node.set_last_modified(node.last_modified())
        new_node.set_last_visited(node.last_visited())
        key = urlparse.urlunparse(_parse_uri(uri)[:3] + ('', '', ''))
        try:
            self.__node_map[key].append(new_node)
        except KeyError:
            self.__node_map[key] = [new_node]

    def start_Folder(self, node):
        new_node = nodes.Folder()
        self.add_node(new_node)
        self.add_describable(new_node, node)
        if node.expanded_p():
            new_node.expand()
        else:
            new_node.collapse()
        self.__parents.append(new_node)

    def end_Folder(self, node):
        self.__parents.pop()

    def start_Separator(self, node):
        self.add_node(nodes.Separator())
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.