1# -*- coding: utf-8 -*-
2
3# Copyright (c) 2012 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4#
5
6"""
7Module implementing a class to write Netscape HTML bookmark files.
8"""
9
10from PyQt5.QtCore import QObject, QIODevice, QFile
11
12from .BookmarkNode import BookmarkNode
13
14import Utilities
15
16
17class NsHtmlWriter(QObject):
18    """
19    Class implementing a writer object to generate Netscape HTML bookmark
20    files.
21    """
22    indentSize = 4
23
24    def __init__(self):
25        """
26        Constructor
27        """
28        super().__init__()
29
30    def write(self, fileNameOrDevice, root):
31        """
32        Public method to write an Netscape HTML bookmark file.
33
34        @param fileNameOrDevice name of the file to write (string)
35            or device to write to (QIODevice)
36        @param root root node of the bookmark tree (BookmarkNode)
37        @return flag indicating success (boolean)
38        """
39        if isinstance(fileNameOrDevice, QIODevice):
40            f = fileNameOrDevice
41        else:
42            f = QFile(fileNameOrDevice)
43            if root is None or not f.open(QFile.WriteOnly):
44                return False
45
46        self.__dev = f
47        return self.__write(root)
48
49    def __write(self, root):
50        """
51        Private method to write an Netscape HTML bookmark file.
52
53        @param root root node of the bookmark tree (BookmarkNode)
54        @return flag indicating success (boolean)
55        """
56        self.__dev.write(
57            "<!DOCTYPE NETSCAPE-Bookmark-file-1>\n"
58            "<!-- This is an automatically generated file.\n"
59            "     It will be read and overwritten.\n"
60            "     DO NOT EDIT! -->\n"
61            "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html;"
62            " charset=UTF-8\">\n"
63            "<TITLE>Bookmarks</TITLE>\n"
64            "<H1>Bookmarks</H1>\n"
65            "\n"
66            "<DL><p>\n")
67        if root.type() == BookmarkNode.Root:
68            for child in root.children():
69                self.__writeItem(child, self.indentSize)
70        else:
71            self.__writeItem(root, self.indentSize)
72        self.__dev.write("</DL><p>\n")
73        return True
74
75    def __writeItem(self, node, indent):
76        """
77        Private method to write an entry for a node.
78
79        @param node reference to the node to be written (BookmarkNode)
80        @param indent size of the indentation (integer)
81        """
82        if node.type() == BookmarkNode.Folder:
83            self.__writeFolder(node, indent)
84        elif node.type() == BookmarkNode.Bookmark:
85            self.__writeBookmark(node, indent)
86        elif node.type() == BookmarkNode.Separator:
87            self.__writeSeparator(indent)
88
89    def __writeSeparator(self, indent):
90        """
91        Private method to write a separator.
92
93        @param indent size of the indentation (integer)
94        """
95        self.__dev.write(" " * indent)
96        self.__dev.write("<HR>\n")
97
98    def __writeBookmark(self, node, indent):
99        """
100        Private method to write a bookmark node.
101
102        @param node reference to the node to be written (BookmarkNode)
103        @param indent size of the indentation (integer)
104        """
105        added = (
106            " ADD_DATE=\"{0}\"".format(node.added.toTime_t())
107            if node.added.isValid() else
108            ""
109        )
110        modified = (
111            " LAST_MODIFIED=\"{0}\"".format(node.modified.toTime_t())
112            if node.modified.isValid() else
113            ""
114        )
115        visited = (
116            " LAST_VISIT=\"{0}\"".format(node.visited.toTime_t())
117            if node.visited.isValid() else
118            ""
119        )
120
121        self.__dev.write(" " * indent)
122        self.__dev.write("<DT><A HREF=\"{0}\"{1}{2}{3}>{4}</A>\n".format(
123            node.url, added, modified, visited,
124            Utilities.html_uencode(node.title)
125        ))
126
127        if node.desc:
128            self.__dev.write(" " * indent)
129            self.__dev.write("<DD>{0}\n".format(
130                Utilities.html_uencode("".join(node.desc.splitlines()))))
131
132    def __writeFolder(self, node, indent):
133        """
134        Private method to write a bookmark node.
135
136        @param node reference to the node to be written (BookmarkNode)
137        @param indent size of the indentation (integer)
138        """
139        folded = "" if node.expanded else " FOLDED"
140
141        added = (
142            " ADD_DATE=\"{0}\"".format(node.added.toTime_t())
143            if node.added.isValid() else
144            ""
145        )
146
147        self.__dev.write(" " * indent)
148        self.__dev.write("<DT><H3{0}{1}>{2}</H3>\n".format(
149            folded, added, Utilities.html_uencode(node.title)
150        ))
151
152        if node.desc:
153            self.__dev.write(" " * indent)
154            self.__dev.write("<DD>{0}\n".format(
155                "".join(node.desc.splitlines())))
156
157        self.__dev.write(" " * indent)
158        self.__dev.write("<DL><p>\n")
159
160        for child in node.children():
161            self.__writeItem(child, indent + self.indentSize)
162
163        self.__dev.write(" " * indent)
164        self.__dev.write("</DL><p>\n")
165