Commits

Brian Mearns committed c6f62b0

Continued work on writeText with AbstractWriter and TextOutput.
Primarily cleaning up all the ctx stuff, and adding titles to writeText.

  • Participants
  • Parent commits 968bc12
  • Branches pre2.0

Comments (0)

Files changed (3)

File src/tome/AbstractWriter.py

     def cause(self):
         return self.__cause
 
+LEVEL_LOWEST = -1
+LEVEL_TOME = 0
+LEVEL_PART = 1
+LEVEL_BOOK = 2
+LEVEL_CHAPTER = 3
+LEVEL_SCENE = 4
+LEVEL_PARAGRAPH = 5
     
 
 class AbstractWriter(object):
+
+    def __init__(self):
+        self.tome = self.part = self.book = self.chapter = self.scene = self.par = None
+        self.__numbers = (
+            [0],            #part numbers
+            [0,0],          #book numbers
+            [0,0,0],        #chapter numbers
+            [0,0,0,0],      #scene numbers
+            [0,0,0,0,0],    #par numbers
+        )
+
+    def _stepNumbers(self, level):
+        for i in xrange(len(self.__numbers[level-1])):
+            self.__numbers[level-1][i] += 1
+
+        #Reset the lower numbers
+        for i in xrange(level, len(self.__numbers)):
+            numbers = self.__numbers[i]
+            for j in xrange(level, len(numbers)):
+                numbers[j] = 0
+
+    def listNumbers(self, level, relative=0):
+        """
+        Like `getNumber`, but returns a tuple of the numbers of all the levels up
+        to (but not including) `relative`, relative to `relative`.
+        """
+        return tuple(self.getNumber(L, -1) for L in xrange(relative+1, level+1))
+
+    def joinNumbers(self, glue, level, relative=0):
+        return glue.join("%d" % number for number in self.listNumbers(level, relative))
+        
+    def getNumber(self, level, relative=-1):
+        """
+        Returns the current number of a section, relative to another level.
+
+        For instance, you can find the number of the chapter within the current book, or within
+        the current part, or within the entire tome. By default, returns the number relative to
+        the next layer up (e.g., par in scene, scene in chapter, etc.).
+        """
+        return self.__numbers[level-1][relative]
+
     def write(self, tome):
         """
         The main API function which is called to generate the complete output for the specified
         |Tome| object based on this object's configuration.
         """
 
+        self.tome = tome
         try:
-            ctx = self._prepareOutput(tome)
-            self._frontMatter(tome, ctx)
+            self._prepareOutput(tome)
+            self._frontMatter(tome)
 
             for part in tome:
-                self._writePart(part, ctx)
+                self.part = part
+                self._stepNumbers(LEVEL_PART)
+                self._writePart(part)
 
-            self._endMatter(tome, ctx)
-            self._finishOutput(tome, ctx)
+            self._endMatter(tome)
+            self._finishOutput(tome)
         except TomeWriterException: raise
-        except Exception, e: self._raiseError(ctx, None, e)
+        except Exception, e: self._raiseError(None, e)
 
     def _prepareOutput(self, tome):
         """
         Called as the first step of `write`, this is typically used to open the output stream or
         create any output directories that are required.
+        """
+        pass
 
-        :returns: An abritrary value which can be used by implementations to manage contextual data
-        related to generating this particular output. The returned value will be passed into each
-        of the subsequent steps called by `write` and is a useful alternative to instance variables.
-        The default implementation returns an empty dictionary to which data can be added by subsequent
-        steps.
-        """
-        return {}
-
-    def _frontMatter(self, tome, ctx):
+    def _frontMatter(self, tome):
         """
         Called as the second step of `write` (after `_prepareOutput`), this is typically used to generate
         any front matter for the document, such as title pages, tables of contents, etc.
         """
         pass
 
-    def _endMatter(self, tome, ctx):
+    def _endMatter(self, tome):
         """
         Called as the second-to-last step of `write` (immediately before `_finishOutput`), this is typically
         used to generate any back matter for the document, such as indices, appendicies, afterwards, etc.
         """
         pass
 
-    def _finishOutput(self, tome, ctx):
+    def _finishOutput(self, tome):
         """
         Called as the final step of `write`, this is typically used to close the output stream or package up
         the generated files, as needed.
         """
         pass
 
-    def _raiseError(self, ctx, position, e):
+    def _raiseError(self, position, e):
         trace = sys.exc_info()[2]
         raise TomeWriterException(position, e), None, trace
 
-    def _writePart(self, part, ctx):
+    def _writePart(self, part):
         try:
-            ctx = self._preparePart(part, ctx)
+            self._preparePart(part)
             
-            self._writePartTitle(part, ctx)
+            self._writePartTitle(part)
             for book in part:
-                self._writeBook(book, ctx)
+                self.book = book
+                self._stepNumbers(LEVEL_BOOK)
+                self._writeBook(book)
 
-            self._finishPart(part, ctx)
+            self._finishPart(part)
         except TomeWriterException: raise
-        except Exception, e: self._raiseError(ctx, None, e)
+        except Exception, e: self._raiseError(None, e)
 
-    def _preparePart(self, part, ctx):
-        return ctx
-
-    def _writePartTitle(self, part, ctx):
+    def _preparePart(self, part):
         pass
 
-    def _finishPart(self, part, ctx):
+    def _writePartTitle(self, part):
         pass
 
-    def _writeBook(self, book, ctx):
-        try:
-            ctx = self._prepareBook(book, ctx)
-            
-            self._writeBookTitle(book, ctx)
-            for chapter in book:
-                self._writeChapter(chapter, ctx)
-
-            self._finishBook(book, ctx)
-        except TomeWriterException: raise
-        except Exception, e: self._raiseError(ctx, None, e)
-
-    def _prepareBook(self, book, ctx):
-        return ctx
-
-    def _writeBookTitle(self, book, ctx):
+    def _finishPart(self, part):
         pass
 
-    def _finishBook(self, book, ctx):
+    def _writeBook(self, book):
+        try:
+            self._prepareBook(book)
+            
+            self._writeBookTitle(book)
+            for chapter in book:
+                self.chapter = chapter
+                self._stepNumbers(LEVEL_CHAPTER)
+                self._writeChapter(chapter)
+
+            self._finishBook(book)
+        except TomeWriterException: raise
+        except Exception, e: self._raiseError(None, e)
+
+    def _prepareBook(self, book):
         pass
 
-    def _writeChapter(self, chapter, ctx):
+    def _writeBookTitle(self, book):
+        pass
+
+    def _finishBook(self, book):
+        pass
+
+    def _writeChapter(self, chapter):
         try:
-            ctx = self._prepareChapter(chapter, ctx)
+            self._prepareChapter(chapter)
             
-            self._writeChapterTitle(chapter, ctx)
+            self._writeChapterTitle(chapter)
             sceneCount = len(chapter)
             lastScene = sceneCount-1
             for i in xrange(sceneCount):
-                self._writeScene(chapter[i], ctx, i==0, i==lastScene)
+                self.scene = chapter[i]
+                self._stepNumbers(LEVEL_SCENE)
+                self._writeScene(self.scene, i==0, i==lastScene)
 
-            self._finishChapter(chapter, ctx)
+            self._finishChapter(chapter)
         except TomeWriterException: raise
-        except Exception, e: self._raiseError(ctx, None, e)
+        except Exception, e: self._raiseError(None, e)
 
-    def _prepareChapter(self, chapter, ctx):
-        return ctx
-
-    def _writeChapterTitle(self, chapter, ctx):
+    def _prepareChapter(self, chapter):
         pass
 
-    def _finishChapter(self, chapter, ctx):
+    def _writeChapterTitle(self, chapter):
         pass
 
-    def _writeScene(self, scene, ctx, firstScene, lastScene):
+    def _finishChapter(self, chapter):
+        pass
+
+    def _writeScene(self, scene, firstScene, lastScene):
         try:
 
-            ctx = self._prepareScene(scene, ctx, firstScene)
+            self._prepareScene(scene, firstScene)
             parCount = len(scene)
             lastPar = parCount-1
             for i in xrange(parCount):
                 paragraph = scene[i]
+                self.paragraph = paragraph
+                self._stepNumbers(LEVEL_PARAGRAPH)
+
                 tag = paragraph.tag()
                 if tag not in ("p", "pre"):
                     raise Exception("Invalid toplevel element in scene: %s" % tag)
+
                 if tag == "pre":
-                    self._writePreformatted(paragraph, ctx, i==0, i==lastPar)
+                    self._writePreformatted(paragraph, i==0, i==lastPar)
                 else:
-                    self._writeParagraph(paragraph, ctx, i==0, i==lastPar)
-            self._finishScene(scene, ctx, lastScene)
+                    self._writeParagraph(paragraph, i==0, i==lastPar)
+            self._finishScene(scene, lastScene)
 
         except TomeWriterException: raise
-        except Exception, e: self._raiseError(ctx, None, e)
+        except Exception, e: self._raiseError(None, e)
 
-    def _prepareScene(self, scene, ctx, firstScene):
-        return ctx
-
-    def _finishScene(self, scene, ctx, lastScene):
+    def _prepareScene(self, scene, firstScene):
         pass
 
-    def _writePreformatted(self, paragraph, ctx, firstPar, lastPar):
-        try:
-            ctx = self._preparePreformatted(paragraph, ctx, firstPar)
-            for segment in paragraph:
-                self._writePreformattedSegment(segment, ctx)
-            self._finishPreformatted(paragraph, ctx, lastPar)
-        except TomeWriterException: raise
-        except Exception, e: self._raiseError(ctx, None, e)
-
-    def _preparePreformatted(self, paragraph, ctx, firstPar):
-        return ctx
-
-    def _finishPreformatted(self, paragraph, ctx, lastPar):
+    def _finishScene(self, scene, lastScene):
         pass
 
-    def _writeParagraph(self, paragraph, ctx, firstPar, lastPar):
+    def _writePreformatted(self, paragraph, firstPar, lastPar):
         try:
-            ctx = self._prepareParagraph(paragraph, ctx, firstPar)
+            self._preparePreformatted(paragraph, firstPar)
             for segment in paragraph:
-                self._writeSegment(segment, ctx)
-            self._finishParagraph(paragraph, ctx, lastPar)
+                self._writePreformattedSegment(segment)
+            self._finishPreformatted(paragraph, lastPar)
         except TomeWriterException: raise
-        except Exception, e: self._raiseError(ctx, None, e)
+        except Exception, e: self._raiseError(None, e)
 
-    def _prepareParagraph(self, paragraph, ctx, firstPar):
-        return ctx
-
-    def _finishParagraph(self, paragraph, ctx, lastPar):
+    def _preparePreformatted(self, paragraph, firstPar):
         pass
 
-    def _writePreformattedSegment(self, segment, ctx):
-        return self._writeSegment(segment, ctx)
+    def _finishPreformatted(self, paragraph, lastPar):
+        pass
 
-    def _writeSegment(self, segment, ctx):
+    def _writeParagraph(self, paragraph, firstPar, lastPar):
+        try:
+            self._prepareParagraph(paragraph, firstPar)
+            for segment in paragraph:
+                self._writeSegment(segment)
+            self._finishParagraph(paragraph, lastPar)
+        except TomeWriterException: raise
+        except Exception, e: self._raiseError(None, e)
+
+    def _prepareParagraph(self, paragraph, firstPar):
+        pass
+
+    def _finishParagraph(self, paragraph, lastPar):
+        pass
+
+    def _writePreformattedSegment(self, segment):
+        return self._writeSegment(segment)
+
+    def _writeSegment(self, segment):
         if isinstance(segment, Tome.TextSegment):
             try:
-                self._writeText(segment.text(), segment, ctx)
+                self._writeText(segment.text(), segment)
             except TomeWriterException: raise
-            except Exception, e: self._raiseError(ctx, segment, e)
+            except Exception, e: self._raiseError(segment, e)
 
         elif isinstance(segment, Tome.TaggedSegment):
             tag = segment.tag()
             try:
                 #Formatting
                 if tag in ("pre" , "b" , "i" , "em" , "u"):
-                    self._writeFormatSegment(tag, segment, ctx)
+                    self._writeFormatSegment(tag, segment)
 
                 #Block segments
                 elif tag in ("q", "sq", "bq"):
-                    self._writeBlockSegment(tag, segment, ctx)
+                    self._writeBlockSegment(tag, segment)
 
                 #Notes:
                 elif tag == "n":
-                    self._writeNote(segment, ctx)
+                    self._writeNote(segment)
 
                 #Text objects
                 elif tag in ("ellips", "md", "nd", "sp", "lnbrk"):
-                    self._writeTextObject(tag, segment, ctx)
+                    self._writeTextObject(tag, segment)
 
                 #Accents
                 elif tag in ("grave", "acute", "circumflex", "umlaut", "tilde", "cedilla"):
                     target = segment[0].text()
                     if len(target) != 1:
                         raise Exception("Invalid use of %s accent: segment content must be a single character: " + target)
-                    self._writeAccent(tag, target, segment, ctx)
+                    self._writeAccent(tag, target, segment)
                     
 
             except TomeWriterException: raise
-            except Exception, e: self._raiseError(ctx, segment, e)
+            except Exception, e: self._raiseError(segment, e)
 
         else:
             raise TypeError("Unexpected type for segment:" % repr(segment))
 
-    def _writeNote(self, segment, ctx):
+    def _writeNote(self, segment):
         #FIXME: TODO
         pass
 
-    def _writeBlockSegment(self, tag, segment, ctx):
-        ctx = self._prepareBlockSegment(tag, segment, ctx)
+    def _writeBlockSegment(self, tag, segment):
+        self._prepareBlockSegment(tag, segment)
 
         notFirst = False
         parCount = len(segment)
                 raise Exception("Block node may only contain \"p\" elements: found \"%s\"" % par.tag())
 
             #Don't actually put a par-break in front of the first paragraph in a block element (like a quoted string).
-            cctx = ctx
             if notFirst:
-                cctx = self._openPar(self, par, ctx)
+                cself._openPar(self, par)
                 notFirst = True
 
             for child in par:
-                self._writeSegment(child, cctx)
+                self._writeSegment(child)
                 dropCap = False
 
             if parNum != (parCount-1):
-                self._closePar(par, cctx)
+                self._closePar(par)
 
-        self._finishBlockSegment(tag, segment, ctx)
+        self._finishBlockSegment(tag, segment)
 
     @abc.abstractmethod
-    def _prepareBlockSegment(self, tag, segment, ctx):
-        return ctx
-
-    @abc.abstractmethod
-    def _finishBlockSegment(self, tag, segment, ctx):
+    def _prepareBlockSegment(self, tag, segment):
         pass
 
     @abc.abstractmethod
-    def _openPar(self, par, ctx):
+    def _finishBlockSegment(self, tag, segment):
+        pass
+
+    @abc.abstractmethod
+    def _openPar(self, par):
         """
         Called by `_writeBlockSegment` to open subsequent paragraphs within the block segment.
         This is NOT called for the first segment in the block, which is considered part of the current
         paragraph.
-
-        This method should return a new context to be used for the rest of this paragraph, passed
-        to `_writeSegment` for each of the child segments, and `_closePar`, if it is called.
         """
-        return ctx
+        pass
 
     @abc.abstractmethod
-    def _closePar(self, par, ctx):
+    def _closePar(self, par):
         """
         Called by `_writeBlockSegment` to close all but the last paragraph within the block segment.
         """
         pass
 
-    def _writeFormatSegment(self, tag, segment, ctx):
+    def _writeFormatSegment(self, tag, segment):
         """
         Writes the output for a formatting segment (e.g., bold, italics, etc.).
         This is called from `_writeSegment` for segments which are determined to be
         
         :param segment: The segment to write.
         :type segment: `Tome.TaggedSegment`.
+        """
+        self._prepareFormatSegment(tag, segment)
+        for child in segment:
+            self._writeSegment(child)
+        self._finishFormatSegment(tag, segment)
 
-        :param ctx: The current context.
-        """
-        ctx = self._prepareFormatSegment(tag, segment, ctx)
-        for child in segment:
-            self._writeSegment(child, ctx)
-        self._finishFormatSegment(tag, segment, ctx)
-
-    def _prepareFormatSegment(self, tag, segment, ctx):
+    def _prepareFormatSegment(self, tag, segment):
         """
         Called from the default implementation of `_writeFormatSegment` in order to
         open the formatting. 
+        """
+        self._writeOut(self._formatPrefix(tag, segment))
+        pass
 
-        :returns: A new context for use while writing the segment.
-        """
-        self._writeOut(self._formatPrefix(tag, segment, ctx), ctx)
-        return ctx
-
-    def _finishFormatSegment(self, tag, segment, ctx):
+    def _finishFormatSegment(self, tag, segment):
         """
         Called from the default implementation of `_writeFormatSegment` in order to
         close the formatting. 
         """
-        self._writeOut(self._formatSuffix(tag, segment, ctx), ctx)
+        self._writeOut(self._formatSuffix(tag, segment))
 
     @abc.abstractmethod
-    def _formatPrefix(self, tag, segment, ctx):
+    def _formatPrefix(self, tag, segment):
         """
         Return a string which should prefix the content for the specified
         format segment (e.g., bold, italics, etc.). Used by default implementation
         
         :param segment: The segment whose formatting tag is being requested.
         :type segment: `Tome.TaggedSegment`.
-
-        :param ctx: The current context.
         """
         pass
 
     @abc.abstractmethod
-    def _formatSuffix(self, tag, segment, ctx):
+    def _formatSuffix(self, tag, segment):
         """
         Return a string which should suffix the content for the specified
         format segment (e.g., bold, italics, etc.). Used by default implementation
         
         :param segment: The segment whose formatting tag is being requested.
         :type segment: `Tome.TaggedSegment`.
-
-        :param ctx: The current context.
         """
         pass
 
     @abc.abstractmethod
-    def _writeOut(self, string, ctx):
+    def _writeOut(self, string):
         """
         Write the specified string to the output stream.
 
         :param str string: The string to write.
-        :param ctx: The current context.
         """
         pass
 
-    def _writeText(self, text, segment, ctx):
+    def _writeText(self, text, segment):
         """
         Write a text segment to the output stream. Default simply passes the text directly to `_writeOut`.
 
         
         :param segment: The segment to write.
         :type segment: `Tome.TextSegment`
-
-        :param ctx: The current context.
         """
-        self._writeOut(text, ctx)
+        self._writeOut(text)
 
     @abc.abstractmethod
-    def _writeTextObject(self, tag, segment, ctx):
+    def _writeTextObject(self, tag, segment):
         """
         Write a text object (mdash, ellips, etc.) to the output stream.
 
         
         :param segment: The segment to write.
         :type segment: `Tome.TaggedSegment`
-
-        :param ctx: The current context.
         """
         pass
 
     @abc.abstractmethod
-    def _writeAccent(self, tag, char, segment, ctx):
+    def _writeAccent(self, tag, char, segment):
         """
         Write an accented character to the output stream.
 
         
         :param segment: The segment to write.
         :type segment: `Tome.TaggedSegment`
-
-        :param ctx: The current context.
         """
         pass
 
+
+

File src/tome/TextOutput.py

         """
         self.__ostream = ostream
         self.linewidth = linewidth
+        self.__justify = []
         self.justify = justify
         self.__buffer = ""
 
         """
         Sets the justification, and returns the old value.
         """
-        old = self.__justify
-        self.__justify = justify
-        return old
+        self.__justify.append(justify)
+
+    def popJustify(self):
+        return self.__justify.pop()
 
     @property
     def justify(self):
-        return self.__justify
+        return self.__justify[-1]
 
     @justify.setter
     def justify(self, justify):
 
         """
         if justify in (JUSTIFY_LEFT, JUSTIFY_RIGHT, JUSTIFY_CENTER, JUSTIFY_FULL):
-            self.__justify = justify
+            self.__setJustify(justify)
         else:
             raise ValueError("Invalid value for justify.")
 
         """
         A string identifying the current justification.
         """
-        return JUSTIFY_NAMES[self.__justify]
+        return JUSTIFY_NAMES[self.justify]
 
     @property
     def ostream(self):
         """
         self.__writePar()
 
+    def hr(self, fill=1.0, maxlength=None, c='-'):
+        self.flush()
+        available = self.__linewidth - len(self.__prefix) + len(self.__suffix)
+        width = int(float(available)*fill)
+        if maxlength is not None and maxlength < width:
+            width = maxlength
+        if ((width % 2) != (available % 2)) and (width > 3):
+            width -= 1
+        self.__writeLineOfWords([c*width])
+
     def blankline(self):
         """
         Insert a blank line after the current text. This will add one or two linebreaks
 
         """
         if justify is None:
-            justify = self.__justify
+            justify = self.justify
 
         if justify == JUSTIFY_LEFT:
             line = self.__prefix + indent + " ".join(words) + self.__suffix
         words = self.__buffer.split()
         self.__buffer = ""
 
-        doIndent = self.__justify != JUSTIFY_CENTER
+        doIndent = self.justify != JUSTIFY_CENTER
 
         linenum = 1
         tlen = len(self.parIndent)
 
         if linelength > 0:
             #Don't full justify the last line.
-            if self.__justify == JUSTIFY_FULL:
+            if self.justify == JUSTIFY_FULL:
                 justify = JUSTIFY_LEFT
             else:
-                justify = self.__justify
+                justify = self.justify
             self.__writeLineOfWords(line, indent, justify)
 
     def flush(self):

File src/tome/writeText.py

         self.__noteNumber = 1
 
 
-    def _openPar(self, par, ctx):
-        return ctx
-
-    def _closePar(self, par, ctx):
+    def _closePar(self, par):
         self.__writer.blankline()
 
-    def _writeAccent(self, tag, char, segment, ctx):
+    def _writeAccent(self, tag, char, segment):
         self.__writer.write(char)
 
-    def _writeTextObject(self, tag, segment, ctx):
+    def _writeTextObject(self, tag, segment):
         if tag == "lnbrk":
             self.__writer.newline()
         elif tag == "sp":
         else:
             raise Exception("Unsupported text object '%s'." % tag)
 
-    def _writeOut(self, string, ctx):
+    def _writeOut(self, string):
         self.__writer.write(string)
 
-    def _formatSuffix(self, tag, segment, ctx):
+    def _formatSuffix(self, tag, segment):
         if tag in TextWriter.__FORMAT_MAP:
             return TextWriter.__FORMAT_MAP[tag]
         else:
             raise Exception("Unsupported format tag '%s'." % tag)
         
-    def _formatPrefix(self, tag, segment, ctx):
+    def _formatPrefix(self, tag, segment):
         if tag in TextWriter.__FORMAT_MAP:
             return TextWriter.__FORMAT_MAP[tag]
         else:
             raise Exception("Unsupported format tag '%s'." % tag)
 
-    def _finishBlockSegment(self, tag, segment, ctx):
+    def _finishBlockSegment(self, tag, segment):
         if tag == "q":
             self.__writer.write('"')
         elif tag == "sq":
             self.__writer.outdent()
             self.__writer.rightOutdent()
         
-    def _prepareBlockSegment(self, tag, segment, ctx):
+    def _prepareBlockSegment(self, tag, segment):
         if tag == "q":
             self.__writer.write('"')
         elif tag == "sq":
             self.__writer.indent()
             self.__writer.rightIndent()
             self.__writer.write('"')
-        return ctx
         
-    def _prepareScene(self, scene, ctx, firstScene):
+    def _prepareScene(self, scene, firstScene):
         if not firstScene:
             self.__writer.blankline()
             justify = self.__writer.justifyCenter()
             self.__writer.write("***")
             self.__writer.blankline()
             self.__writer.justify = justify
-        return ctx
 
-    def _prepareParagraph(self, paragraph, ctx, firstPar):
+    def _prepareParagraph(self, paragraph, firstPar):
         if not firstPar:
             self.__writer.blankline()
-        return ctx
 
-    def _finishParagraph(self, par, ctx, lastPar):
+    def _finishParagraph(self, par, lastPar):
         self.__writer.flush()
 
-    def _preparePreformatted(self, par, ctx, firstPar):
+    def _preparePreformatted(self, par, firstPar):
         if not firstPar:
             self.__writer.blankline()
         self.__writer.preformatted = True
         self.__writer.indent()
-        return ctx
 
-    def _finishPreformatted(self, par, ctx, lastPar):
+    def _finishPreformatted(self, par, lastPar):
         self.__writer.outdent()
         self.__writer.preformatted = False
 
-
-
-    def writeHr(self, ostream, width, linewidth=None, char='-'):
-
-        hr = char*width
-
-        if linewidth is None:
-            linewidth = self.__linewidth
-
-        if linewidth is None:
-            ostream.write(hr + "\n")
+    def _writePartTitle(self, part):
+        if part.title() is None:
             return
 
-        diff = linewidth - width
-        lpadd = (diff + 1) / 2
-        ostream.write((" "*lpadd) + hr + "\n")
+        self.__writer.flush()
+        self.__writer.justifyCenter()
+        for i in xrange(4):
+            self.__writer.blankline()
+        self.__writer.hr(fill=0.6, c='=')
+        for i in xrange(3):
+            self.__writer.blankline()
+
+        string = "PART %d" % (
+            self.getNumber(AbstractWriter.LEVEL_PART),
+        )
+        self.__writer.write(string)
+
+        titles = part.allTitles()
+        titleCount = len(titles)
+        if titleCount > 0:
+            self.__writer.blankline()
+            for i in xrange(titleCount):
+                self.__writer.write(titles[i])
+                self.__writer.newline()
+
+        self.__writer.blankline()
+        self.__writer.flush()
+        self.__writer.popJustify()
+
+    def _writeBookTitle(self, book):
+
+        self.__writer.flush()
+        self.__writer.justifyCenter()
+
+        hasPart = self.part.title() is not None
+        hasBook = book.title() is not None
+        firstBook = (self.getNumber(AbstractWriter.LEVEL_BOOK) == 1) and hasPart
+
+        if hasBook:
+
+            if firstBook:
+                self.__writer.blankline()
+                self.__writer.blankline()
+                self.__writer.write("-----")
+                self.__writer.blankline()
+                self.__writer.blankline()
+                self.__writer.write("Book %d" % (
+                    self.getNumber(AbstractWriter.LEVEL_BOOK)
+                ))
+
+            else:
+                self.__writer.blankline()
+                self.__writer.blankline()
+                self.__writer.hr(fill=0.4)
+                self.__writer.blankline()
+                self.__writer.blankline()
+                self.__writer.blankline()
+
+                if hasPart:
+                    self.__writer.write("Part %d, " % self.getNumber(AbstractWriter.LEVEL_PART))
+                self.__writer.write("Book %d" % self.getNumber(AbstractWriter.LEVEL_BOOK))
+
+            titles = book.allTitles()
+            titleCount = len(titles)
+            if titleCount > 0:
+                self.__writer.blankline()
+                tcount = 0
+                for i in xrange(titleCount):
+                    title = titles[i]
+                    if len(title.strip()) > 0:
+                        self.__writer.write(titles[i])
+                        self.__writer.newline()
+                        tcount += 1
+                if tcount > 0:
+                    self.__writer.blankline()
+            self.__writer.blankline()
+            self.__writer.blankline()
+
+        if firstBook and hasPart:
+            self.__writer.hr(fill=0.6, c='=')
+        elif hasBook:
+            self.__writer.hr(fill=0.4)
+
+        self.__writer.popJustify()
+
         
 
-            
+    def _writeChapterTitle(self, chapter):
+        self.__writer.flush()
+        self.__writer.blankline()
+        self.__writer.blankline()
+        self.__writer.blankline()
+        self.__writer.justifyCenter()
+
+        string = "Chapter %d" % self.getNumber(AbstractWriter.LEVEL_CHAPTER)
+        self.__writer.write(string)
+        self.__writer.hr(maxlength=len(string))
+
+        titles = chapter.allTitles()
+        titleCount = len(titles)
+        if titleCount > 0:
+            for i in xrange(titleCount):
+                self.__writer.newline()
+                self.__writer.write(titles[i])
+            self.__writer.hr(maxlength=8)
+
+        self.__writer.blankline()
+        self.__writer.blankline()
+        self.__writer.popJustify()
+
+
+
     def writeText(self, tome):
 
         ostream.write("\n"*3)