Пример #1
0
    def get_widget_text_pos_from_kv(self, widget, parent=None,
                                    path_to_widget=None):
        '''To get start and end pos of widget's rule in kv text
        :param path_to_widget: array with widget path
        :param parent: parent of widget
        :param widget: widget to find the kv text
        '''
        if not path_to_widget:
            path_to_widget = self.get_widget_path(widget)
            path_to_widget.reverse()

        # Go to widget's rule's line and determines all its rule's
        # and it's child if any. Then delete them
        text = re.sub(r'#.+', '', self.text)
        lines = text.splitlines()
        total_lines = len(lines)
        root_lineno = 0
        root_name = self.playground.root_name
        for lineno, line in enumerate(lines):
            pos = line.find(root_name)
            if pos != -1 and get_indentation(line) == 0:
                root_lineno = lineno
                break

        widget_lineno = self._find_widget_place(path_to_widget, lines,
                                                total_lines, root_lineno + 1)
        widget_line = lines[widget_lineno]
        indent = len(widget_line) - len(widget_line.lstrip())
        lineno = widget_lineno
        _indent = indent + 1
        line = widget_line
        while line.strip() == '' or _indent > indent:
            lineno += 1
            if lineno >= total_lines:
                break
            line = lines[lineno]
            _indent = len(line) - len(line.lstrip())

        delete_until_line = lineno - 1
        line = lines[delete_until_line]
        while line.strip() == '':
            delete_until_line -= 1
            line = lines[delete_until_line]

        widget_line_pos = get_line_start_pos(self.text, widget_lineno)
        delete_until_line_pos = -1
        if delete_until_line == total_lines - 1:
            delete_until_line_pos = len(self.text)
        else:
            delete_until_line_pos = get_line_end_pos(self.text,
                                                     delete_until_line)

        self._reload = False

        return widget_line_pos, delete_until_line_pos
Пример #2
0
    def set_property_value(self, widget, prop, value, proptype):
        '''To find and change the value of property of widget rule in text
        '''

        # Do not add property if value is empty and
        # property is not a string property

        self._reload = False
        if not isinstance(widget.properties()[prop], StringProperty) and\
                value == '':
            return

        path_to_widget = self.get_widget_path(widget)
        path_to_widget.reverse()

        # Go to the line where widget is declared
        lines = re.sub(r'#.+', '', self.text.rstrip()).splitlines()
        total_lines = len(lines)

        root_name = self.playground.root_name
        total_lines = len(lines)
        root_lineno = 0
        for lineno, line in enumerate(lines):
            pos = line.find(root_name)
            if pos != -1 and get_indentation(line) == 0:
                root_lineno = lineno
                break

        widget_lineno = self._find_widget_place(path_to_widget, lines,
                                                total_lines, root_lineno + 1)
        widget_line = lines[widget_lineno]
        if not widget_line.strip():
            return

        indent = get_indentation(widget_line)
        prop_found = False

        if ':' not in widget_line:
            # If cannot find ':' then insert it
            self.cursor = (len(lines[widget_lineno]), widget_lineno)
            lines[widget_lineno] += ':'
            self.insert_text(':')

        else:
            # Else find if property has already been declared with a value
            lineno = widget_lineno + 1
            # But if widget line is the last line in the text
            if lineno < total_lines:
                line = lines[lineno]
                _indent = get_indentation(line)
                colon_pos = -1
                while lineno < total_lines and (line.strip() == '' or
                                                _indent > indent):
                    line = lines[lineno]
                    _indent = get_indentation(line)
                    if line.strip() != '':
                        colon_pos = line.find(':')
                        if colon_pos == -1:
                            break

                        if colon_pos == len(line.rstrip()) - 1:
                            break

                        if prop == line[:colon_pos].strip():
                            prop_found = True
                            break

                    lineno += 1

        if prop_found:
            # if property found then change its value
            _pos_prop_value = get_line_start_pos(self.text, lineno) + \
                colon_pos + 2
            if lineno == total_lines - 1:
                _line_end_pos = len(self.text)
            else:
                _line_end_pos = get_line_end_pos(self.text, lineno)

            if proptype == 'StringProperty' or \
                    (proptype == 'OptionProperty' and
                         not isinstance(value, list)):
                value = "'{}'".format(value.replace("'", "\\'"))

            self.text = self.text[:_pos_prop_value] + ' ' + str(value) + \
                self.text[_line_end_pos:]

            self.cursor = (0, lineno)

        else:
            # if not found then add property after the widgets line
            _line_start_pos = get_line_start_pos(self.text, widget_lineno)
            _line_end_pos = get_line_end_pos(self.text, widget_lineno)
            if proptype == 'StringProperty' or \
                    (proptype == 'OptionProperty' and
                         not isinstance(value, list)):
                value = "'{}'".format(value.replace("'", "\\'"))

            indent_str = '\n'
            for i in range(indent + 4):
                indent_str += ' '

            self.cursor = (len(lines[widget_lineno]), widget_lineno)
            self.insert_text(indent_str + prop + ': ' + str(value))
Пример #3
0
    def set_event_handler(self, widget, prop, value):
        self._reload = False

        path_to_widget = self.get_widget_path(widget)
        path_to_widget.reverse()

        # Go to the line where widget is declared
        lines = re.sub(r'#.+', '', self.text).splitlines()
        total_lines = len(lines)

        root_name = self.playground.root_name
        total_lines = len(lines)
        root_lineno = 0
        for lineno, line in enumerate(lines):
            pos = line.find(root_name)
            if pos != -1 and get_indentation(line) == 0:
                root_lineno = lineno
                break

        widget_lineno = self._find_widget_place(path_to_widget, lines,
                                                total_lines, root_lineno + 1)

        widget_line = lines[widget_lineno]
        indent = get_indentation(widget_line)
        prop_found = False

        if not widget_line.strip():
            return

        if ':' not in widget_line:
            # If cannot find ':' then insert it
            self.cursor = (len(lines[widget_lineno]), widget_lineno)
            lines[widget_lineno] += ':'
            self.insert_text(':')

        else:
            # Else find if property has already been declared with a value
            lineno = widget_lineno + 1
            # But if widget line is the last line in the text
            if lineno < total_lines:
                line = lines[lineno]
                _indent = get_indentation(line)
                colon_pos = -1
                while lineno < total_lines and (line.strip() == '' or
                                                _indent > indent):
                    line = lines[lineno]
                    _indent = get_indentation(line)
                    if line.strip() != '':
                        colon_pos = line.find(':')
                        if colon_pos == -1:
                            break

                        if colon_pos == len(line.rstrip()) - 1:
                            break

                        if prop == line[:colon_pos].strip():
                            prop_found = True
                            break

                    lineno += 1

        if prop_found:
            if lineno == total_lines - 1:
                _line_end_pos = len(self.text)
            else:
                _line_end_pos = get_line_end_pos(self.text, lineno)

            if value != '':
                # if property found then change its value
                _pos_prop_value = get_line_start_pos(self.text, lineno) + \
                    colon_pos + 2
                self.text = self.text[:_pos_prop_value] + ' ' + value + \
                    self.text[_line_end_pos:]

                self.cursor = (0, lineno)

            else:
                _line_start_pos = get_line_start_pos(self.text, widget_lineno)
                self.text = \
                    self.text[:get_line_start_pos(self.text, lineno)] + \
                    self.text[_line_end_pos:]

        elif value != '':
            # if not found then add property after the widgets line
            _line_end_pos = get_line_end_pos(self.text, widget_lineno)

            indent_str = '\n'
            for i in range(indent + 4):
                indent_str += ' '

            self.cursor = (len(lines[widget_lineno]), widget_lineno)
            self.insert_text(indent_str + prop + ': ' + str(value))
Пример #4
0
    def get_property_value(self, widget, prop):
        self._reload = False
        if prop[:3] != 'on_' and \
                not isinstance(widget.properties()[prop], StringProperty) and\
                value == '':
            return

        path_to_widget = self.get_widget_path(widget)
        path_to_widget.reverse()

        # Go to the line where widget is declared
        lines = re.sub(r'#.+', '', self.text).splitlines()
        total_lines = len(lines)

        root_name = self.playground.root_name
        total_lines = len(lines)
        root_lineno = 0
        for lineno, line in enumerate(lines):
            pos = line.find(root_name)
            if pos != -1 and get_indentation(line) == 0:
                root_lineno = lineno
                break

        widget_lineno = self._find_widget_place(path_to_widget, lines,
                                                total_lines, root_lineno + 1)
        widget_line = lines[widget_lineno]
        indent = get_indentation(widget_line)
        prop_found = False

        # Else find if property has already been declared with a value
        lineno = widget_lineno + 1
        # But if widget line is the last line in the text
        if lineno < total_lines:
            line = lines[lineno]
            _indent = get_indentation(line)
            colon_pos = -1
            while lineno < total_lines and (line.strip() == '' or
                                            _indent > indent):
                line = lines[lineno]
                _indent = get_indentation(line)
                if line.strip() != '':
                    colon_pos = line.find(':')
                    if colon_pos == -1:
                        break

                    if colon_pos == len(line.rstrip()) - 1:
                        break

                    if prop == line[:colon_pos].strip():
                        prop_found = True
                        break

                lineno += 1

        if prop_found:
            # if property found then change its value
            _pos_prop_value = get_line_start_pos(self.text, lineno) + \
                colon_pos + 2
            if lineno == total_lines - 1:
                _line_end_pos = len(self.text)
            else:
                _line_end_pos = get_line_end_pos(self.text, lineno)

            return self.text[_pos_prop_value:_line_end_pos]

        return ''
Пример #5
0
    def save_project(self, proj_dir=''):
        '''To save project to proj_dir. If proj_dir is not empty string then
           project is saved to a new directory other than its
           current directory and otherwise it is saved to the
           current directory.
        '''

        # To stop ProjectWatcher from emitting event when project is saved
        self.proj_watcher.allow_event_dispatch = False
        proj_dir_changed = False

        if self.new_project:
            # Create dir and copy new_proj.kv and new_proj.py to new directory
            if not os.path.exists(proj_dir):
                os.mkdir(proj_dir)

            kivy_designer_dir = get_kivy_designer_dir()
            kivy_designer_new_proj_dir = os.path.join(kivy_designer_dir,
                                                      "new_proj")
            for _file in os.listdir(kivy_designer_new_proj_dir):
                old_file = os.path.join(kivy_designer_new_proj_dir, _file)
                new_file = os.path.join(proj_dir, _file)
                if os.path.isdir(old_file):
                    shutil.copytree(old_file, new_file)
                else:
                    shutil.copy(old_file, new_file)

            self.file_list = self._get_file_list(proj_dir)

            new_kv_file = os.path.join(proj_dir, "main.kv")
            new_py_file = os.path.join(proj_dir, "main.py")

            self.proj_dir = proj_dir
            if self.root_rule:
                self.root_rule.kv_file = new_kv_file
                self.root_rule.py_file = new_py_file

            if self.class_rules:
                self.class_rules[0].py_file = new_py_file
                self.class_rules[0].kv_file = new_kv_file

            self.new_project = False

        else:
            if proj_dir != '' and proj_dir != self.proj_dir:
                proj_dir_changed = True

                # Remove previous project directories from sys.path
                for _dir in self._dir_list:
                    try:
                        sys.path.remove(_dir)
                    except:
                        pass

                # if proj_dir and self.proj_dir differs then user wants to save
                # an already opened project to somewhere else
                # Copy all the files
                if not os.path.exists(proj_dir):
                    os.mkdir(proj_dir)

                for _file in os.listdir(self.proj_dir):
                    old_file = os.path.join(self.proj_dir, _file)
                    new_file = os.path.join(proj_dir, _file)
                    if os.path.isdir(old_file):
                        shutil.copytree(old_file, new_file)
                    else:
                        shutil.copy(old_file, new_file)

                self.file_list = self._get_file_list(proj_dir)

                # Change the path of all files in the class rules,
                # root rule and app
                relative_path = self._app_file[
                    self._app_file.find(self.proj_dir):]
                self._app_file = os.path.join(proj_dir, relative_path)

                f = open(self._app_file, 'r')
                s = f.read()
                f.close()

                self._import_module(s, self._app_file,
                                    _fromlist=[self._app_class])

                for _rule in self.class_rules:
                    relative_path = _rule.kv_file[
                        _rule.kv_file.find(self.proj_dir):]
                    _rule.kv_file = os.path.join(proj_dir, relative_path)

                    relative_path = _rule.file[_rule.file.find(self.proj_dir):]
                    _rule.file = os.path.join(proj_dir, relative_path)

                    f = open(_rule.file, 'r')
                    s = f.read()
                    f.close()
                    self._import_module(s, _rule.file, _fromlist=[_rule.name])

                relative_path = self.root_rule.kv_file[
                    self.root_rule.kv_file.find(self.proj_dir):]
                self.root_rule.kv_file = os.path.join(proj_dir, relative_path)

                relative_path = self.root_rule.file[
                    self.root_rule.file.find(self.proj_dir):]
                self.root_rule.file = os.path.join(proj_dir, relative_path)

                self.proj_dir = proj_dir

        # For custom widgets copy py and kv file to project directory
        for widget in self.custom_widgets:
            custom_kv = os.path.join(self.proj_dir,
                                     os.path.basename(widget.kv_file))
            if not os.path.exists(custom_kv):
                shutil.copy(widget.kv_file, custom_kv)

            custom_py = os.path.join(self.proj_dir,
                                     os.path.basename(widget.py_file))
            if not os.path.exists(custom_py):
                shutil.copy(widget.py_file, custom_py)

        # Saving all opened py files and also reimport them
        for _code_input in self.tab_pannel.list_py_code_inputs:
            path = os.path.join(self.proj_dir, _code_input.rel_file_path)
            f = open(path, 'w')
            f.write(_code_input.text)
            f.close()
            _from_list = []
            for rule in self.class_rules:
                if rule.file == path:
                    _from_list.append(rule.file)

            if not self.is_root_a_class_rule():
                if self.root_rule.file == path:
                    _from_list.append(self.root_rule.name)

            # Ignore all types that are not .py
            if path.endswith(".py"):
                self._import_module(_code_input.text, path,
                                    _fromlist=_from_list)

        # Save all class rules
        text = self.kv_code_input.text
        for _rule in self.class_rules:
            # Get the kv text from KVLangArea and write it to class rule's file
            f = open(_rule.kv_file, 'r')
            _file_str = f.read()
            f.close()

            old_str = self.get_class_str_from_text(_rule.name, _file_str)
            new_str = self.get_class_str_from_text(_rule.name, text)

            f = open(_rule.kv_file, 'w')
            _file_str = _file_str.replace(old_str, new_str)
            f.write(_file_str)
            f.close()

        # If root widget is not changed
        if self._root_rule.name == self.root_rule.name:
            # Save root widget's rule
            is_root_class = False
            for _rule in self.class_rules:
                if _rule.name == self.root_rule.name:
                    is_root_class = True
                    break

            if not is_root_class:
                f = open(self.root_rule.kv_file, 'r')
                _file_str = f.read()
                f.close()

                old_str = self.get_class_str_from_text(self.root_rule.name,
                                                       _file_str,
                                                       is_class=False)
                new_str = self.get_class_str_from_text(self.root_rule.name,
                                                       text, is_class=False)

                f = open(self.root_rule.kv_file, 'w')
                _file_str = _file_str.replace(old_str, new_str)
                f.write(_file_str)
                f.close()

        else:
            # If root widget is changed
            # Root Widget changes, there can be these cases:
            root_name = self.root_rule.name
            f = open(self._app_file, 'r')
            file_str = f.read()
            f.close()
            self._root_rule = self.root_rule

            if self.is_root_a_class_rule() and self._app_file:
                # Root Widget's class rule is a custom class
                # and its rule is class rule. So, it already have been saved
                # the string of App's build() function will be changed to
                # return new root widget's class

                if self._app_class != 'runTouchApp':
                    s = re.search(r'class\s+%s.+:' % self._app_class, file_str)
                    if s:
                        build_searchiter = None
                        for searchiter in re.finditer(
                                r'[ \ \t]+def\s+build\s*\(\s*self.+\s*:',
                                file_str):
                            if searchiter.start() > s.start():
                                build_searchiter = searchiter
                                break

                        if build_searchiter:
                            indent = get_indentation(build_searchiter.group(0))
                            file_str = file_str[:build_searchiter.end()] +\
                                '\n' + get_indent_str(2 * indent) + "return " +\
                                root_name + "()\n" + \
                                file_str[build_searchiter.end():]

                        else:
                            file_str = file_str[:s.end()] + \
                                "\n    def build(self):\n        return " + \
                                root_name + '()\n' + file_str[s.end():]

                else:
                    file_str = re.sub(r'runTouchApp\s*\(.+\)',
                                      'runTouchApp(' + root_name + '())',
                                      file_str)

                f = open(self._app_file, 'w')
                f.write(file_str)
                f.close()

            else:
                # Root Widget's rule is not a custom class
                # and its rule is root rule
                # Its kv_file should be of App's class name
                # and App's build() function should be cleared
                if not self.root_rule.kv_file:
                    s = self._app_class.replace('App', '').lower()
                    root_file = None
                    for _file in self.kv_file_list:
                        if os.path.basename(_file).find(s) == 0:
                            self.root_rule.kv_file = _file
                            break

                f = open(self.root_rule.kv_file, 'r')
                _file_str = f.read()
                f.close()

                new_str = self.get_class_str_from_text(self.root_rule.name,
                                                       text, False)

                f = open(self.root_rule.kv_file, 'a')
                f.write(new_str)
                f.close()

                if self._app_class != 'runTouchApp':
                    s = re.search(r'class\s+%s.+:' % self._app_class, file_str)
                    if s:
                        build_searchiter = None
                        for searchiter in re.finditer(
                                r'[ \ \t]+def\s+build\s*\(\s*self.+\s*:',
                                file_str):
                            if searchiter.start() > s.start():
                                build_searchiter = searchiter
                                break

                        if build_searchiter:
                            lines = file_str.splitlines()
                            total_lines = len(lines)
                            indent = get_indentation(build_searchiter.group(0))

                            _line = 0
                            _line_pos = -1
                            _line_pos = file_str.find('\n', _line_pos + 1)
                            while _line_pos <= build_searchiter.start():
                                _line_pos = file_str.find('\n', _line_pos + 1)
                                _line += 1

                            _line += 1

                            while _line < total_lines:
                                if lines[_line].strip() != '' and\
                                        get_indentation(lines[_line]) <= \
                                        indent:
                                    break

                                _line += 1

                            _line -= 1
                            end = get_line_start_pos(file_str, _line)
                            start = build_searchiter.start()
                            file_str = file_str.replace(file_str[start:end],
                                                        '    pass')

                            f = open(self._app_file, 'w')
                            f.write(file_str)
                            f.close()

        # Allow Project Watcher to emit events
        Clock.schedule_once(self._allow_proj_watcher_dispatch, 1)
Пример #6
0
    def get_property_value(self, widget, prop):
        self._reload = False
        if prop[:3] != 'on_' and \
                not isinstance(widget.properties()[prop], StringProperty) and\
                value == '':
            return

        path_to_widget = self._get_widget_path(widget)
        path_to_widget.reverse()

        # Go to the line where widget is declared
        lines = re.sub(r'#.+', '', self.text).splitlines()
        total_lines = len(lines)

        root_name = self.project_loader.root_rule.name
        total_lines = len(lines)
        root_lineno = 0
        for lineno, line in enumerate(lines):
            pos = line.find(root_name)
            if pos != -1 and get_indentation(line) == 0:
                root_lineno = lineno
                break

        widget_lineno = self._find_widget_place(path_to_widget, lines,
                                                total_lines, root_lineno + 1)
        widget_line = lines[widget_lineno]
        indent = get_indentation(widget_line)
        prop_found = False

        # Else find if property has already been declared with a value
        lineno = widget_lineno + 1
        # But if widget line is the last line in the text
        if lineno < total_lines:
            line = lines[lineno]
            _indent = get_indentation(line)
            colon_pos = -1
            while lineno < total_lines and (line.strip() == ''
                                            or _indent > indent):
                line = lines[lineno]
                _indent = get_indentation(line)
                if line.strip() != '':
                    colon_pos = line.find(':')
                    if colon_pos == -1:
                        break

                    if colon_pos == len(line.rstrip()) - 1:
                        break

                    if prop == line[:colon_pos].strip():
                        prop_found = True
                        break

                lineno += 1

        if prop_found:
            # if property found then change its value
            _pos_prop_value = get_line_start_pos(self.text, lineno) + \
                colon_pos + 2
            if lineno == total_lines - 1:
                _line_end_pos = len(self.text)
            else:
                _line_end_pos = get_line_end_pos(self.text, lineno)

            return self.text[_pos_prop_value:_line_end_pos]

        return ""
Пример #7
0
    def set_property_value(self, widget, prop, value, proptype):
        '''To find and change the value of property of widget rule in text
        '''

        #Do not add property if value is empty and
        #property is not a string property

        self._reload = False
        if not isinstance(widget.properties()[prop], StringProperty) and\
                value == '':
            return

        path_to_widget = self._get_widget_path(widget)
        path_to_widget.reverse()

        #Go to the line where widget is declared
        lines = re.sub(r'#.+', '', self.text.rstrip()).splitlines()
        total_lines = len(lines)

        root_name = self.project_loader.root_rule.name
        total_lines = len(lines)
        root_lineno = 0
        for lineno, line in enumerate(lines):
            pos = line.find(root_name)
            if pos != -1 and get_indentation(line) == 0:
                root_lineno = lineno
                break

        widget_lineno = self._find_widget_place(path_to_widget, lines,
                                                total_lines, root_lineno + 1)
        widget_line = lines[widget_lineno]
        if not widget_line.strip():
            return

        indent = get_indentation(widget_line)
        prop_found = False

        if ':' not in widget_line:
            #If cannot find ':' then insert it
            self.cursor = (len(lines[widget_lineno]), widget_lineno)
            lines[widget_lineno] += ':'
            self.insert_text(':')

        else:
            #Else find if property has already been declared with a value
            lineno = widget_lineno + 1
            #But if widget line is the last line in the text
            if lineno < total_lines:
                line = lines[lineno]
                _indent = get_indentation(line)
                colon_pos = -1
                while lineno < total_lines and (line.strip() == ''
                                                or _indent > indent):
                    line = lines[lineno]
                    _indent = get_indentation(line)
                    if line.strip() != '':
                        colon_pos = line.find(':')
                        if colon_pos == -1:
                            break

                        if colon_pos == len(line.rstrip()) - 1:
                            break

                        if prop == line[:colon_pos].strip():
                            prop_found = True
                            break

                    lineno += 1

        if prop_found:
            #if property found then change its value
            _pos_prop_value = get_line_start_pos(self.text, lineno) + \
                colon_pos + 2
            if lineno == total_lines - 1:
                _line_end_pos = len(self.text)
            else:
                _line_end_pos = get_line_end_pos(self.text, lineno)

            if proptype == 'StringProperty':
                value = "'" + value + "'"

            self.text = self.text[:_pos_prop_value] + ' ' + str(value) + \
                self.text[_line_end_pos:]

            self.cursor = (0, lineno)

        else:
            #if not found then add property after the widgets line
            _line_start_pos = get_line_start_pos(self.text, widget_lineno)
            _line_end_pos = get_line_end_pos(self.text, widget_lineno)
            if proptype == 'StringProperty':
                value = "'" + value + "'"

            indent_str = '\n'
            for i in range(indent + 4):
                indent_str += ' '

            self.cursor = (len(lines[widget_lineno]), widget_lineno)
            self.insert_text(indent_str + prop + ': ' + str(value))
Пример #8
0
    def save_project(self, proj_dir=''):
        '''To save project to proj_dir. If proj_dir is not empty string then
           project is saved to a new directory other than its
           current directory and otherwise it is saved to the
           current directory.
        '''

        #To stop ProjectWatcher from emitting event when project is saved
        self.proj_watcher.allow_event_dispatch = False
        proj_dir_changed = False

        if self.new_project:
            #Create dir and copy new_proj.kv and new_proj.py to new directory
            if not os.path.exists(proj_dir):
                os.mkdir(proj_dir)

            kivy_designer_dir = get_kivy_designer_dir()
            kivy_designer_new_proj_dir = os.path.join(kivy_designer_dir,
                                                      "new_proj")
            for _file in os.listdir(kivy_designer_new_proj_dir):
                old_file = os.path.join(kivy_designer_new_proj_dir, _file)
                new_file = os.path.join(proj_dir, _file)
                if os.path.isdir(old_file):
                    shutil.copytree(old_file, new_file)
                else:
                    shutil.copy(old_file, new_file)

            self.file_list = self._get_file_list(proj_dir)

            new_kv_file = os.path.join(proj_dir, "main.kv")
            new_py_file = os.path.join(proj_dir, "main.py")

            self.proj_dir = proj_dir
            if self.root_rule:
                self.root_rule.kv_file = new_kv_file
                self.root_rule.py_file = new_py_file

            if self.class_rules:
                self.class_rules[0].py_file = new_py_file
                self.class_rules[0].kv_file = new_kv_file

            self.new_project = False

        else:
            if proj_dir != '' and proj_dir != self.proj_dir:
                proj_dir_changed = True

                #Remove previous project directories from sys.path
                for _dir in self._dir_list:
                    try:
                        sys.path.remove(_dir)
                    except:
                        pass

                #if proj_dir and self.proj_dir differs then user wants to save
                #an already opened project to somewhere else
                #Copy all the files
                if not os.path.exists(proj_dir):
                    os.mkdir(proj_dir)

                for _file in os.listdir(self.proj_dir):
                    old_file = os.path.join(self.proj_dir, _file)
                    new_file = os.path.join(proj_dir, _file)
                    if os.path.isdir(old_file):
                        shutil.copytree(old_file, new_file)
                    else:
                        shutil.copy(old_file, new_file)

                self.file_list = self._get_file_list(proj_dir)

                #Change the path of all files in the class rules,
                #root rule and app
                relative_path = self._app_file[
                    self._app_file.find(self.proj_dir):]
                self._app_file = os.path.join(proj_dir, relative_path)

                f = open(self._app_file, 'r')
                s = f.read()
                f.close()

                self._import_module(s, self._app_file,
                                    _fromlist=[self._app_class])

                for _rule in self.class_rules:
                    relative_path = _rule.kv_file[
                        _rule.kv_file.find(self.proj_dir):]
                    _rule.kv_file = os.path.join(proj_dir, relative_path)

                    relative_path = _rule.file[_rule.file.find(self.proj_dir):]
                    _rule.file = os.path.join(proj_dir, relative_path)

                    f = open(_rule.file, 'r')
                    s = f.read()
                    f.close()

                    self._import_module(s, _rule.file, _fromlist=[_rule.name])

                relative_path = self.root_rule.kv_file[
                    self.root_rule.kv_file.find(self.proj_dir):]
                self.root_rule.kv_file = os.path.join(proj_dir, relative_path)

                relative_path = self.root_rule.file[
                    self.root_rule.file.find(self.proj_dir):]
                self.root_rule.file = os.path.join(proj_dir, relative_path)

                self.proj_dir = proj_dir

        #For custom widgets copy py and kv file to project directory
        for widget in self.custom_widgets:
            custom_kv = os.path.join(self.proj_dir,
                                     os.path.basename(widget.kv_file))
            if not os.path.exists(custom_kv):
                shutil.copy(widget.kv_file, custom_kv)

            custom_py = os.path.join(self.proj_dir,
                                     os.path.basename(widget.py_file))
            if not os.path.exists(custom_py):
                shutil.copy(widget.py_file, custom_py)

        #Saving all opened py files and also reimport them
        for _code_input in self.tab_pannel.list_py_code_inputs:
            path = os.path.join(self.proj_dir, _code_input.rel_file_path)
            f = open(path, 'w')
            f.write(_code_input.text)
            f.close()
            _from_list = []
            for rule in self.class_rules:
                if rule.file == path:
                    _from_list.append(rule.file)

            if not self.is_root_a_class_rule():
                if self.root_rule.file == path:
                    _from_list.append(self.root_rule.name)

            self._import_module(_code_input.text, path, _fromlist=_from_list)

        #Save all class rules
        text = self.kv_code_input.text
        for _rule in self.class_rules:
            #Get the kv text from KVLangArea and write it to class rule's file
            f = open(_rule.kv_file, 'r')
            _file_str = f.read()
            f.close()

            old_str = self.get_class_str_from_text(_rule.name, _file_str)
            new_str = self.get_class_str_from_text(_rule.name, text)

            f = open(_rule.kv_file, 'w')
            _file_str = _file_str.replace(old_str, new_str)
            f.write(_file_str)
            f.close()

        #If root widget is not changed
        if self._root_rule.name == self.root_rule.name:
            #Save root widget's rule
            is_root_class = False
            for _rule in self.class_rules:
                if _rule.name == self.root_rule.name:
                    is_root_class = True
                    break

            if not is_root_class:
                f = open(self.root_rule.kv_file, 'r')
                _file_str = f.read()
                f.close()

                old_str = self.get_class_str_from_text(self.root_rule.name,
                                                       _file_str,
                                                       is_class=False)
                new_str = self.get_class_str_from_text(self.root_rule.name,
                                                       text, is_class=False)

                f = open(self.root_rule.kv_file, 'w')
                _file_str = _file_str.replace(old_str, new_str)
                f.write(_file_str)
                f.close()

        else:
            #If root widget is changed
            #Root Widget changes, there can be these cases:
            root_name = self.root_rule.name
            f = open(self._app_file, 'r')
            file_str = f.read()
            f.close()
            self._root_rule = self.root_rule

            if self.is_root_a_class_rule() and self._app_file:
                #Root Widget's class rule is a custom class
                #and its rule is class rule. So, it already have been saved
                #the string of App's build() function will be changed to
                #return new root widget's class

                if self._app_class != 'runTouchApp':
                    s = re.search(r'class\s+%s.+:' % self._app_class, file_str)
                    if s:
                        build_searchiter = None
                        for searchiter in re.finditer(
                                r'[ \ \t]+def\s+build\s*\(\s*self.+\s*:',
                                file_str):
                            if searchiter.start() > s.start():
                                build_searchiter = searchiter
                                break

                        if build_searchiter:
                            indent = get_indentation(build_searchiter.group(0))
                            file_str = file_str[:build_searchiter.end()] +\
                                '\n' + get_indent_str(2*indent) + "return " +\
                                root_name + "()\n" + \
                                file_str[build_searchiter.end():]

                        else:
                            file_str = file_str[:s.end()] + \
                                "\n    def build(self):\n        return " + \
                                root_name + '()\n' + file_str[s.end():]

                else:
                    file_str = re.sub(r'runTouchApp\s*\(.+\)',
                                      'runTouchApp('+root_name+'())', file_str)

                f = open(self._app_file, 'w')
                f.write(file_str)
                f.close()

            else:
                #Root Widget's rule is not a custom class
                #and its rule is root rule
                #Its kv_file should be of App's class name
                #and App's build() function should be cleared
                if not self.root_rule.kv_file:
                    s = self._app_class.replace('App', '').lower()
                    root_file = None
                    for _file in self.kv_file_list:
                        if os.path.basename(_file).find(s) == 0:
                            self.root_rule.kv_file = _file
                            break

                f = open(self.root_rule.kv_file, 'r')
                _file_str = f.read()
                f.close()

                new_str = self.get_class_str_from_text(self.root_rule.name,
                                                       text, False)

                f = open(self.root_rule.kv_file, 'a')
                f.write(new_str)
                f.close()

                if self._app_class != 'runTouchApp':
                    s = re.search(r'class\s+%s.+:' % self._app_class, file_str)
                    if s:
                        build_searchiter = None
                        for searchiter in re.finditer(
                                r'[ \ \t]+def\s+build\s*\(\s*self.+\s*:',
                                file_str):
                            if searchiter.start() > s.start():
                                build_searchiter = searchiter
                                break

                        if build_searchiter:
                            lines = file_str.splitlines()
                            total_lines = len(lines)
                            indent = get_indentation(build_searchiter.group(0))

                            _line = 0
                            _line_pos = -1
                            _line_pos = file_str.find('\n', _line_pos + 1)
                            while _line_pos <= build_searchiter.start():
                                _line_pos = file_str.find('\n', _line_pos + 1)
                                _line += 1

                            _line += 1

                            while _line < total_lines:
                                if lines[_line].strip() != '' and\
                                        get_indentation(lines[_line]) <= \
                                        indent:
                                    break

                                _line += 1

                            _line -= 1
                            end = get_line_start_pos(file_str, _line)
                            start = build_searchiter.start()
                            file_str = file_str.replace(file_str[start:end],
                                                        '    pass')

                            f = open(self._app_file, 'w')
                            f.write(file_str)
                            f.close()

        #Allow Project Watcher to emit events
        Clock.schedule_once(self._allow_proj_watcher_dispatch, 1)