'Fix indentation (Python only, no text selection)
forward=True: fix indent only if text is not enough indented
(otherwise force indent)
forward=False: fix indent only if text is too much indented
(otherwise force unindent)
Returns True if indent needed to be fixed'

def fix_indent_smart(self, forward=True, comment_or_string=False):

    cursor = self.textCursor()
    block_nb = cursor.blockNumber()
    diff_paren = 0
    diff_brack = 0
    diff_curly = 0
    add_indent = False
    prevline = None
    prevtext = ''
    for prevline in range((block_nb - 1), (-1), (-1)):
        cursor.movePosition(QTextCursor.PreviousBlock)
        prevtext = to_text_string(cursor.block().text()).rstrip()
        inline_comment = prevtext.find('#')
        if (inline_comment != (-1)):
            prevtext = prevtext[:inline_comment]
        if ((self.is_python_like() and (not prevtext.strip().startswith('#')) and prevtext) or prevtext):
            if ((not ('return' in prevtext.strip().split()[:1])) and (prevtext.strip().endswith(')') or prevtext.strip().endswith(']') or prevtext.strip().endswith('}'))):
                comment_or_string = True
            elif (prevtext.strip().endswith(':') and self.is_python_like()):
                add_indent = True
                comment_or_string = True
            if (prevtext.count(')') > prevtext.count('(')):
                diff_paren = (prevtext.count(')') - prevtext.count('('))
            elif (prevtext.count(']') > prevtext.count('[')):
                diff_brack = (prevtext.count(']') - prevtext.count('['))
            elif (prevtext.count('}') > prevtext.count('{')):
                diff_curly = (prevtext.count('}') - prevtext.count('{'))
            elif (diff_paren or diff_brack or diff_curly):
                diff_paren += (prevtext.count(')') - prevtext.count('('))
                diff_brack += (prevtext.count(']') - prevtext.count('['))
                diff_curly += (prevtext.count('}') - prevtext.count('{'))
                if (not (diff_paren or diff_brack or diff_curly)):
                    break
            else:
                break
    if prevline:
        correct_indent = self.get_block_indentation(prevline)
    else:
        correct_indent = 0
    indent = self.get_block_indentation(block_nb)
    if add_indent:
        if (self.indent_chars == ' DCTB '):
            correct_indent += self.tab_stop_width_spaces
        else:
            correct_indent += len(self.indent_chars)
    if (not comment_or_string):
        if (prevtext.endswith(':') and self.is_python_like()):
            if (self.indent_chars == ' DCTB '):
                correct_indent += self.tab_stop_width_spaces
            else:
                correct_indent += len(self.indent_chars)
        elif (self.is_python_like() and (prevtext.endswith('continue') or prevtext.endswith('break') or prevtext.endswith('pass') or (('return' in prevtext.strip().split()[:1]) and (len(re.split('\\(|\\{|\\[', prevtext)) == len(re.split('\\)|\\}|\\]', prevtext)))))):
            if (self.indent_chars == ' DCTB '):
                correct_indent -= self.tab_stop_width_spaces
            else:
                correct_indent -= len(self.indent_chars)
        elif (len(re.split('\\(|\\{|\\[', prevtext)) > 1):
            stack = ['dummy']
            deactivate = None
            for c in prevtext:
                if (deactivate is not None):
                    if (c == deactivate):
                        deactivate = None
                elif (c in ["'", '"']):
                    deactivate = c
                elif (c in ['(', '[', '{']):
                    stack.append(c)
                elif ((c == ')') and (stack[(-1)] == '(')):
                    stack.pop()
                elif ((c == ']') and (stack[(-1)] == '[')):
                    stack.pop()
                elif ((c == '}') and (stack[(-1)] == '{')):
                    stack.pop()
            if (len(stack) == 1):
                pass
            elif ((re.search('[\\(|\\{|\\[]\\s*$', prevtext) is not None) and (((self.indent_chars == ' DCTB ') and ((self.tab_stop_width_spaces * 2) < len(prevtext))) or (self.indent_chars.startswith('    ') and ((len(self.indent_chars) * 2) < len(prevtext))))):
                if (self.indent_chars == ' DCTB '):
                    correct_indent += (self.tab_stop_width_spaces * 2)
                else:
                    correct_indent += (len(self.indent_chars) * 2)
            else:
                rlmap = {')': '(', ']': '[', '}': '{'}
                for par in rlmap:
                    i_right = prevtext.rfind(par)
                    if (i_right != (-1)):
                        prevtext = prevtext[:i_right]
                        for _i in range(len(prevtext.split(par))):
                            i_left = prevtext.rfind(rlmap[par])
                            if (i_left != (-1)):
                                prevtext = prevtext[:i_left]
                            else:
                                break
                else:
                    if prevtext.strip():
                        if (len(re.split('\\(|\\{|\\[', prevtext)) > 1):
                            prevexpr = re.split('\\(|\\{|\\[', prevtext)[(-1)]
                            correct_indent = (len(prevtext) - len(prevexpr))
                        else:
                            correct_indent = len(prevtext)
    if ((not (diff_paren or diff_brack or diff_curly)) and (not prevtext.endswith(':')) and prevline):
        cur_indent = self.get_block_indentation((block_nb - 1))
        is_blank = (not self.get_text_line((block_nb - 1)).strip())
        prevline_indent = self.get_block_indentation(prevline)
        trailing_text = self.get_text_line(block_nb).strip()
        if ((cur_indent < prevline_indent) and (trailing_text or is_blank)):
            if ((cur_indent % len(self.indent_chars)) == 0):
                correct_indent = cur_indent
            else:
                correct_indent = (cur_indent + (len(self.indent_chars) - (cur_indent % len(self.indent_chars))))
    if ((forward and (indent >= correct_indent)) or ((not forward) and (indent <= correct_indent))):
        return False
    if (correct_indent >= 0):
        cursor = self.textCursor()
        cursor.movePosition(QTextCursor.StartOfBlock)
        if (self.indent_chars == ' DCTB '):
            indent = (indent // self.tab_stop_width_spaces)
        cursor.setPosition((cursor.position() + indent), QTextCursor.KeepAnchor)
        cursor.removeSelectedText()
        if (self.indent_chars == ' DCTB '):
            indent_text = ((' DCTB ' * (correct_indent // self.tab_stop_width_spaces)) + ('    ' * (correct_indent % self.tab_stop_width_spaces)))
        else:
            indent_text = ('    ' * correct_indent)
        cursor.insertText(indent_text)
        return True
