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