Write text of editor to a file.

        Args:
            index: self.data index to save.  If None, defaults to
                currentIndex().
            force: Force save regardless of file state.

        Returns:
            True upon successful save or when file doesn't need to be saved.
            False if save failed.

        If the text isn't modified and it's not newly created, then the save
        is aborted.  If the file hasn't been saved before, then save_as()
        is invoked.  Otherwise, the file is written using the file name
        currently in self.data.  This function doesn't change the file name.

def save(self, index=None, force=False):
        """Write text of editor to a file.

        Args:
            index: self.data index to save.  If None, defaults to
                currentIndex().
            force: Force save regardless of file state.

        Returns:
            True upon successful save or when file doesn't need to be saved.
            False if save failed.

        If the text isn't modified and it's not newly created, then the save
        is aborted.  If the file hasn't been saved before, then save_as()
        is invoked.  Otherwise, the file is written using the file name
        currently in self.data.  This function doesn't change the file name.
        """
        if index is None:
            # Save the currently edited file
            if not self.get_stack_count():
                return
            index = self.get_stack_index()

        finfo = self.data[index]
        if not (finfo.editor.document().isModified() or
                finfo.newly_created) and not force:
            return True
        if not osp.isfile(finfo.filename) and not force:
            # File has not been saved yet
            return self.save_as(index=index)
        if self.always_remove_trailing_spaces:
            self.remove_trailing_spaces(index)
        if self.convert_eol_on_save:
            # hack to account for the fact that the config file saves
            # CR/LF/CRLF while set_os_eol_chars wants the os.name value.
            osname_lookup = {'LF': 'posix', 'CRLF': 'nt', 'CR': 'mac'}
            osname = osname_lookup[self.convert_eol_on_save_to]
            self.set_os_eol_chars(osname=osname)
        try:
            self._write_to_file(finfo, finfo.filename)
            self.autosave.remove_autosave_file(finfo)
            finfo.newly_created = False
            self.encoding_changed.emit(finfo.encoding)
            finfo.lastmodified = QFileInfo(finfo.filename).lastModified()

            # We pass self object ID as a QString, because otherwise it would
            # depend on the platform: long for 64bit, int for 32bit. Replacing
            # by long all the time is not working on some 32bit platforms
            # (see Issue 1094, Issue 1098)
            # The filename is passed instead of an index in case the tabs
            # have been rearranged (see issue 5703).
            self.file_saved.emit(str(id(self)),
                                 finfo.filename, finfo.filename)

            finfo.editor.document().setModified(False)
            finfo.editor.document().changed_since_autosave = False
            self.modification_changed(index=index)
            self.analyze_script(index)

            #XXX CodeEditor-only: re-scan the whole text to rebuild outline
            # explorer data from scratch (could be optimized because
            # rehighlighting text means searching for all syntax coloring
            # patterns instead of only searching for class/def patterns which
            # would be sufficient for outline explorer data.
            finfo.editor.rehighlight()

            self._refresh_outlineexplorer(index)

            finfo.editor.notify_save()
            return True
        except EnvironmentError as error:
            self.msgbox = QMessageBox(
                    QMessageBox.Critical,
                    _("Save Error"),
                    _("<b>Unable to save file '%s'</b>"
                      "<br><br>Error message:<br>%s"
                      ) % (osp.basename(finfo.filename),
                                        str(error)),
                    parent=self)
            self.msgbox.exec_()
            return False