def open_file(self, filename, revert=False): """This method reads a file contents and inserts the text read into the text buffer. Several things are done while the file is read: Tags are applied according to the type of place, the previous choices are also read and, if any are found, they are applied to the tags found, so that progress can be halted and resumed in further sessions. An Annotator object is created (or retrieved, in case of a file that is simply being revisited in this session), which will hold the annotations of the user. """ # Store the name of the file currently opened self.current_filename = filename # Create or retrieve the Annotator and TextBuffer objects assigned to this # file. If we are asked to revert, then do not run this block if filename in self.results and not revert: # We have already seen this file, so a Annotator and a TextBuffer # objects were already constructed for it self.current_result = self.results[filename] self.current_buffer = self.current_result.buffer # When reusing these objects, we don't need to open the file again, but # simply to switch the text buffer associated to the text view. To do # this, we run the post_open_file() method, that also takes care of the # rest of the window. We don't need the pre_open_file() method because the # progress bar will never be needed. self.post_open_file() # No further processing needed return # Do not change the modified flag for this file self.backend = True # Create an empty TextBuffer to hold the text self.current_buffer = self.new_buffer() # If we are not reverting, then try to open the .ann file. if not revert: # Even if we are seeing this file for the first time, choices may already # have been made for it and saved in the disk. In that case, retrieve the # Annotator object from the file on disk. ann_filename = ANNOTATOR_TEMPLATE % clean_filename(filename) try: fh = self.get_ann_file(ann_filename) except IOError: # The file does not exist or is unreadable, so we will not use it pass else: # The file was successfully opened. Give the file descriptor to the method # that creates a new instance of the Annotator object with the information # read from the file. self.current_result = Annotator.from_saved(fh, self.current_buffer, self.current_filename) self.results[filename] = self.current_result # As above, no further processing of the file is needed; just user # interface stuff self.post_open_file() # Further changes are user-made, so they must be processed self.backend = False return # Start the Annotator object as an empty instance self.results[filename] = self.current_result = \ Annotator(self.current_buffer, self.current_filename) # Prepare for the opening process. self.pre_open_file() # Get the contents of the file as nodes f = self.get_input_file(filename) nodes = xml_utils.extract_nodes(f) # Record the number of places n_places = sum(1 for i in nodes if i[1] != "text") place_index = 0 for node in nodes: # node comes from the xml_utils.extract_nodes() function, which returns # several tuples. Each tuple describes a string of data in the file: # text, explicit places (with GeoNetID, ...) or implicit places text, type = node[0], node[1] # Types are either "text", "explicit" or "implicit", with everything # except "text" signaling a place tag is_place = type != "text" if is_place: # Store the original name found on the file original_text = text # The position of the current cursor is the place this piece of text # will be inserted on. We create a mark (whose position remains fixed # relative to its surroundings) because the rest of the text may change. # The mark is created with left gravity because more text will be added # by the method, but it must change to right_gravity later on, so that # newly added text does not get inserted in the name of the place. start_iter = self.get_cursor_iter() start_mark = self.current_buffer.create_mark(None, start_iter, True) # We want to slightly change the visible text for implicit places if type == "implicit": text = "(" + text + ARROW + ")" # Insert the text in the current position of the cursor self.current_buffer.insert_at_cursor(text) # When the node is a place, there are other things that must be done if is_place: # Put a mark on the end of the text, to signal the end of the place # name. This mark should have left gravity and remain so, because text # added after it must not modify the position of the mark in relative to # the place. end_iter = self.get_cursor_iter() end_mark = self.current_buffer.create_mark(None, end_iter, True) # As explained above, we need to recreate the start_mark with right # gravity start_iter = self.current_buffer.get_iter_at_mark(start_mark) start_mark = self.current_buffer.create_mark(None, start_iter, False) # Now we need to retrieve from the database more information about the # place. if type == "explicit": # node[2] contains triples with domain (physical or administrative), # GeoNet ID and type of location respectively possibilities = [(int(i[1]), i[2]) for i in node[2]] elif type == "implicit": # When dealing with implicit places, we only have the name. Retrieve # the possible GeoNet IDs from the database possibilities = self.find_by_name(node[0]) # We also want the municipality name of the place to be present in the # possibilities list possibilities = [(i, j, self.find_municipality(i)) for i, j in possibilities] # We now add all the information to the self.current_result object self.current_result.add(original_text, start_mark, end_mark, type, possibilities) # Increase the index of the places and update the progress bar showing # how much of the file has been gathered and processed place_index += 1 self.update_progress_bar(place_index, n_places) # Format the text to give cues about each place's status self.current_result.format_buffer() # After opening the file, several operations must be performed self.post_open_file() # Further changes are user-made, so they must be processed self.backend = False