######################################################################### # # # # # copyright 2002 Paul Henry Tremblay # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # # General Public License for more details. # # # # # ######################################################################### import sys, os, re from ebook_converter.ebooks.rtf2xml import copy from ebook_converter.ptempfile import better_mktemp from . import open_for_read, open_for_write class MakeLists: """ Form lists. Use RTF's own formatting to determine if a paragraph definition is part of a list. Use indents to determine items and how lists are nested. """ def __init__(self, in_file, bug_handler, headings_to_sections, list_of_lists, copy=None, run_level=1, no_headings_as_list=1, write_list_info=0, ): """ Required: 'file' Optional: 'copy'-- whether to make a copy of result for debugging 'temp_dir' --where to output temporary results (default is directory from which the script is run.) Returns: nothing """ self.__file = in_file self.__bug_handler = bug_handler self.__run_level = run_level self.__no_headings_as_list = no_headings_as_list self.__headings_to_sections = headings_to_sections self.__copy = copy self.__write_to = better_mktemp() self.__list_of_lists = list_of_lists self.__write_list_info = write_list_info def __initiate_values(self): """ Required: Nothing Return: Nothing Logic: The self.__end_list is a list of tokens that will force a list to end. Likewise, the self.__end_lines is a list of lines that forces a list to end. """ self.__state = "default" self.__left_indent = 0 self.__list_type = 'not-defined' self.__pard_def = "" self.__all_lists = [] self.__level = 0 self.__list_chunk = '' self.__state_dict={ 'default' : self.__default_func, 'in_pard' : self.__in_pard_func, 'after_pard' : self.__after_pard_func, } self.__headings = [ 'heading 1', 'heading 2', 'heading 3', 'heading 4', 'heading 5', 'heading 6', 'heading 7', 'heading 8', 'heading 9' ] self.__allow_levels = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] self.__style_name = '' self.__end_list = [ 'mi(\d+)') self.__lv_regex = re.compile(r'\(\d+)') self.__found_appt = 0 self.__line_num = 0 def __in_pard_func(self, line): """ Required: line -- the line of current text. Return: Nothing Logic: You are in a list, but in the middle of a paragraph definition. Don't do anything until you find the end of the paragraph definition. """ if self.__token_info == 'mi last_list_indent: self.__write_obj.write(self.__list_chunk) self.__write_start_list(id) else: self.__write_end_item() self.__write_obj.write(self.__list_chunk) self.__write_start_item() self.__list_chunk = '' def __close_lists(self): """ Required: Nothing Return: Nothing Logic: Reverse the list of dictionaries. Iterate through the list and get the indent for each list. If the current indent is less than or equal to the indent in the dictionary, close that level. Keep track of how many levels you close. Reduce the list by that many levels. Reverse the list again. """ if self.__line_num < 25 and self.__found_appt: sys.stderr.write('in closing out lists\n') sys.stderr.write('current_indent is "%s"\n' % self.__left_indent) current_indent = self.__left_indent self.__all_lists.reverse() num_levels_closed = 0 for the_dict in self.__all_lists: list_indent = the_dict.get('left-indent') if self.__line_num < 25 and self.__found_appt: sys.stderr.write('last indent is "%s"' % list_indent) if current_indent <= list_indent: self.__write_end_item() self.__write_end_list() num_levels_closed += 1 self.__all_lists = self.__all_lists[num_levels_closed:] self.__all_lists.reverse() def __write_end_list(self): """ Required: Nothing Return: Nothing Logic: Write the end of a list. """ self.__write_obj.write('mi%s%s' % (id, lev_num) ) list_dict = {} if self.__list_of_lists: # older RTF won't generate a list_of_lists index_of_list = self.__get_index_of_list(id) if index_of_list is not None: # found a matching id curlist = self.__list_of_lists[index_of_list] list_dict = curlist[0] level = int(self.__level) + 1 if level >= len(curlist): level = len(curlist) - 1 level_dict = curlist[level][0] list_type = level_dict.get('numbering-type') if list_type == 'bullet': list_type = 'unordered' else: list_type = 'ordered' self.__write_obj.write( '%s' % (list_type)) else: # no matching id self.__write_obj.write( '%s' % (self.__list_type)) else: # older RTF self.__write_obj.write( '%s' % (self.__list_type)) # if you want to dump all the info to the list, rather than # keeping it in the table above, change self.__write_list_info # to true. if self.__list_of_lists and self.__write_list_info and list_dict: not_allow = ['list-id',] the_keys_list = list_dict.keys() for the_key in the_keys_list: if the_key in not_allow: continue self.__write_obj.write('<%s>%s' % (the_key, list_dict[the_key])) the_keys_level = level_dict.keys() for the_key in the_keys_level: self.__write_obj.write('<%s>%s' % (the_key, level_dict[the_key])) self.__write_obj.write('\n') self.__write_obj.write( 'mi 0: sys.stderr.write('Module is make_lists.py\n' 'Method is __get_index_of_list\n' 'The main list does not appear to have a matching id for %s \n' % (id) ) # sys.stderr.write(repr(self.__list_of_lists)) # if self.__run_level > 3: # msg = 'level is "%s"\n' % self.__run_level # self.__bug_handler def __write_start_item(self): self.__write_obj.write('mi