def on_close_tab(self, instance, *args):
        '''Event handler to close icon
        :param instance: tab instance
        '''
        d = get_designer()
        if d.popup:
            return False

        self.switch_to(instance)
        if instance.has_modification:
            # show a dialog to ask if can close
            confirm_dlg = ConfirmationDialog(
                    'All unsaved changes will be lost.\n'
                    'Do you want to continue?')
            popup = Popup(
                    title='New',
                    content=confirm_dlg,
                    size_hint=(None, None),
                    size=('200pt', '150pt'),
                    auto_dismiss=False)

            def close_tab(*args):
                d.close_popup()
                self._perform_close_tab(instance)

            confirm_dlg.bind(
                    on_ok=close_tab,
                    on_cancel=d.close_popup)
            popup.open()
            d.popup = popup
        else:
            Clock.schedule_once(partial(self._perform_close_tab, instance))
Esempio n. 2
0
    def on_close_tab(self, instance, *args):
        '''Event handler to close icon
        :param instance: tab instance
        '''
        d = get_designer()
        if d.popup:
            return False

        self.switch_to(instance)
        if instance.has_modification:
            # show a dialog to ask if can close
            confirm_dlg = ConfirmationDialog(
                    'All unsaved changes will be lost.\n'
                    'Do you want to continue?')
            popup = Popup(
                    title='New',
                    content=confirm_dlg,
                    size_hint=(None, None),
                    size=('200pt', '150pt'),
                    auto_dismiss=False)

            def close_tab(*args):
                d.close_popup()
                self._perform_close_tab(instance)

            confirm_dlg.bind(
                    on_ok=close_tab,
                    on_cancel=d.close_popup)
            popup.open()
            d.popup = popup
        else:
            Clock.schedule_once(partial(self._perform_close_tab, instance))
    def run(self, *args, **kwargs):
        '''Run the project using Python
        '''
        if self.designer.popup:
            self.profiler.dispatch(
                'on_error', 'You must close all popups '
                'before building your project')
            return
        mod = kwargs.get('mod', '')
        data = kwargs.get('data', [])

        self._get_python()
        if not self.can_run:
            return

        py_main = os.path.join(self.profiler.project_path, 'main.py')
        if isinstance(py_main, bytes):
            py_main = py_main.decode(get_fs_encoding())

        if not os.path.isfile(py_main):
            self.profiler.dispatch('on_error', 'Cannot find main.py')
            return
        if sys.platform[0] == 'w':
            py_main = py_main.replace(' ', '\x01')
        else:
            py_main = py_main.replace(' ', '\\ ')
        cmd = ''
        if mod == '':
            cmd = '%s %s %s' % (self.python_path, py_main, self.args)
        elif mod == 'screen':
            cmd = '%s %s -m screen:%s %s' % (self.python_path, py_main, data,
                                             self.args)
        else:
            cmd = '%s %s -m %s %s' % (self.python_path, py_main, mod,
                                      self.args)

        status = self.run_command(cmd)

        # popen busy
        if status is False:
            confirm_dlg = ConfirmationDialog(
                message="There is another command running.\n"
                "Do you want to stop it to run your project?")
            self.designer.popup = Popup(title='Kivy Designer',
                                        content=confirm_dlg,
                                        size_hint=(None, None),
                                        size=('300pt', '150pt'),
                                        auto_dismiss=False)
            confirm_dlg.bind(on_ok=self._perform_kill_run,
                             on_cancel=self.designer.close_popup)
            self.designer.popup.open()
            return

        self.ui_creator.tab_pannel.switch_to(
            self.ui_creator.tab_pannel.tab_list[2])

        self.profiler.dispatch('on_message', 'Running main.py...')
        self.profiler.dispatch('on_run')
        self.ui_creator.kivy_console.bind(on_command_list_done=self.on_stop)
Esempio n. 4
0
    def run(self, *args, **kwargs):
        '''Run the project using Python
        '''
        if self.designer.popup:
            self.profiler.dispatch('on_error', 'You must close all popups '
                                               'before building your project')
            return
        mod = kwargs.get('mod', '')
        data = kwargs.get('data', [])

        self._get_python()
        if not self.can_run:
            return

        py_main = os.path.join(self.profiler.project_path, 'main.py')
        if isinstance(py_main, bytes):
            py_main = py_main.decode(get_fs_encoding())

        if not os.path.isfile(py_main):
            self.profiler.dispatch('on_error', 'Cannot find main.py')
            return
        if sys.platform[0] == 'w':
            py_main = py_main.replace(' ', '\x01')
        else:
            py_main = py_main.replace(' ', '\\ ')
        cmd = ''
        if mod == '':
            cmd = '%s %s %s' % (self.python_path, py_main, self.args)
        elif mod == 'screen':
            cmd = '%s %s -m screen:%s %s' % (self.python_path, py_main,
                                             data, self.args)
        else:
            cmd = '%s %s -m %s %s' % (self.python_path, py_main,
                                      mod, self.args)

        status = self.run_command(cmd)

        # popen busy
        if status is False:
            confirm_dlg = ConfirmationDialog(
                message="There is another command running.\n"
                        "Do you want to stop it to run your project?")
            self.designer.popup = Popup(title='Kivy Designer',
                                        content=confirm_dlg,
                                        size_hint=(None, None),
                                        size=('300pt', '150pt'),
                                        auto_dismiss=False)
            confirm_dlg.bind(on_ok=self._perform_kill_run,
                             on_cancel=self.designer.close_popup)
            self.designer.popup.open()
            return

        self.ui_creator.tab_pannel.switch_to(
            self.ui_creator.tab_pannel.tab_list[2])

        self.profiler.dispatch('on_message', 'Running main.py...')
        self.profiler.dispatch('on_run')
        self.ui_creator.kivy_console.bind(on_command_list_done=self.on_stop)
Esempio n. 5
0
    def _initialize(self):
        '''Try to get the buildozer path and check required variables
        If there is something wrong shows an alert.
        '''
        if self.designer.popup:
            self.can_run = False
            self.profiler.dispatch('on_error', 'You must close all popups '
                                               'before building your project')
            return
        # first, check if buildozer is set
        self.buildozer_path = self.designer_settings.config_parser.getdefault(
            'buildozer',
            'buildozer_path',
            ''
        )

        if self.buildozer_path == '':
            self.profiler.dispatch('on_error',
                                   'Buildozer Path not specified.'
                                   "\n\nUpdate it on File -> Settings")
            self.can_run = False
            return

        envs = self.proj_settings.config_parser.getdefault(
            'env variables',
            'env',
            ''
        )

        for env in envs.split(' '):
            self.ui_creator.kivy_console.environment[
                env[:env.find('=')]] = env[env.find('=') + 1:]
        # check if buildozer.spec exists
        if not os.path.isfile(os.path.join(self.profiler.project_path,
                                           'buildozer.spec')):
            confirm_dlg = ConfirmationDialog(
                message='buildozer.spec not found.\n'
                        'Do you want to create it now?')
            self.designer.popup = Popup(title='Buildozer',
                                        content=confirm_dlg,
                                        size_hint=(None, None),
                                        size=('200pt', '150pt'),
                                        auto_dismiss=False)
            confirm_dlg.bind(on_ok=self._perform_create_spec,
                             on_cancel=self.designer.close_popup)
            self.designer.popup.open()
            self.can_run = False
            return

        # TODO check if buildozer source.dir and main file exists

        self.can_run = True
 def on_delete(self, *args):
     '''Handler to "Delete profile" button
     '''
     confirm_dlg = ConfirmationDialog(
         message="Do you want to delete this profile?")
     self._popup = Popup(title='Delete Profile',
                         content=confirm_dlg,
                         size_hint=(None, None),
                         size=('200pt', '150pt'),
                         auto_dismiss=False)
     confirm_dlg.bind(on_ok=self._perform_delete_prof,
                      on_cancel=self._popup.dismiss)
     self._popup.open()
Esempio n. 7
0
 def on_delete(self, *args):
     '''Handler to "Delete profile" button
     '''
     confirm_dlg = ConfirmationDialog(
         message="Do you want to delete this profile?")
     self._popup = Popup(title='Delete Profile',
                         content=confirm_dlg,
                         size_hint=(None, None),
                         size=('200pt', '150pt'),
                         auto_dismiss=False)
     confirm_dlg.bind(on_ok=self._perform_delete_prof,
                      on_cancel=self._popup.dismiss)
     self._popup.open()
Esempio n. 8
0
 def on_close_tab(self, instance, *args):
     """Event handler to close icon
     :param instance: tab instance
     """
     self.switch_to(instance)
     if instance.has_modification:
         # show a dialog to ask if can close
         confirm_dlg = ConfirmationDialog("All unsaved changes will be lost.\n" "Do you want to continue?")
         self._popup = Popup(
             title="New", content=confirm_dlg, size_hint=(None, None), size=("200pt", "150pt"), auto_dismiss=False
         )
         confirm_dlg.bind(on_ok=partial(self._perform_close_tab, instance), on_cancel=self._popup.dismiss)
         self._popup.open()
     else:
         Clock.schedule_once(partial(self._perform_close_tab, instance))
    def _initialize(self):
        '''Try to get the buildozer path and check required variables
        If there is something wrong shows an alert.
        '''
        if self.designer.popup:
            self.can_run = False
            self.profiler.dispatch(
                'on_error', 'You must close all popups '
                'before building your project')
            return
        # first, check if buildozer is set
        self.buildozer_path = self.designer_settings.config_parser.getdefault(
            'buildozer', 'buildozer_path', '')

        if self.buildozer_path == '':
            self.profiler.dispatch(
                'on_error', 'Buildozer Path not specified.'
                "\n\nUpdate it on File -> Settings")
            self.can_run = False
            return

        envs = self.proj_settings.config_parser.getdefault(
            'env variables', 'env', '')

        for env in envs.split(' '):
            self.ui_creator.kivy_console.environment[
                env[:env.find('=')]] = env[env.find('=') + 1:]
        # check if buildozer.spec exists
        if not os.path.isfile(
                os.path.join(self.profiler.project_path, 'buildozer.spec')):
            confirm_dlg = ConfirmationDialog(
                message='buildozer.spec not found.\n'
                'Do you want to create it now?')
            self.designer.popup = Popup(title='Buildozer',
                                        content=confirm_dlg,
                                        size_hint=(None, None),
                                        size=('200pt', '150pt'),
                                        auto_dismiss=False)
            confirm_dlg.bind(on_ok=self._perform_create_spec,
                             on_cancel=self.designer.close_popup)
            self.designer.popup.open()
            self.can_run = False
            return

        # TODO check if buildozer source.dir and main file exists

        self.can_run = True
Esempio n. 10
0
    def action_btn_new_pressed(self, *args):
        '''Event Handler when ActionButton "New" is pressed.
        '''

        if not self._curr_proj_changed:
            self._show_new_dialog()
            return

        self._confirm_dlg = ConfirmationDialog('All unsaved changes will be'
                                               ' lost.\n'
                                               'Do you want to continue?')
        self._confirm_dlg.bind(on_ok=self._show_new_dialog,
                               on_cancel=self._cancel_popup)

        self._popup = Popup(title='New',
                            content=self._confirm_dlg,
                            size_hint=(None, None),
                            size=('200pt', '150pt'),
                            auto_dismiss=False)
        self._popup.open()
Esempio n. 11
0
    def project_modified(self, *args):
        '''Event Handler called when Project is modified outside Kivy Designer
        '''

        #To dispatch modified event only once for all files/folders of proj_dir
        if self._proj_modified_outside:
            return

        self._confirm_dlg = ConfirmationDialog(
            message="Current Project has been modified\n"
            "outside the Kivy Designer.\nDo you want to reload project?")
        self._confirm_dlg.bind(on_ok=self._perform_reload,
                               on_cancel=self._cancel_popup)
        self._popup = Popup(title='Kivy Designer',
                            content=self._confirm_dlg,
                            size_hint=(None, None),
                            size=('200pt', '150pt'),
                            auto_dismiss=False)
        self._popup.open()

        self._proj_modified_outside = True
Esempio n. 12
0
    def buildozer_init(self):
        '''Checks if the .spec exists or not; and when possible, calls
            _perform_buildozer_init
        '''

        proj_dir = get_current_project().path
        spec_file = os.path.join(proj_dir, 'buildozer.spec')

        if os.path.exists(spec_file):
            self._confirm_dlg = ConfirmationDialog(
                message='The buildozer.spec file already exist.'
                '\nDo you want to create a new spec?')
            self._popup = Popup(title='Buildozer init',
                                content=self._confirm_dlg,
                                size_hint=(None, None),
                                size=('250pt', '150pt'),
                                auto_dismiss=False)
            self._confirm_dlg.bind(on_ok=self._perform_buildozer_init,
                                   on_cancel=self._popup.dismiss)
            self._popup.open()
        else:
            self._perform_buildozer_init()
Esempio n. 13
0
    def buildozer_init(self):
        '''Checks if the .spec exists or not; and when possible, calls
            _perform_buildozer_init
        '''
        d = get_designer()
        if d.popup:
            return False
        proj_dir = get_current_project().path
        spec_file = os.path.join(proj_dir, 'buildozer.spec')

        if os.path.exists(spec_file):
            confirm_dlg = ConfirmationDialog(
                message='The buildozer.spec file already exist.'
                        '\nDo you want to create a new spec?')
            d.popup = Popup(title='Buildozer init',
                            content=confirm_dlg,
                            size_hint=(None, None),
                            size=('250pt', '150pt'),
                            auto_dismiss=False)
            confirm_dlg.bind(on_ok=self._perform_buildozer_init,
                             on_cancel=d.close_popup)
            d.popup.open()
        else:
            self._perform_buildozer_init()
Esempio n. 14
0
    def action_btn_new_pressed(self, *args):
        """Event Handler when ActionButton "New" is pressed.
        """

        if not self._curr_proj_changed:
            self._show_new_dialog()
            return

        self._confirm_dlg = ConfirmationDialog("All unsaved changes will be" " lost.\n" "Do you want to continue?")
        self._confirm_dlg.bind(on_ok=self._show_new_dialog, on_cancel=self._cancel_popup)

        self._popup = Popup(
            title="New", content=self._confirm_dlg, size_hint=(None, None), size=("200pt", "150pt"), auto_dismiss=False
        )
        self._popup.open()
Esempio n. 15
0
    def action_btn_new_pressed(self, *args):
        '''Event Handler when ActionButton "New" is pressed.
        '''

        if not self._curr_proj_changed:
            self._show_new_dialog()
            return

        self._confirm_dlg = ConfirmationDialog('All unsaved changes will be'
                                               ' lost.\n'
                                               'Do you want to continue?')
        self._confirm_dlg.bind(on_ok=self._show_new_dialog,
                               on_cancel=self._cancel_popup)

        self._popup = Popup(title='New', content = self._confirm_dlg, 
                            size_hint=(None,None),size=('200pt', '150pt'),
                            auto_dismiss=False)
        self._popup.open()
Esempio n. 16
0
    def project_modified(self, *args):
        '''Event Handler called when Project is modified outside Kivy Designer
        '''

        #To dispatch modified event only once for all files/folders of proj_dir
        if self._proj_modified_outside:
            return

        self._confirm_dlg = ConfirmationDialog(
            message="Current Project has been modified\n"
            "outside the Kivy Designer.\nDo you want to reload project?")
        self._confirm_dlg.bind(on_ok=self._perform_reload,
                               on_cancel=self._cancel_popup)
        self._popup = Popup(title='Kivy Designer', content=self._confirm_dlg,
                            size_hint=(None, None), size=('200pt', '150pt'),
                            auto_dismiss=False)
        self._popup.open()

        self._proj_modified_outside = True
Esempio n. 17
0
    def buildozer_init(self):
        '''Checks if the .spec exists or not; and when possible, calls
            _perform_buildozer_init
        '''

        proj_loader = self.designer.project_loader
        proj_dir = proj_loader.proj_dir
        spec_file = os.path.join(proj_dir, 'buildozer.spec')

        if os.path.exists(spec_file):
            self._confirm_dlg = ConfirmationDialog(
                message='The buildozer.spec file already exist.'
                                        '\nDo you want to create a new spec?')
            self._popup = Popup(title='Buildozer init',
                                content=self._confirm_dlg,
                                size_hint=(None, None),
                                size=('250pt', '150pt'),
                                auto_dismiss=False)
            self._confirm_dlg.bind(on_ok=self._perform_buildozer_init,
                                   on_cancel=self._popup.dismiss)
            self._popup.open()
        else:
            self._perform_buildozer_init()
Esempio n. 18
0
class Buildozer(Builder):
    '''Class to handle Buildozer builder
    '''
    def __init__(self, profiler):
        super(Buildozer, self).__init__(profiler)
        self.buildozer_path = ''

    def _initialize(self):
        '''Try to get the buildozer path and check required variables
        If there is something wrong shows an alert.
        '''

        # first, check if buildozer is set
        self.buildozer_path = self.designer_settings.config_parser.getdefault(
            'buildozer', 'buildozer_path', '')

        if self.buildozer_path == '':
            self.profiler.dispatch(
                'on_error', 'Buildozer Path not specified.'
                '\n\nUpdate it on \'File\' -> \'Settings\'')
            self.can_run = False
            return

        envs = self.proj_settings.config_parser.getdefault(
            'env variables', 'env', '')

        for env in envs.split(' '):
            self.ui_creator.kivy_console.environment[
                env[:env.find('=')]] = env[env.find('=') + 1:]

        # check if buildozer.spec exists
        if not os.path.isfile(
                os.path.join(self.profiler.project_path, 'buildozer.spec')):
            self._confirm_dlg = ConfirmationDialog(
                message='buildozer.spec not found.\n'
                'Do you want to create it now?')
            self._popup = Popup(title='Buildozer',
                                content=self._confirm_dlg,
                                size_hint=(None, None),
                                size=('200pt', '150pt'),
                                auto_dismiss=False)
            self._confirm_dlg.bind(on_ok=self._perform_create_spec,
                                   on_cancel=self._popup.dismiss)
            self._popup.open()
            self.can_run = False
            return

        # TODO check if buildozer source.dir and main file exists

        self.can_run = True

    def _perform_create_spec(self, *args):
        '''Creates the default buildozer.spec file
        '''
        _dir = os.path.dirname(designer.__file__)
        _dir = os.path.split(_dir)[0]
        templates_dir = os.path.join(_dir, 'new_templates')
        shutil.copy(os.path.join(templates_dir, 'default.spec'),
                    os.path.join(self.profiler.project_path, 'buildozer.spec'))

        self.designer.designer_content.update_tree_view(get_current_project())
        self._popup.dismiss()
        self.last_command()

    def _create_command(self, extra):
        '''Generate the buildozer command
        '''
        self.project_watcher.pause_watching()
        self._initialize()
        self.ui_creator.tab_pannel.switch_to(
            self.ui_creator.tab_pannel.tab_list[2])

        cd = 'cd ' + self.profiler.project_path
        args = []
        args.append(self.buildozer_path)
        if self.profiler.pro_verbose:
            args.append('--verbose')
        args.append(self.profiler.pro_target.lower())  # android or ios
        args += extra

        return [cd, " ".join(args)]

    def build(self, *args):
        '''Build the Buildozer project.
        Will read the necessary information from the profile and build the app
        '''
        build_mode = self.profiler.pro_mode.lower()
        cmd = self._create_command([build_mode])
        if not self.can_run:
            self.last_command = self.build
            return
        self.run_command(cmd)

        self.profiler.dispatch('on_message', 'Building project...')
        self.ui_creator.kivy_console.bind(on_command_list_done=self.on_build)

    def rebuild(self, *args):
        '''Update project dependencies, and build it again
        '''
        self.clean()
        self.profiler.bind(on_clean=self._rebuild)

    def _rebuild(self, *args):
        '''Perform the project rebuild
        '''
        cmd = self._create_command(['update'])
        if not self.can_run:
            self.last_command = self.rebuild
            return
        self.run_command(cmd)

        self.profiler.dispatch('on_message',
                               'Updating project dependencies...')
        self.ui_creator.kivy_console.bind(on_command_list_done=self.build)

    def run(self, *args, **kwargs):
        '''Run the build command and then run the application on the device
        '''
        self.build()
        if not self.can_run:
            self.last_command = self.run
            return
        if not self.profiler.pro_install:
            self.profiler.bind(on_build=self.deploy)
        self.profiler.bind(on_deploy=self._run)

    def _run(self, *args):
        '''Perform the buildozer run
        '''
        cmds = ['run']
        if self.profiler.pro_debug and self.profiler.pro_target == 'Android':
            cmds.append('logcat')
        cmd = self._create_command(cmds)
        if not self.can_run:
            return
        self.run_command(cmd)

        self.profiler.dispatch('on_message', 'Running on device...')
        self.ui_creator.kivy_console.bind(on_command_list_done=self.on_run)

    def deploy(self, *args):
        '''Perform the buildozer deploy
        '''
        cmd = self._create_command(['deploy'])
        if not self.can_run:
            return
        self.run_command(cmd)

        self.profiler.dispatch('on_message', 'Installing on device...')
        self.ui_creator.kivy_console.bind(on_command_list_done=self.on_deploy)

    def clean(self, *args):
        '''Clean the project directory
        '''
        cmd = self._create_command(['clean'])
        if not self.can_run:
            self.last_command = self.clean
            return
        self.run_command(cmd)

        self.profiler.dispatch('on_message', 'Cleaning project...')
        self.ui_creator.kivy_console.bind(on_command_list_done=self.on_clean)

    def on_clean(self, *args):
        '''on_clean event handler
        '''
        self.ui_creator.kivy_console.unbind(on_command_list_done=self.on_clean)

        self.project_watcher.resume_watching(delay=0)

        self.profiler.dispatch('on_message', 'Project clean', 5)
        self.profiler.dispatch('on_clean')

    def on_build(self, *args):
        '''on_build event handler
        '''
        self.ui_creator.kivy_console.unbind(on_command_list_done=self.on_build)

        self.project_watcher.resume_watching(delay=0)

        self.profiler.dispatch('on_message', 'Build complete', 5)
        self.profiler.dispatch('on_build')

        if self.profiler.pro_install:
            self.deploy()

    def on_deploy(self, *args):
        '''on_build event handler
        '''
        self.ui_creator.kivy_console.unbind(
            on_command_list_done=self.on_deploy)

        self.project_watcher.resume_watching(delay=0)

        self.profiler.dispatch('on_message', 'Installed on device', 5)
        self.profiler.dispatch('on_deploy')

    def on_stop(self, *args):
        '''on_stop event handler
        '''
        self.ui_creator.kivy_console.unbind(on_command_list_done=self.on_stop)

        self.profiler.dispatch('on_stop')

    def on_run(self, *args):
        '''on_run event handler
        '''
        self.ui_creator.kivy_console.unbind(on_command_list_done=self.on_run)

        self.project_watcher.resume_watching(delay=0)

        self.profiler.dispatch('on_message', '', 1)
        self.profiler.dispatch('on_run')
        self.designer.ids.actn_btn_stop_proj.disabled = True
Esempio n. 19
0
class Desktop(Builder):
    '''Class to handle Desktop builder
    '''
    def __init__(self, profiler):
        super(Desktop, self).__init__(profiler)
        self.python_path = ''
        self.args = ''
        # TODO check if buildozer source.dir and main file is set, if so
        # use this file

    def _get_python(self):
        '''Initialize python variables
        If there is something wrong shows an alert
        '''
        self.python_path = self.designer_settings.config_parser.getdefault(
            'global', 'python_shell_path', '')

        if self.python_path == '':
            self.profiler.dispatch(
                'on_error', 'Python Shell Path not '
                'specified.'
                '\n\nUpdate it on \'File\' -> \'Settings\'')
            self.can_run = False
            return

        self.args = self.proj_settings.config_parser.getdefault(
            'arguments', 'arg', '')

        envs = self.proj_settings.config_parser.getdefault(
            'env variables', 'env', '')

        for env in envs.split(' '):
            self.ui_creator.kivy_console.environment[
                env[:env.find('=')]] = env[env.find('=') + 1:]

        self.can_run = True

    def _perform_kill_run(self, *args):
        '''Stop the running project/command and then run the project
        '''
        self._popup.dismiss()
        self.stop()
        Clock.schedule_once(self.run)

    def run(self, *args, **kwargs):
        '''Run the project using Python
        '''
        mod = kwargs.get('mod', '')
        data = kwargs.get('data', [])

        self._get_python()
        if not self.can_run:
            return

        py_main = os.path.join(self.profiler.project_path, 'main.py')

        if not os.path.isfile(py_main):
            self.profiler.dispatch('on_error', 'Cannot find main.py')
            return

        cmd = ''
        if mod == '':
            cmd = '%s %s %s' % (self.python_path, py_main, self.args)
        elif mod == 'screen':
            cmd = '%s %s -m screen:%s %s' % (self.python_path, py_main, data,
                                             self.args)
        else:
            cmd = '%s %s -m %s %s' % (self.python_path, py_main, mod,
                                      self.args)

        status = self.run_command(cmd)

        # popen busy
        if status is False:
            self._confirm_dlg = ConfirmationDialog(
                message="There is another command running.\n"
                "Do you want to stop it to run your project?")
            self._popup = Popup(title='Kivy Designer',
                                content=self._confirm_dlg,
                                size_hint=(None, None),
                                size=('300pt', '150pt'),
                                auto_dismiss=False)
            self._confirm_dlg.bind(on_ok=self._perform_kill_run,
                                   on_cancel=self._popup.dismiss)
            self._popup.open()
            return

        self.ui_creator.tab_pannel.switch_to(
            self.ui_creator.tab_pannel.tab_list[2])

        self.profiler.dispatch('on_message', 'Running main.py...')
        self.profiler.dispatch('on_run')
        self.ui_creator.kivy_console.bind(on_command_list_done=self.on_stop)

    def stop(self, *args):
        '''If there is a process running, it'll be stopped
        '''
        self.ui_creator.kivy_console.kill_process()
        self.profiler.dispatch('on_stop')
        self.profiler.dispatch('on_message', '', 1)

    def clean(self, *args):
        '''Remove .pyc files and __pycache__ folder
        '''
        # here it's necessary to stop the listener as long as the
        # python is managing files
        self.project_watcher.pause_watching()
        for _file in os.listdir(self.profiler.project_path):
            ext = _file.split('.')[-1]
            if ext == 'pyc':
                os.remove(os.path.join(self.profiler.project_path, _file))
        __pycache__ = os.path.join(self.profiler.project_path, '__pycache__')
        if os.path.exists(__pycache__):
            shutil.rmtree(__pycache__)

        self.project_watcher.resume_watching(delay=0)
        self.profiler.dispatch('on_message', 'Project cleaned', 5)

    def build(self, *args):
        '''Compile all .py to .pyc
        '''
        self._get_python()
        if not self.can_run:
            return

        self.project_watcher.pause_watching()
        proj_path = self.profiler.project_path

        self.run_command('%s -m compileall -l %s' %
                         (self.python_path, proj_path))

        self.ui_creator.tab_pannel.switch_to(
            self.ui_creator.tab_pannel.tab_list[2])

        self.profiler.dispatch('on_message', 'Building project...')
        self.ui_creator.kivy_console.bind(on_command_list_done=self.on_build)

    def rebuild(self, *args):
        '''Clean and build the project
        '''
        self.clean()
        self.build()

    def on_build(self, *args):
        '''on_build event handler
        '''
        self.project_watcher.resume_watching(delay=0)
        self.profiler.dispatch('on_message', 'Build complete', 5)
        self.profiler.dispatch('on_build')

    def on_stop(self, *args):
        '''on_stop event handler
        '''
        self.profiler.dispatch('on_message', '', 1)
        self.profiler.dispatch('on_stop')
Esempio n. 20
0
class Designer(FloatLayout):
    '''Designer is the Main Window class of Kivy Designer
       :data:`message` is a :class:`~kivy.properties.StringProperty`
    '''

    designer_console = ObjectProperty(None)
    '''Instance of :class:`designer.designer_console.ConsoleDialog`
    '''

    statusbar = ObjectProperty(None)
    '''Reference to the :class:`~designer.statusbar.StatusBar` instance.
       :data:`statusbar` is a :class:`~kivy.properties.ObjectProperty`
    '''

    editcontview = ObjectProperty(None)
    '''Reference to the :class:`~designer.uix.EditContView` instance.
       :data:`v` is a :class:`~kivy.properties.ObjectProperty`
    '''

    actionbar = ObjectProperty(None)
    '''Reference to the :class:`~kivy.actionbar.ActionBar` instance.
       ActionBar is used as a MenuBar to display bunch of menu items.
       :data:`actionbar` is a :class:`~kivy.properties.ObjectProperty`
    '''

    undo_manager = ObjectProperty(UndoManager())
    '''Reference to the :class:`~designer.UndoManager` instance.
       :data:`undo_manager` is a :class:`~kivy.properties.ObjectProperty`
    '''

    project_watcher = ObjectProperty(None)
    '''Reference to the :class:`~designer.project_watcher.ProjectWatcher`.
       :data:`project_watcher` is a :class:`~kivy.properties.ObjectProperty`
    '''

    project_loader = ObjectProperty(None)
    '''Reference to the :class:`~designer.project_loader.ProjectLoader`.
       :data:`project_loader` is a :class:`~kivy.properties.ObjectProperty`
    '''

    proj_settings = ObjectProperty(None)
    '''Reference of :class:`~designer.project_settings.ProjectSettings`.
       :data:`proj_settings` is a :class:`~kivy.properties.ObjectProperty`
    '''

    _curr_proj_changed = BooleanProperty(False)
    '''Specifies whether current project has been changed inside Kivy Designer
       :data:`_curr_proj_changed` is
       a :class:`~kivy.properties.BooleanProperty`
    '''

    _proj_modified_outside = BooleanProperty(False)
    '''Specifies whether current project has been changed outside Kivy Designer
       :data:`_proj_modified_outside` is a
       :class:`~kivy.properties.BooleanProperty`
    '''

    ui_creator = ObjectProperty(None)
    '''Reference to :class:`~designer.ui_creator.UICreator` instance.
       :data:`ui_creator` is a :class:`~kivy.properties.ObjectProperty`
    '''

    designer_content = ObjectProperty(None)
    '''Reference to
       :class:`~designer.designer_content.DesignerContent` instance.
       :data:`designer_content` is a :class:`~kivy.properties.ObjectProperty`
    '''

    proj_tree_view = ObjectProperty(None)
    '''Reference to Project Tree instance
       :data:`proj_tree_view` is a :class:`~kivy.properties.ObjectProperty`
    '''

    designer_settings = ObjectProperty(None)
    '''Reference of :class:`~designer.designer_settings.DesignerSettings`.
       :data:`designer_settings` is a :class:`~kivy.properties.ObjectProperty`
    '''

    start_page = ObjectProperty(None)
    '''Reference of :class:`~designer.start_page.DesignerStartPage`.
       :data:`start_page` is a :class:`~kivy.properties.ObjectProperty`
    '''

    recent_files_cont_menu = ObjectProperty(None)
    '''The context sub menu, containing the recently opened/saved projects.
       Reference of :class:`~designer.uix.contextual.ContextSubMenu`.
       :data:`recent_files_cont_menu` is a
       :class:`~kivy.properties.ObjectProperty`
    '''
    def __init__(self, **kwargs):
        super(Designer, self).__init__(**kwargs)
        self.project_watcher = ProjectWatcher(self.project_modified)
        self.project_loader = ProjectLoader(self.project_watcher)
        self.recent_manager = RecentManager()
        self.widget_to_paste = None
        self.designer_content = DesignerContent(size_hint=(1, None))

        self.designer_settings = DesignerSettings()
        self.designer_settings.bind(on_config_change=self._config_change)
        self.designer_settings.load_settings()
        self.designer_settings.bind(on_close=self._cancel_popup)

        Clock.schedule_interval(
            self.project_loader.perform_auto_save,
            int(
                self.designer_settings.config_parser.getdefault(
                    'global', 'auto_save_time', 5)) * 60)

    def show_help(self, *args):
        '''Event handler for 'on_help' event of self.start_page
        '''

        self.help_dlg = HelpDialog()
        self._popup = Popup(title='Kivy Designer Help',
                            content=self.help_dlg,
                            size_hint=(0.95, 0.95),
                            auto_dismiss=False)
        self._popup.open()
        self.help_dlg.bind(on_cancel=self._cancel_popup)

        self.help_dlg.rst.source = 'help.rst'

    def _config_change(self, *args):
        '''Event Handler for 'on_config_change'
           event of self.designer_settings.
        '''

        Clock.unschedule(self.project_loader.perform_auto_save)
        Clock.schedule_interval(
            self.project_loader.perform_auto_save,
            int(
                self.designer_settings.config_parser.getdefault(
                    'global', 'auto_save_time', 5)) * 60)

        self.ui_creator.kv_code_input.reload_kv = \
            bool(self.designer_settings.config_parser.getdefault(
                 'global', 'reload_kv', True))

        self.recent_manager.max_recent_files = \
            int(self.designer_settings.config_parser.getdefault(
                'global', 'num_recent_files', 5))

    def _add_designer_content(self):
        '''Add designer_content to Designer, when a project is loaded
        '''

        for _child in self.children[:]:
            if _child == self.designer_content:
                return

        self.remove_widget(self.start_page)
        self.add_widget(self.designer_content, 1)

        self.ids['actn_btn_save'].disabled = False
        self.ids['actn_btn_save_as'].disabled = False
        self.ids['actn_chk_proj_tree'].disabled = False
        self.ids['actn_chk_prop_event'].disabled = False
        self.ids['actn_chk_widget_tree'].disabled = False
        self.ids['actn_chk_status_bar'].disabled = False
        self.ids['actn_chk_kv_lang_area'].disabled = False
        self.ids['actn_btn_add_file'].disabled = False
        self.ids['actn_btn_custom_widget'].disabled = False
        self.ids['actn_btn_proj_pref'].disabled = False
        self.ids['actn_btn_run_proj'].disabled = False

    def on_statusbar_height(self, *args):
        '''Callback for statusbar.height
        '''

        self.designer_content.y = self.statusbar.height
        self.on_height(*args)

    def on_actionbar_height(self, *args):
        '''Callback for actionbar.height
        '''

        self.on_height(*args)

    def on_height(self, *args):
        '''Callback for self.height
        '''

        if self.actionbar and self.statusbar:
            self.designer_content.height = self.height - \
                self.actionbar.height - self.statusbar.height

            self.designer_content.y = self.statusbar.height

    def project_modified(self, *args):
        '''Event Handler called when Project is modified outside Kivy Designer
        '''

        #To dispatch modified event only once for all files/folders of proj_dir
        if self._proj_modified_outside:
            return

        self._confirm_dlg = ConfirmationDialog(
            message="Current Project has been modified\n"
            "outside the Kivy Designer.\nDo you want to reload project?")
        self._confirm_dlg.bind(on_ok=self._perform_reload,
                               on_cancel=self._cancel_popup)
        self._popup = Popup(title='Kivy Designer',
                            content=self._confirm_dlg,
                            size_hint=(None, None),
                            size=('200pt', '150pt'),
                            auto_dismiss=False)
        self._popup.open()

        self._proj_modified_outside = True

    def _perform_reload(self, *args):
        '''Perform reload of project after it is modified
        '''

        #Perform reload of project after it is modified
        self._popup.dismiss()
        self.project_watcher.allow_event_dispatch = False
        self._perform_open(self.project_loader.proj_dir)
        self.project_watcher.allow_event_dispatch = True
        self._proj_modified_outside = False

    def on_show_edit(self, *args):
        '''Event Handler of 'on_show_edit' event. This will show EditContView
           in ActionBar
        '''

        if isinstance(self.actionbar.children[0], EditContView):
            return

        if self.editcontview is None:
            self.editcontview = EditContView(
                on_undo=self.action_btn_undo_pressed,
                on_redo=self.action_btn_redo_pressed,
                on_cut=self.action_btn_cut_pressed,
                on_copy=self.action_btn_copy_pressed,
                on_paste=self.action_btn_paste_pressed,
                on_delete=self.action_btn_delete_pressed,
                on_selectall=self.action_btn_select_all_pressed,
                on_next_screen=self._next_screen,
                on_prev_screen=self._prev_screen)

        self.actionbar.add_widget(self.editcontview)

        widget = self.ui_creator.propertyviewer.widget

        if isinstance(widget, Carousel) or\
                isinstance(widget, ScreenManager) or\
                isinstance(widget, TabbedPanel):
            self.editcontview.show_action_btn_screen(True)
        else:
            self.editcontview.show_action_btn_screen(False)

        if self.ui_creator.kv_code_input.clicked:
            self._edit_selected = 'KV'
        elif self.ui_creator.playground.clicked:
            self._edit_selected = 'Play'
        else:
            self._edit_selected = 'Py'

        self.ui_creator.playground.clicked = False
        self.ui_creator.kv_code_input.clicked = False

    def _prev_screen(self, *args):
        '''Event handler for 'on_prev_screen' for self.editcontview
        '''

        widget = self.ui_creator.propertyviewer.widget
        if isinstance(widget, Carousel):
            widget.load_previous()

        elif isinstance(widget, ScreenManager):
            widget.current = widget.previous()

        elif isinstance(widget, TabbedPanel):
            index = widget.tab_list.index(widget.current_tab)
            if len(widget.tab_list) <= index + 1:
                return

            widget.switch_to(widget.tab_list[index + 1])

    def _next_screen(self, *args):
        '''Event handler for 'on_next_screen' for self.editcontview
        '''

        widget = self.ui_creator.propertyviewer.widget
        if isinstance(widget, Carousel):
            widget.load_next()

        elif isinstance(widget, ScreenManager):
            widget.current = widget.next()

        elif isinstance(widget, TabbedPanel):
            index = widget.tab_list.index(widget.current_tab)
            if index == 0:
                return

            widget.switch_to(widget.tab_list[index - 1])

    def on_touch_down(self, touch):
        '''Override of FloatLayout.on_touch_down. Used to determine where
           touch is down and to call self.actionbar.on_previous
        '''

        if not isinstance(self.actionbar.children[0], EditContView) or\
           self.actionbar.collide_point(*touch.pos):
            return super(FloatLayout, self).on_touch_down(touch)

        self.actionbar.on_previous(self)

        return super(FloatLayout, self).on_touch_down(touch)

    def action_btn_new_pressed(self, *args):
        '''Event Handler when ActionButton "New" is pressed.
        '''

        if not self._curr_proj_changed:
            self._show_new_dialog()
            return

        self._confirm_dlg = ConfirmationDialog('All unsaved changes will be'
                                               ' lost.\n'
                                               'Do you want to continue?')
        self._confirm_dlg.bind(on_ok=self._show_new_dialog,
                               on_cancel=self._cancel_popup)

        self._popup = Popup(title='New',
                            content=self._confirm_dlg,
                            size_hint=(None, None),
                            size=('200pt', '150pt'),
                            auto_dismiss=False)
        self._popup.open()

    def _show_new_dialog(self, *args):
        if hasattr(self, '_popup'):
            self._popup.dismiss()

        self._new_dialog = NewProjectDialog()
        self._new_dialog.bind(on_select=self._perform_new,
                              on_cancel=self._cancel_popup)
        self._popup = Popup(title='New Project',
                            content=self._new_dialog,
                            size_hint=(None, None),
                            size=('650pt', '450pt'),
                            auto_dismiss=False)
        self._popup.open()

    def _perform_new(self, *args):
        '''To load new project
        '''

        if hasattr(self, '_popup'):
            self._popup.dismiss()

        self.cleanup()
        new_proj_dir = os.path.join(get_kivy_designer_dir(),
                                    NEW_PROJECT_DIR_NAME)
        if os.path.exists(new_proj_dir):
            shutil.rmtree(new_proj_dir)

        os.mkdir(new_proj_dir)

        template = self._new_dialog.adapter.selection[0].text
        kv_file = NEW_PROJECTS[template][0]
        py_file = NEW_PROJECTS[template][1]

        _dir = os.path.dirname(designer.__file__)
        _dir = os.path.split(_dir)[0]
        templates_dir = os.path.join(_dir, NEW_TEMPLATES_DIR)
        shutil.copy(os.path.join(templates_dir, py_file),
                    os.path.join(new_proj_dir, "main.py"))

        shutil.copy(os.path.join(templates_dir, kv_file),
                    os.path.join(new_proj_dir, "main.kv"))

        self.ui_creator.playground.sandbox.error_active = True
        with self.ui_creator.playground.sandbox:
            self.project_loader.load_new_project(
                os.path.join(new_proj_dir, "main.kv"))
            root_wigdet = self.project_loader.get_root_widget()
            self.ui_creator.playground.add_widget_to_parent(root_wigdet,
                                                            None,
                                                            from_undo=True)
            self.ui_creator.kv_code_input.text = \
                self.project_loader.get_full_str()
            self.designer_content.update_tree_view(self.project_loader)
            self._add_designer_content()
            if self.project_loader.class_rules:
                for i, _rule in enumerate(self.project_loader.class_rules):
                    widgets.append((_rule.name, 'custom'))

                self.designer_content.toolbox.add_custom()

        self.ui_creator.playground.sandbox.error_active = False

    def cleanup(self):
        '''To cleanup everything loaded by the current project before loading
           another project.
        '''

        self.project_loader.cleanup()
        self.ui_creator.cleanup()
        self.undo_manager.cleanup()
        self.designer_content.toolbox.cleanup()

        for node in self.proj_tree_view.root.nodes[:]:
            self.proj_tree_view.remove_node(node)

        for widget in widgets[:]:
            if widget[1] == 'custom':
                widgets.remove(widget)

        self._curr_proj_changed = False
        self.ui_creator.kv_code_input.text = ""

        self.designer_content.tab_pannel.list_py_code_inputs = []
        for th in self.designer_content.tab_pannel.tab_list[:-1]:
            self.designer_content.tab_pannel.remove_widget(th)

    def action_btn_open_pressed(self, *args):
        '''Event Handler when ActionButton "Open" is pressed.
        '''

        if not self._curr_proj_changed:
            self._show_open_dialog()
            return

        self._confirm_dlg = ConfirmationDialog('All unsaved changes will be '
                                               'lost.\n'
                                               'Do you want to continue?')

        self._confirm_dlg.bind(on_ok=self._show_open_dialog,
                               on_cancel=self._cancel_popup)

        self._popup = Popup(title='Kivy Designer',
                            content=self._confirm_dlg,
                            size_hint=(None, None),
                            size=('200pt', '150pt'),
                            auto_dismiss=False)
        self._popup.open()

    def _show_open_dialog(self, *args):
        '''To show FileBrowser to "Open" a project
        '''

        if hasattr(self, '_popup'):
            self._popup.dismiss()

        self._fbrowser = FileBrowser(select_string='Open')

        def_path = os.getcwd()
        if not self.project_loader.new_project and \
                self.project_loader.proj_dir:
            def_path = self.project_loader.proj_dir

        if self._fbrowser.ids.tabbed_browser.current_tab.text == 'List View':
            self._fbrowser.ids.list_view.path = def_path
        else:
            self._fbrowser.ids.icon_view.path = def_path

        self._fbrowser.bind(on_success=self._fbrowser_load,
                            on_canceled=self._cancel_popup)

        self._popup = Popup(title="Open",
                            content=self._fbrowser,
                            size_hint=(0.9, 0.9),
                            auto_dismiss=False)
        self._popup.open()

    def _select_class_selected(self, *args):
        '''Event Handler for 'on_select' event of self._select_class
        '''

        selection = self._select_class.listview.adapter.selection[0].text

        with self.ui_creator.playground.sandbox:
            root_widget = self.project_loader.set_root_widget(selection)
            self.ui_creator.playground.add_widget_to_parent(root_widget,
                                                            None,
                                                            from_undo=True)
            self.ui_creator.kv_code_input.text = \
                self.project_loader.get_root_str()

        self._select_class_popup.dismiss()

    def _select_class_cancel(self, *args):
        '''Event Handler for 'on_cancel' event of self._select_class
        '''

        self._select_class_popup.dismiss()

    def _fbrowser_load(self, instance):
        '''Event Handler for 'on_load' event of self._fbrowser
        '''
        if instance.selection == []:
            return

        file_path = instance.selection[0]
        self._popup.dismiss()
        self._perform_open(file_path)

    def _perform_open(self, file_path):
        '''To open a project given by file_path
        '''

        for widget in widgets[:]:
            if widget[1] == 'custom':
                widgets.remove(widget)

        self.cleanup()

        self.ui_creator.playground.sandbox.error_active = True

        root_widget = None

        with self.ui_creator.playground.sandbox:
            try:
                self.project_loader.load_project(file_path)

                if self.project_loader.class_rules:
                    for i, _rule in enumerate(self.project_loader.class_rules):
                        widgets.append((_rule.name, 'custom'))

                    self.designer_content.toolbox.add_custom()

                #to test listview
                #root_wigdet = None
                root_wigdet = self.project_loader.get_root_widget()

                if not root_wigdet:
                    #Show list box showing widgets
                    self._select_class = SelectClass(
                        self.project_loader.class_rules)

                    self._select_class.bind(
                        on_select=self._select_class_selected,
                        on_cancel=self._select_class_cancel)

                    self._select_class_popup = Popup(
                        title="Select Root Widget",
                        content=self._select_class,
                        size_hint=(0.5, 0.5),
                        auto_dismiss=False)
                    self._select_class_popup.open()

                else:
                    self.ui_creator.playground.add_widget_to_parent(
                        root_wigdet, None, from_undo=True)
                    self.ui_creator.kv_code_input.text = \
                        self.project_loader.get_full_str()

                self.recent_manager.add_file(file_path)
                #Record everything for later use
                self.project_loader.record()
                self.designer_content.update_tree_view(self.project_loader)
                self._add_designer_content()

            except Exception as e:
                self.statusbar.show_message('Cannot load Project: %s' %
                                            (str(e)))

        self.ui_creator.playground.sandbox.error_active = False

    def _cancel_popup(self, *args):
        '''EventHandler for all self._popup when self._popup.content
           emits 'on_cancel' or equivalent.
        '''

        self._proj_modified_outside = False
        self._popup.dismiss()

    def action_btn_save_pressed(self, *args):
        '''Event Handler when ActionButton "Save" is pressed.
        '''

        if self.project_loader.root_rule:
            try:
                if self.project_loader.new_project:
                    self.action_btn_save_as_pressed()
                    return

                else:
                    self.project_loader.save_project()
                    projdir = self.project_loader.proj_dir
                    self.project_loader.cleanup(stop_watcher=False)
                    self.ui_creator.playground.cleanup()
                    self.project_loader.load_project(projdir)
                    root_wigdet = self.project_loader.get_root_widget()
                    self.ui_creator.playground.add_widget_to_parent(
                        root_wigdet, None, from_undo=True, from_kv=True)
                self._curr_proj_changed = False
                self.statusbar.show_message('Project saved successfully')

            except:
                self.statusbar.show_message('Cannot save project')

    def action_btn_save_as_pressed(self, *args):
        '''Event Handler when ActionButton "Save As" is pressed.
        '''

        if self.project_loader.root_rule:
            self._curr_proj_changed = False

            self._save_as_browser = FileBrowser(select_string='Save')

            def_path = os.getcwd()
            if not self.project_loader.new_project and \
                    self.project_loader.proj_dir:
                def_path = self.project_loader.proj_dir

            if self._save_as_browser.ids.tabbed_browser.current_tab.text == \
                    'List View':
                self._save_as_browser.ids.list_view.path = def_path
            else:
                self._save_as_browser.ids.icon_view.path = def_path

            self._save_as_browser.bind(on_success=self._perform_save_as,
                                       on_canceled=self._cancel_popup)

            self._popup = Popup(title="Enter Folder Name",
                                content=self._save_as_browser,
                                size_hint=(0.9, 0.9),
                                auto_dismiss=False)
            self._popup.open()

    def _perform_save_as(self, instance):
        '''Event handler for 'on_success' event of self._save_as_browser
        '''

        if hasattr(self, '_popup'):
            self._popup.dismiss()

        proj_dir = ''
        if instance.ids.tabbed_browser.current_tab.text == 'List View':
            proj_dir = instance.ids.list_view.path
        else:
            proj_dir = instance.ids.icon_view.path

        proj_dir = os.path.join(proj_dir, instance.filename)
        try:
            self.project_loader.save_project(proj_dir)
            self.recent_manager.add_file(proj_dir)
            projdir = self.project_loader.proj_dir
            self.project_loader.cleanup()
            self.ui_creator.playground.cleanup()
            self.project_loader.load_project(projdir)
            root_wigdet = self.project_loader.get_root_widget()
            self.ui_creator.playground.add_widget_to_parent(root_wigdet,
                                                            None,
                                                            from_undo=True)
            self.statusbar.show_message('Project saved successfully')

        except:
            self.statusbar.show_message('Cannot save project')

    def action_btn_settings_pressed(self, *args):
        '''Event handler for 'on_release' event of
           DesignerActionButton "Settings"
        '''

        self.designer_settings.parent = None
        self._popup = Popup(title="Kivy Designer Settings",
                            content=self.designer_settings,
                            size_hint=(None, None),
                            size=(600, 400),
                            auto_dismiss=False)

        self._popup.open()

    def action_btn_recent_files_pressed(self, *args):
        '''Event Handler when ActionButton "Recent Files" is pressed.
        '''
        pass

    def fill_recent_menu(self, *args):
        '''Fill self.recent_files_cont_menu with DesignerActionButton
           of all Recent Files
        '''
        recent_menu = self.recent_files_cont_menu
        for _file in self.recent_manager.list_files:
            act_btn = DesignerActionButton(text=_file, shorten=True)
            recent_menu.add_widget(act_btn)
            act_btn.bind(on_release=self._recent_file_release)

    def _recent_file_release(self, instance, *args):
        '''Event Handler for 'on_select' event of self._recent_dlg.
        '''
        self._perform_open(instance.text)

    def action_btn_quit_pressed(self, *args):
        '''Event Handler when ActionButton "Quit" is pressed.
        '''

        App.get_running_app().stop()

    def action_btn_undo_pressed(self, *args):
        '''Event Handler when ActionButton "Undo" is pressed.
        '''

        if self._edit_selected == 'Play':
            self.undo_manager.do_undo()
        elif self._edit_selected == 'KV':
            self.ui_creator.kv_code_input.do_undo()
        elif self._edit_selected == 'Py':
            list_py = self.designer_content.tab_pannel.list_py_code_inputs
            for code_input in list_py:
                if code_input.clicked is True:
                    code_input.clicked = False
                    code_input.do_undo()

    def action_btn_redo_pressed(self, *args):
        '''Event Handler when ActionButton "Redo" is pressed.
        '''

        if self._edit_selected == 'Play':
            self.undo_manager.do_redo()
        elif self._edit_selected == 'KV':
            self.ui_creator.kv_code_input.do_redo()
        elif self._edit_selected == 'Py':
            list_py = self.designer_content.tab_pannel.list_py_code_inputs
            for code_input in list_py:
                if code_input.clicked is True:
                    code_input.clicked = False
                    code_input.do_redo()

    def action_btn_cut_pressed(self, *args):
        '''Event Handler when ActionButton "Cut" is pressed.
        '''

        if self._edit_selected == 'Play':
            self.ui_creator.playground.do_cut()

        elif self._edit_selected == 'KV':
            self.ui_creator.kv_code_input.do_cut()

        elif self._edit_selected == 'Py':
            list_py = self.designer_content.tab_pannel.list_py_code_inputs
            for code_input in list_py:
                if code_input.clicked is True:
                    code_input.clicked = False
                    code_input.do_cut()

    def action_btn_copy_pressed(self, *args):
        '''Event Handler when ActionButton "Copy" is pressed.
        '''

        if self._edit_selected == 'Play':
            self.ui_creator.playground.do_copy()

        elif self._edit_selected == 'KV':
            self.ui_creator.kv_code_input.do_copy()

        elif self._edit_selected == 'Py':
            list_py = self.designer_content.tab_pannel.list_py_code_inputs
            for code_input in list_py:
                if code_input.clicked is True:
                    code_input.clicked = False
                    code_input.do_copy()

    def action_btn_paste_pressed(self, *args):
        '''Event Handler when ActionButton "Paste" is pressed.
        '''

        if self._edit_selected == 'Play':
            self.ui_creator.playground.do_paste()

        elif self._edit_selected == 'KV':
            self.ui_creator.kv_code_input.do_paste()

        elif self._edit_selected == 'Py':
            list_py = self.designer_content.tab_pannel.list_py_code_inputs
            for code_input in list_py:
                if code_input.clicked is True:
                    code_input.clicked = False
                    code_input.do_paste()

    def action_btn_delete_pressed(self, *args):
        '''Event Handler when ActionButton "Delete" is pressed.
        '''

        if self._edit_selected == 'Play':
            self.ui_creator.playground.do_delete()

        elif self._edit_selected == 'KV':
            self.ui_creator.kv_code_input.do_delete()

        elif self._edit_selected == 'Py':
            list_py = self.designer_content.tab_pannel.list_py_code_inputs
            for code_input in list_py:
                if code_input.clicked is True:
                    code_input.clicked = False
                    code_input.do_delete()

    def action_btn_select_all_pressed(self, *args):
        '''Event Handler when ActionButton "Select All" is pressed.
        '''

        if self._edit_selected == 'Play':
            self.ui_creator.playground.do_select_all()

        elif self._edit_selected == 'KV':
            self.ui_creator.kv_code_input.do_select_all()

        elif self._edit_selected == 'Py':
            list_py = self.designer_content.tab_pannel.list_py_code_inputs
            for code_input in list_py:
                if code_input.clicked is True:
                    code_input.clicked = False
                    code_input.do_select_all()

    def action_btn_add_custom_widget_press(self, *args):
        '''Event Handler when ActionButton "Add Custom Widget" is pressed.
        '''

        self._custom_browser = FileBrowser(select_string='Add')
        self._custom_browser.bind(on_success=self._custom_browser_load,
                                  on_canceled=self._cancel_popup)

        self._popup = Popup(title="Add Custom Widget",
                            content=self._custom_browser,
                            size_hint=(0.9, 0.9),
                            auto_dismiss=False)
        self._popup.open()

    def _custom_browser_load(self, instance):
        '''Event Handler for 'on_success' event of self._custom_browser
        '''

        file_path = instance.selection[0]
        self._popup.dismiss()

        self.ui_creator.playground.sandbox.error_active = True

        with self.ui_creator.playground.sandbox:
            try:
                self.project_loader.add_custom_widget(file_path)

                self.designer_content.toolbox.cleanup()
                for _rule in (self.project_loader.custom_widgets):
                    widgets.append((_rule.name, 'custom'))

                self.designer_content.toolbox.add_custom()

            except ProjectLoaderException as e:
                self.statusbar.show_message('Cannot load widget. %s' % str(e))

        self.ui_creator.playground.sandbox.error_active = False

    def action_chk_btn_toolbox_active(self, chk_btn):
        '''Event Handler when ActionCheckButton "Toolbox" is activated.
        '''

        if chk_btn.checkbox.active:
            self._toolbox_parent.add_widget(
                self.designer_content.splitter_tree)
            self.designer_content.splitter_tree.width = self._toolbox_width

        else:
            self._toolbox_parent = self.designer_content.splitter_tree.parent
            self._toolbox_parent.remove_widget(
                self.designer_content.splitter_tree)
            self._toolbox_width = self.designer_content.splitter_tree.width
            self.designer_content.splitter_tree.width = 0

    def action_chk_btn_property_viewer_active(self, chk_btn):
        '''Event Handler when ActionCheckButton "Property Viewer" is activated.
        '''

        if chk_btn.checkbox.active:
            self._toggle_splitter_widget_tree()
            if self.ui_creator.splitter_widget_tree.parent is None:
                self._splitter_widget_tree_parent.add_widget(
                    self.ui_creator.splitter_widget_tree)
                self.ui_creator.splitter_widget_tree.width = \
                    self._splitter_widget_tree_width

            add_tree = False
            if self.ui_creator.grid_widget_tree.parent is not None:
                add_tree = True
                self.ui_creator.splitter_property.size_hint_y = None
                self.ui_creator.splitter_property.height = 300

            self._splitter_property_parent.clear_widgets()
            if add_tree:
                self._splitter_property_parent.add_widget(
                    self.ui_creator.grid_widget_tree)

            self._splitter_property_parent.add_widget(
                self.ui_creator.splitter_property)
        else:
            self._splitter_property_parent = \
                self.ui_creator.splitter_property.parent
            self._splitter_property_parent.remove_widget(
                self.ui_creator.splitter_property)
            self._toggle_splitter_widget_tree()

    def action_chk_btn_widget_tree_active(self, chk_btn):
        '''Event Handler when ActionCheckButton "Widget Tree" is activated.
        '''

        if chk_btn.checkbox.active:
            self._toggle_splitter_widget_tree()
            add_prop = False
            if self.ui_creator.splitter_property.parent is not None:
                add_prop = True

            self._grid_widget_tree_parent.clear_widgets()
            self._grid_widget_tree_parent.add_widget(
                self.ui_creator.grid_widget_tree)
            if add_prop:
                self._grid_widget_tree_parent.add_widget(
                    self.ui_creator.splitter_property)
                self.ui_creator.splitter_property.size_hint_y = None
                self.ui_creator.splitter_property.height = 300
        else:
            self._grid_widget_tree_parent = \
                self.ui_creator.grid_widget_tree.parent
            self._grid_widget_tree_parent.remove_widget(
                self.ui_creator.grid_widget_tree)
            self.ui_creator.splitter_property.size_hint_y = 1
            self._toggle_splitter_widget_tree()

    def _toggle_splitter_widget_tree(self):
        '''To show/hide splitter_widget_tree
        '''

        if self.ui_creator.splitter_widget_tree.parent is not None and\
                self.ui_creator.splitter_property.parent is None and\
                self.ui_creator.grid_widget_tree.parent is None:

            self._splitter_widget_tree_parent = \
                self.ui_creator.splitter_widget_tree.parent
            self._splitter_widget_tree_parent.remove_widget(
                self.ui_creator.splitter_widget_tree)
            self._splitter_widget_tree_width = \
                self.ui_creator.splitter_widget_tree.width
            self.ui_creator.splitter_widget_tree.width = 0

        elif self.ui_creator.splitter_widget_tree.parent is None:
            self._splitter_widget_tree_parent.add_widget(
                self.ui_creator.splitter_widget_tree)
            self.ui_creator.splitter_widget_tree.width = \
                self._splitter_widget_tree_width

    def action_chk_btn_status_bar_active(self, chk_btn):
        '''Event Handler when ActionCheckButton "StatusBar" is activated.
        '''

        if chk_btn.checkbox.active:
            self._statusbar_parent.add_widget(self.statusbar)
            self.statusbar.height = self._statusbar_height
        else:
            self._statusbar_parent = self.statusbar.parent
            self._statusbar_height = self.statusbar.height
            self._statusbar_parent.remove_widget(self.statusbar)
            self.statusbar.height = 0

    def action_chk_btn_kv_area_active(self, chk_btn):
        '''Event Handler when ActionCheckButton "KVLangArea" is activated.
        '''

        if chk_btn.checkbox.active:
            self.ui_creator.splitter_kv_code_input.height = \
                self._kv_area_height
            self._kv_area_parent.add_widget(
                self.ui_creator.splitter_kv_code_input)
        else:
            self._kv_area_parent = \
                self.ui_creator.splitter_kv_code_input.parent
            self._kv_area_height = \
                self.ui_creator.splitter_kv_code_input.height
            self.ui_creator.splitter_kv_code_input.height = 0
            self._kv_area_parent.remove_widget(
                self.ui_creator.splitter_kv_code_input)

    def _error_adding_file(self, *args):
        '''Event Handler for 'on_error' event of self._add_file_dlg
        '''

        self.statusbar.show_message('Error while adding file to project')
        self._popup.dismiss()

    def _added_file(self, *args):
        '''Event Handler for 'on_added' event of self._add_file_dlg
        '''

        self.statusbar.show_message('File successfully added to project')
        self._popup.dismiss()
        if self._add_file_dlg.target_file[3:] == '.py':
            self.designer_content.add_file_to_tree_view(
                self._add_file_dlg.target_file)

    def action_btn_add_file_pressed(self, *args):
        '''Event Handler when ActionButton "Add File" is pressed.
        '''

        self._add_file_dlg = AddFileDialog(self.project_loader)
        self._add_file_dlg.bind(on_added=self._added_file,
                                on_error=self._error_adding_file,
                                on_cancel=self._cancel_popup)

        self._popup = Popup(title="Add File",
                            content=self._add_file_dlg,
                            size_hint=(None, None),
                            size=(400, 300),
                            auto_dismiss=False)

        self._popup.open()

    def action_btn_project_pref_pressed(self, *args):
        '''Event Handler when ActionButton "Project Prefences" is pressed.
        '''
        self.proj_settings = ProjectSettings(proj_loader=self.project_loader)
        self.proj_settings.load_proj_settings()
        self.proj_settings.bind(on_close=self._cancel_popup)
        self._popup = Popup(title="Project Preferences",
                            content=self.proj_settings,
                            size_hint=(None, None),
                            size=(600, 400),
                            auto_dismiss=False)

        self._popup.open()

    def action_btn_run_project_pressed(self, *args):
        '''Event Handler when ActionButton "Run" is pressed.
        '''
        if self.project_loader.file_list == []:
            return
        args = ''
        envs = ''

        python_path = self.designer_settings.config_parser.getdefault(
            'global', 'python_shell_path', '')

        if python_path == '':
            self.statusbar.show_message("Python Shell Path not specified,"
                                        " please specify it before running"
                                        " project")
            return

        if self.proj_settings and self.proj_settings.config_parser:
            args = self.proj_settings.config_parser.getdefault(
                'arguments', 'arg', '')
            envs = self.proj_settings.config_parser.getdefault(
                'env variables', 'env', '')
            for env in envs.split(' '):
                self.ui_creator.kivy_console.environment[
                    env[:env.find('=')]] = env[env.find('=') + 1:]

        for _file in self.project_loader.file_list:
            if 'main.py' in os.path.basename(_file):
                self.ui_creator.kivy_console.stdin.write(
                    '%s %s %s' % (python_path, _file, args))
                self.ui_creator.tab_pannel.switch_to(
                    self.ui_creator.tab_pannel.tab_list[2])
                return

        self.ui_creator.kivy_console.stdin.write(
            '%s %s %s' % (python_path, self.project_loader._app_file, args))

        self.ui_creator.tab_pannel.switch_to(
            self.ui_creator.tab_pannel.tab_list[2])

    def on_sandbox_getting_exception(self, *args):
        '''Event Handler for
           :class:`~designer.uix.designer_sandbox.DesignerSandbox`
           on_getting_exception event. This function will add exception
           string in error_console.
        '''

        s = traceback.format_list(
            traceback.extract_tb(self.ui_creator.playground.sandbox.tb))
        s = '\n'.join(s)
        to_insert = "Exception:\n" + s + '\n' + \
            "{!r}".format(self.ui_creator.playground.sandbox.exception)
        text = self.ui_creator.error_console.text + to_insert + '\n\n'
        self.ui_creator.error_console.text = text
        if self.ui_creator.playground.sandbox.error_active:
            self.ui_creator.tab_pannel.switch_to(
                self.ui_creator.tab_pannel.tab_list[0])

        self.ui_creator.playground.sandbox.error_active = False

    def action_btn_about_pressed(self, *args):
        '''Event handler for 'on_release' event of DesignerActionButton
           "About Kivy Designer"
        '''
        self.about_dlg = AboutDialog()
        self._popup = Popup(title='About Kivy Designer',
                            content=self.about_dlg,
                            size_hint=(None, None),
                            size=(600, 400),
                            auto_dismiss=False)
        self._popup.open()
        self.about_dlg.bind(on_cancel=self._cancel_popup)
Esempio n. 21
0
class DesignerTools(EventDispatcher):

    designer = ObjectProperty()
    '''Instance of Designer
       :data:`designer` is a :class:`~kivy.properties.ObjectProperty`
    '''
    @ignore_proj_watcher
    def export_png(self):
        '''Export playground widget to png file.
        If there is a selected widget, export it.
        If not, export the root widget
        '''
        playground = self.designer.ui_creator.playground
        proj_dir = get_current_project().path
        status = self.designer.statusbar

        wdg = playground.selected_widget
        if wdg is None:
            wdg = playground.root

        name = datetime.datetime.now().strftime("%m-%d-%Y_%H-%M-%S.png")
        if wdg.id:
            name = wdg.id + '_' + name
        wdg.export_to_png(os.path.join(proj_dir, name))
        status.show_message('Image saved at ' + name, 5, 'info')

    def check_pep8(self):
        '''Check the PEP8 from current project
        '''
        proj_dir = get_current_project().path
        kd_dir = os.path.dirname(designer.__file__)
        kd_dir = os.path.split(kd_dir)[0]
        pep8_dir = os.path.join(kd_dir, 'tools', 'pep8checker', 'pep8kivy.py')

        python_path =\
            self.designer.designer_settings.config_parser.getdefault(
                'global',
                'python_shell_path',
                ''
            )

        if python_path == '':
            self.profiler.dispatch(
                'on_error', 'Python Shell Path not '
                'specified.'
                '\n\nUpdate it on \'File\' -> \'Settings\'')
            return

        cmd = '%s %s %s' % (python_path, pep8_dir, proj_dir)
        self.designer.ui_creator.tab_pannel.switch_to(
            self.designer.ui_creator.tab_pannel.tab_list[2])
        self.designer.ui_creator.kivy_console.run_command(cmd)

    def create_setup_py(self):
        '''Runs the GUI to create a setup.py file
        '''
        proj_dir = get_current_project().path
        designer_content = self.designer.designer_content

        setup_path = os.path.join(proj_dir, 'setup.py')
        if os.path.exists(setup_path):
            show_alert('Create setup.py', 'setup.py already exists!')
            return False

        content = ToolSetupPy(path=setup_path)
        self._popup = Popup(title='Create setup.py',
                            content=content,
                            size_hint=(None, None),
                            size=(550, 350),
                            auto_dismiss=False)
        content.bind(on_cancel=self._popup.dismiss)

        def on_create(*args):
            designer_content.update_tree_view(get_current_project())
            self._popup.dismiss()

        content.bind(on_create=on_create)
        self._popup.open()

    @ignore_proj_watcher
    def create_gitignore(self):
        '''Create .gitignore
        '''
        proj_dir = get_current_project().path
        status = self.designer.statusbar

        gitignore_path = os.path.join(proj_dir, '.gitignore')

        if os.path.exists(gitignore_path):
            show_alert('Create .gitignore', '.gitignore already exists!')
            return False

        gitignore = '''*.pyc
*.pyo
bin/
.designer/
.buildozer/
__pycache__/'''

        f = open(gitignore_path, 'w').write(gitignore)
        status.show_message('.gitignore created successfully', 5, 'info')

    def buildozer_init(self):
        '''Checks if the .spec exists or not; and when possible, calls
            _perform_buildozer_init
        '''

        proj_dir = get_current_project().path
        spec_file = os.path.join(proj_dir, 'buildozer.spec')

        if os.path.exists(spec_file):
            self._confirm_dlg = ConfirmationDialog(
                message='The buildozer.spec file already exist.'
                '\nDo you want to create a new spec?')
            self._popup = Popup(title='Buildozer init',
                                content=self._confirm_dlg,
                                size_hint=(None, None),
                                size=('250pt', '150pt'),
                                auto_dismiss=False)
            self._confirm_dlg.bind(on_ok=self._perform_buildozer_init,
                                   on_cancel=self._popup.dismiss)
            self._popup.open()
        else:
            self._perform_buildozer_init()

    @ignore_proj_watcher
    def _perform_buildozer_init(self, *args):
        '''Copies the spec from new_templates/default.spec to the project
        folder
        '''
        self._popup.dismiss()

        proj_dir = get_current_project().path
        spec_file = os.path.join(proj_dir, 'buildozer.spec')

        _dir = os.path.dirname(designer.__file__)
        _dir = os.path.split(_dir)[0]
        templates_dir = os.path.join(_dir, 'new_templates')
        shutil.copy(os.path.join(templates_dir, 'default.spec'), spec_file)

        self.designer.designer_content.update_tree_view(get_current_project())
Esempio n. 22
0
class Designer(FloatLayout):
    '''Designer is the Main Window class of Kivy Designer
       :data:`message` is a :class:`~kivy.properties.StringProperty`
    '''
    
    designer_console = ObjectProperty(None)
    '''Instance of :class:`designer.designer_console.ConsoleDialog`
    '''

    statusbar = ObjectProperty(None)
    '''Reference to the :class:`~designer.statusbar.StatusBar` instance.
       :data:`statusbar` is a :class:`~kivy.properties.ObjectProperty`
    '''

    editcontview = ObjectProperty(None)
    '''Reference to the :class:`~designer.uix.EditContView` instance.
       :data:`v` is a :class:`~kivy.properties.ObjectProperty`
    '''

    actionbar = ObjectProperty(None)
    '''Reference to the :class:`~kivy.actionbar.ActionBar` instance. 
       ActionBar is used as a MenuBar to display bunch of menu items.
       :data:`actionbar` is a :class:`~kivy.properties.ObjectProperty`
    '''

    undo_manager = ObjectProperty(UndoManager())
    '''Reference to the :class:`~designer.UndoManager` instance.
       :data:`undo_manager` is a :class:`~kivy.properties.ObjectProperty`
    '''

    project_watcher = ObjectProperty(None)
    '''Reference to the :class:`~designer.project_watcher.ProjectWatcher`.
       :data:`project_watcher` is a :class:`~kivy.properties.ObjectProperty`
    '''

    project_loader = ObjectProperty(None)
    '''Reference to the :class:`~designer.project_loader.ProjectLoader`.
       :data:`project_loader` is a :class:`~kivy.properties.ObjectProperty`
    '''
    
    proj_settings = ObjectProperty(None)
    '''Reference of :class:`~designer.project_settings.ProjectSettings`.
       :data:`proj_settings` is a :class:`~kivy.properties.ObjectProperty`
    '''

    _curr_proj_changed = BooleanProperty(False)
    '''Specifies whether current project has been changed inside Kivy Designer
       :data:`_curr_proj_changed` is a :class:`~kivy.properties.BooleanProperty`
    '''

    _proj_modified_outside = BooleanProperty(False)
    '''Specifies whether current project has been changed outside Kivy Designer
       :data:`_proj_modified_outside` is a :class:`~kivy.properties.BooleanProperty`
    '''

    ui_creator = ObjectProperty(None)
    '''Reference to :class:`~designer.ui_creator.UICreator` instance.
       :data:`ui_creator` is a :class:`~kivy.properties.ObjectProperty`
    '''

    designer_content = ObjectProperty(None)
    '''Reference to :class:`~designer.designer_content.DesignerContent` instance.
       :data:`designer_content` is a :class:`~kivy.properties.ObjectProperty`
    '''

    proj_tree_view = ObjectProperty(None)
    '''Reference to Project Tree instance
       :data:`proj_tree_view` is a :class:`~kivy.properties.ObjectProperty`
    '''

    designer_settings = ObjectProperty(None)
    '''Reference of :class:`~designer.designer_settings.DesignerSettings`.
       :data:`designer_settings` is a :class:`~kivy.properties.ObjectProperty`
    '''
    
    start_page = ObjectProperty(None)
    '''Reference of :class:`~designer.start_page.DesignerStartPage`.
       :data:`start_page` is a :class:`~kivy.properties.ObjectProperty`
    '''

    recent_files_cont_menu = ObjectProperty(None)
    '''The context sub menu, containing the recently opened/saved projects.
       Reference of :class:`~designer.uix.contextual.ContextSubMenu`.
       :data:`recent_files_cont_menu` is a :class:`~kivy.properties.ObjectProperty`
    '''

    def __init__(self, **kwargs):
        super(Designer, self).__init__(**kwargs)
        self.project_watcher = ProjectWatcher(self.project_modified)
        self.project_loader = ProjectLoader(self.project_watcher)
        self.recent_manager = RecentManager()
        self.widget_to_paste = None
        self.designer_content = DesignerContent(size_hint=(1, None))

        self.designer_settings = DesignerSettings()
        self.designer_settings.bind(on_config_change=self._config_change)
        self.designer_settings.load_settings()
        self.designer_settings.bind(on_close=self._cancel_popup)

        Clock.schedule_interval(self.project_loader.perform_auto_save,
                                int(self.designer_settings.config_parser.getdefault(
                                    'global', 'auto_save_time', 5))*60)

    def _config_change(self, *args):
        '''Event Handler for 'on_config_change' event of self.designer_settings.
        '''

        Clock.unschedule(self.project_loader.perform_auto_save)
        Clock.schedule_interval(self.project_loader.perform_auto_save,
                                int(self.designer_settings.config_parser.getdefault(
                                    'global', 'auto_save_time', 5))*60)

        self.ui_creator.kv_code_input.reload_kv = \
            bool(self.designer_settings.config_parser.getdefault(
                 'global', 'reload_kv', True))

        self.recent_manager.max_recent_files = \
            int(self.designer_settings.config_parser.getdefault(
                'global', 'num_recent_files', 5))

    def _add_designer_content(self):
        '''Add designer_content to Designer, when a project is loaded
        '''

        for _child in self.children[:]:
            if _child == self.designer_content:
                return

        self.remove_widget(self.start_page)
        self.add_widget(self.designer_content, 1)

        self.ids['actn_btn_save'].disabled = False
        self.ids['actn_btn_save_as'].disabled = False
        self.ids['actn_chk_proj_tree'].disabled = False
        self.ids['actn_chk_prop_event'].disabled = False
        self.ids['actn_chk_widget_tree'].disabled = False
        self.ids['actn_chk_status_bar'].disabled = False
        self.ids['actn_chk_kv_lang_area'].disabled = False
        self.ids['actn_btn_add_file'].disabled = False
        self.ids['actn_btn_custom_widget'].disabled = False
        self.ids['actn_btn_proj_pref'].disabled = False
        self.ids['actn_btn_run_proj'].disabled = False

    def on_statusbar_height(self, *args):
        '''Callback for statusbar.height
        '''

        self.designer_content.y = self.statusbar.height
        self.on_height(*args)

    def on_actionbar_height(self, *args):
        '''Callback for actionbar.height
        '''

        self.on_height(*args)
    
    def on_height(self, *args):
        '''Callback for self.height
        '''

        if self.actionbar and self.statusbar:
            self.designer_content.height = self.height - \
                self.actionbar.height - self.statusbar.height

            self.designer_content.y = self.statusbar.height

    def project_modified(self, *args):
        '''Event Handler called when Project is modified outside Kivy Designer
        '''

        #To dispatch modified event only once for all files/folders of proj_dir
        if self._proj_modified_outside:
            return

        self._confirm_dlg = ConfirmationDialog(message="Current Project has "
                                               "been modified\n"
                                               "outside the Kivy Designer.\n"
                                               "Do you want to reload project?")
        self._confirm_dlg.bind(on_ok=self._perform_reload,
                               on_cancel=self._cancel_popup)
        self._popup = Popup(title='Kivy Designer', content=self._confirm_dlg,
                            size_hint=(None, None),size=('200pt', '150pt'),
                            auto_dismiss=False)
        self._popup.open()

        self._proj_modified_outside = True
    
    def _perform_reload(self, *args):
        '''Perform reload of project after it is modified
        ''' 

        #Perform reload of project after it is modified
        self._popup.dismiss()
        self.project_watcher.allow_event_dispatch = False
        self._perform_open(self.project_loader.proj_dir)
        self.project_watcher.allow_event_dispatch = True
        self._proj_modified_outside = False

    def on_show_edit(self, *args):
        '''Event Handler of 'on_show_edit' event. This will show EditContView
           in ActionBar
        '''

        if isinstance(self.actionbar.children[0], EditContView):
            return
        
        if self.editcontview == None:
            self.editcontview = EditContView(
                on_undo=self.action_btn_undo_pressed,
                on_redo=self.action_btn_redo_pressed,
                on_cut=self.action_btn_cut_pressed,
                on_copy=self.action_btn_copy_pressed,
                on_paste=self.action_btn_paste_pressed,
                on_delete=self.action_btn_delete_pressed,
                on_selectall=self.action_btn_select_all_pressed,
                on_next_screen=self._next_screen,
                on_prev_screen=self._prev_screen)

        self.actionbar.add_widget(self.editcontview)
        
        widget = self.ui_creator.propertyviewer.widget

        if isinstance(widget, Carousel) or\
            isinstance(widget, ScreenManager) or\
            isinstance(widget, TabbedPanel):
            self.editcontview.show_action_btn_screen(True)
        else:
            self.editcontview.show_action_btn_screen(False)

        if self.ui_creator.kv_code_input.clicked:
            self._edit_selected = 'KV'
        elif self.ui_creator.playground.clicked:
            self._edit_selected = 'Play'
        else:
            self._edit_selected = 'Py'

        self.ui_creator.playground.clicked = False
        self.ui_creator.kv_code_input.clicked = False

    def _prev_screen(self, *args):
        widget = self.ui_creator.propertyviewer.widget
        if isinstance(widget, Carousel):
            widget.load_previous()

        elif isinstance(widget, ScreenManager):
            widget.current = widget.previous()
        
        elif isinstance(widget, TabbedPanel):
            index = widget.tab_list.index(widget.current_tab)
            if len(widget.tab_list) <= index + 1:
                return
            
            widget.switch_to(widget.tab_list[index + 1])
     
    def _next_screen(self, *args):
        widget = self.ui_creator.propertyviewer.widget
        if isinstance(widget, Carousel):
            widget.load_next()

        elif isinstance(widget, ScreenManager):
            widget.current = widget.next()

        elif isinstance(widget, TabbedPanel):
            index = widget.tab_list.index(widget.current_tab)
            if index == 0:
                return
            
            widget.switch_to(widget.tab_list[index - 1])
            

    def on_touch_down(self, touch):
        '''Override of FloatLayout.on_touch_down. Used to determine where
           touch is down and to call self.actionbar.on_previous
        '''

        if not isinstance(self.actionbar.children[0], EditContView) or\
           self.actionbar.collide_point(*touch.pos):
            return super(FloatLayout, self).on_touch_down(touch)

        self.actionbar.on_previous(self)
        
        return super(FloatLayout, self).on_touch_down(touch)  

    def action_btn_new_pressed(self, *args):
        '''Event Handler when ActionButton "New" is pressed.
        '''

        if not self._curr_proj_changed:
            self._show_new_dialog()
            return

        self._confirm_dlg = ConfirmationDialog('All unsaved changes will be'
                                               ' lost.\n'
                                               'Do you want to continue?')
        self._confirm_dlg.bind(on_ok=self._show_new_dialog,
                               on_cancel=self._cancel_popup)

        self._popup = Popup(title='New', content = self._confirm_dlg, 
                            size_hint=(None,None),size=('200pt', '150pt'),
                            auto_dismiss=False)
        self._popup.open()
    
    def _show_new_dialog(self, *args):
        if hasattr(self, '_popup'):
            self._popup.dismiss()
        
        self._new_dialog = NewProjectDialog()
        self._new_dialog.bind(on_select=self._perform_new,
                               on_cancel=self._cancel_popup)
        self._popup = Popup(title='New Project', content = self._new_dialog, 
                            size_hint=(None,None),size=('650pt', '450pt'),
                            auto_dismiss=False)
        self._popup.open()

    def _perform_new(self, *args):
        '''To load new project
        '''

        if hasattr(self, '_popup'):
            self._popup.dismiss()
        
        self.cleanup()
        new_proj_dir = os.path.join(get_kivy_designer_dir(),
                                    NEW_PROJECT_DIR_NAME)
        if os.path.exists(new_proj_dir):
            shutil.rmtree(new_proj_dir)
        
        os.mkdir(new_proj_dir)
        
        template = self._new_dialog.adapter.selection[0].text
        kv_file = NEW_PROJECTS[template][0]
        py_file = NEW_PROJECTS[template][1]

        templates_dir = os.path.join(os.getcwd(), NEW_TEMPLATES_DIR)
        shutil.copy(os.path.join(templates_dir, py_file),
                    os.path.join(new_proj_dir, "main.py"))

        shutil.copy(os.path.join(templates_dir, kv_file),
                    os.path.join(new_proj_dir, "main.kv"))
        
        self.ui_creator.playground.sandbox.error_active = True
        with self.ui_creator.playground.sandbox:
            self.project_loader.load_new_project(os.path.join(new_proj_dir, 
                                                              "main.kv"))
            root_wigdet = self.project_loader.get_root_widget()
            self.ui_creator.playground.add_widget_to_parent(root_wigdet, None,
                                                            from_undo=True)
            self.ui_creator.kv_code_input.text = self.project_loader.get_full_str()
            self.designer_content.update_tree_view(self.project_loader)
            self._add_designer_content()
            if self.project_loader.class_rules:
                for i, _rule in enumerate(self.project_loader.class_rules):
                    widgets.append((_rule.name, 'custom'))

                self.designer_content.toolbox.add_custom()
        
        self.ui_creator.playground.sandbox.error_active = False

    def cleanup(self):
        '''To cleanup everything loaded by the current project before loading
           another project.
        '''

        self.project_loader.cleanup()
        self.ui_creator.cleanup()
        self.undo_manager.cleanup()
        self.designer_content.toolbox.cleanup()

        for node in self.proj_tree_view.root.nodes[:]:
            self.proj_tree_view.remove_node(node)

        for widget in widgets[:]:
            if widget[1] == 'custom':
                widgets.remove(widget)

        self._curr_proj_changed = False
        self.ui_creator.kv_code_input.text = ""

        self.designer_content.tab_pannel.list_py_code_inputs = []
        for th in self.designer_content.tab_pannel.tab_list[:-1]:
            self.designer_content.tab_pannel.remove_widget(th)

    def action_btn_open_pressed(self, *args):
        '''Event Handler when ActionButton "Open" is pressed.
        '''

        if not self._curr_proj_changed:
            self._show_open_dialog()
            return

        self._confirm_dlg = ConfirmationDialog('All unsaved changes will be '
                                                'lost.\n'
                                                'Do you want to continue?')

        self._confirm_dlg.bind(on_ok=self._show_open_dialog,
                               on_cancel=self._cancel_popup)

        self._popup = Popup(title='Kivy Designer', content = self._confirm_dlg, 
                            size_hint=(None,None),size=('200pt', '150pt'),
                            auto_dismiss=False)
        self._popup.open()

    def _show_open_dialog(self, *args):
        '''To show FileBrowser to "Open" a project
        '''

        if hasattr(self, '_popup'):
            self._popup.dismiss()

        self._fbrowser = FileBrowser(select_string='Open')

        def_path = os.getcwd() 
        if not self.project_loader.new_project and self.project_loader.proj_dir:
            def_path = self.project_loader.proj_dir            

        if self._fbrowser.ids.tabbed_browser.current_tab.text == 'List View':
            self._fbrowser.ids.list_view.path = def_path
        else:
            self._fbrowser.ids.icon_view.path = def_path

        self._fbrowser.bind(on_success=self._fbrowser_load,
                            on_canceled=self._cancel_popup)

        self._popup = Popup(title="Open", content = self._fbrowser,
                            size_hint=(0.9, 0.9), auto_dismiss=False)
        self._popup.open()
    
    def _select_class_selected(self, *args):
        '''Event Handler for 'on_select' event of self._select_class
        '''

        selection = self._select_class.listview.adapter.selection[0].text

        with self.ui_creator.playground.sandbox:
            root_widget = self.project_loader.set_root_widget(selection)
            self.ui_creator.playground.add_widget_to_parent(root_widget, None, from_undo=True)
            self.ui_creator.kv_code_input.text = self.project_loader.get_root_str()

        self._select_class_popup.dismiss()
    
    def _select_class_cancel(self, *args):
        '''Event Handler for 'on_cancel' event of self._select_class
        '''

        self._select_class_popup.dismiss()

    def _fbrowser_load(self, instance):
        '''Event Handler for 'on_load' event of self._fbrowser
        '''
        if instance.selection == []:
            return

        file_path = instance.selection[0]
        self._popup.dismiss()
        self._perform_open(file_path)

    def _perform_open(self, file_path):
        '''To open a project given by file_path
        '''

        for widget in widgets[:]:
            if widget[1] == 'custom':
                widgets.remove(widget)

        self.cleanup()

        self.ui_creator.playground.sandbox.error_active = True

        root_widget = None

        with self.ui_creator.playground.sandbox:
            try:
                self.project_loader.load_project(file_path)

                if self.project_loader.class_rules:
                    for i, _rule in enumerate(self.project_loader.class_rules):
                        widgets.append((_rule.name, 'custom'))

                    self.designer_content.toolbox.add_custom()

                #to test listview
                #root_wigdet = None
                root_wigdet = self.project_loader.get_root_widget()

                if not root_wigdet:
                    #Show list box showing widgets
                    self._select_class = SelectClass(
                        self.project_loader.class_rules)
    
                    self._select_class.bind(on_select=self._select_class_selected,
                                            on_cancel=self._select_class_cancel)
    
                    self._select_class_popup = Popup(title="Select Root Widget",
                                                     content = self._select_class,
                                                     size_hint=(0.5, 0.5),
                                                     auto_dismiss=False)
                    self._select_class_popup.open()

                else:
                    self.ui_creator.playground.add_widget_to_parent(root_wigdet,
                                                                    None,
                                                                    from_undo=True)
                    self.ui_creator.kv_code_input.text = self.project_loader.get_full_str()

                self.recent_manager.add_file(file_path)
                #Record everything for later use
                self.project_loader.record()
                self.designer_content.update_tree_view(self.project_loader)
                self._add_designer_content()

            except Exception as e:
                self.statusbar.show_message('Cannot load Project: %s'%(str(e)))
        
        self.ui_creator.playground.sandbox.error_active = False

    def _cancel_popup(self, *args):
        '''EventHandler for all self._popup when self._popup.content
           emits 'on_cancel' or equivalent.
        '''

        self._proj_modified_outside = False
        self._popup.dismiss()

    def action_btn_save_pressed(self, *args):
        '''Event Handler when ActionButton "Save" is pressed.
        '''

        if self.project_loader.root_rule:
            try:
                if self.project_loader.new_project:
                    self.action_btn_save_as_pressed()
                    return

                else:
                    self.project_loader.save_project()
                    projdir = self.project_loader.proj_dir
                    self.project_loader.cleanup(stop_watcher=False)
                    self.ui_creator.playground.cleanup()
                    self.project_loader.load_project(projdir)
                    root_wigdet = self.project_loader.get_root_widget()
                    self.ui_creator.playground.add_widget_to_parent(root_wigdet,
                                                                    None,
                                                                    from_undo=True,
                                                                    from_kv=True)
                    

                self._curr_proj_changed = False
                self.statusbar.show_message('Project saved successfully')

            except:
                self.statusbar.show_message('Cannot save project')

    def action_btn_save_as_pressed(self, *args):
        '''Event Handler when ActionButton "Save As" is pressed.
        '''

        if self.project_loader.root_rule:
            self._curr_proj_changed = False

            self._save_as_browser = FileBrowser(select_string='Save')

            def_path = os.getcwd() 
            if not self.project_loader.new_project and self.project_loader.proj_dir:
                def_path = self.project_loader.proj_dir

            if self._save_as_browser.ids.tabbed_browser.current_tab.text == 'List View':
                self._save_as_browser.ids.list_view.path = def_path
            else:
                self._save_as_browser.ids.icon_view.path = def_path

            self._save_as_browser.bind(on_success=self._perform_save_as,
                                       on_canceled=self._cancel_popup)
    
            self._popup = Popup(title="Enter Folder Name",
                                content = self._save_as_browser,
                                size_hint=(0.9, 0.9), auto_dismiss=False)
            self._popup.open()

    def _perform_save_as(self, instance):
        '''Event handler for 'on_success' event of self._save_as_browser
        '''

        if hasattr(self, '_popup'):
            self._popup.dismiss()

        proj_dir = ''
        if instance.ids.tabbed_browser.current_tab.text == 'List View':
            proj_dir = instance.ids.list_view.path
        else:
            proj_dir = instance.ids.icon_view.path

        proj_dir = os.path.join(proj_dir, instance.filename)
        #try:
        if True:
            self.project_loader.save_project(proj_dir)
            self.recent_manager.add_file(proj_dir)
            projdir = self.project_loader.proj_dir
            self.project_loader.cleanup()
            self.ui_creator.playground.cleanup()
            self.project_loader.load_project(projdir)
            root_wigdet = self.project_loader.get_root_widget()
            self.ui_creator.playground.add_widget_to_parent(root_wigdet,
                                                            None,
                                                            from_undo=True)
            self.statusbar.show_message('Project saved successfully')

        #except:
        #    self.statusbar.show_message('Cannot save project')
    
    def action_btn_settings_pressed(self, *args):
        self.designer_settings.parent = None
        self._popup = Popup(title="Kivy Designer Settings",
                            content = self.designer_settings,
                            size_hint=(None, None), 
                            size=(600, 400), auto_dismiss=False)

        self._popup.open()

    def action_btn_recent_files_pressed(self, *args):
        '''Event Handler when ActionButton "Recent Files" is pressed.
        '''
        pass
    
    def fill_recent_menu(self, *args):
        recent_menu = self.recent_files_cont_menu
        for _file in self.recent_manager.list_files:
            act_btn = DesignerActionButton(text=_file, shorten=True)
            recent_menu.add_widget(act_btn)
            act_btn.bind(on_release=self._recent_file_release)

    def _recent_file_release(self, instance, *args):
        '''Event Handler for 'on_select' event of self._recent_dlg.
        '''
        self._perform_open(instance.text)

    def action_btn_quit_pressed(self, *args):
        '''Event Handler when ActionButton "Quit" is pressed.
        '''

        App.get_running_app().stop()

    def action_btn_undo_pressed(self, *args):
        '''Event Handler when ActionButton "Undo" is pressed.
        '''

        if self._edit_selected == 'Play':
            self.undo_manager.do_undo()
        elif self._edit_selected == 'KV':
            self.ui_creator.kv_code_input.do_undo()
        elif self._edit_selected == 'Py':
            for code_input in self.designer_content.tab_pannel.list_py_code_inputs:
                if code_input.clicked == True:
                    code_input.clicked = False
                    code_input.do_undo()

    def action_btn_redo_pressed(self, *args):
        '''Event Handler when ActionButton "Redo" is pressed.
        '''

        if self._edit_selected == 'Play':
            self.undo_manager.do_redo()
        elif self._edit_selected == 'KV':
            self.ui_creator.kv_code_input.do_redo()
        elif self._edit_selected == 'Py':
            for code_input in self.designer_content.tab_pannel.list_py_code_inputs:
                if code_input.clicked == True:
                    code_input.clicked = False
                    code_input.do_redo()

    def action_btn_cut_pressed(self, *args):
        '''Event Handler when ActionButton "Cut" is pressed.
        '''

        if self._edit_selected == 'Play':
            self.ui_creator.playground.do_cut()

        elif self._edit_selected == 'KV':
            self.ui_creator.kv_code_input.do_cut()

        elif self._edit_selected == 'Py':
            for code_input in self.designer_content.tab_pannel.list_py_code_inputs:
                if code_input.clicked == True:
                    code_input.clicked = False
                    code_input.do_cut()

    def action_btn_copy_pressed(self, *args):
        '''Event Handler when ActionButton "Copy" is pressed.
        '''

        if self._edit_selected == 'Play':
            self.ui_creator.playground.do_copy()
         
        elif self._edit_selected == 'KV':
            self.ui_creator.kv_code_input.do_copy()

        elif self._edit_selected == 'Py':
            for code_input in self.designer_content.tab_pannel.list_py_code_inputs:
                if code_input.clicked == True:
                    code_input.clicked = False
                    code_input.do_copy()
        
    def action_btn_paste_pressed(self, *args):
        '''Event Handler when ActionButton "Paste" is pressed.
        '''

        if self._edit_selected == 'Play':
            self.ui_creator.playground.do_paste()

        elif self._edit_selected == 'KV':
            self.ui_creator.kv_code_input.do_paste()

        elif self._edit_selected == 'Py':
            for code_input in self.designer_content.tab_pannel.list_py_code_inputs:
                if code_input.clicked == True:
                    code_input.clicked = False
                    code_input.do_paste()

    def action_btn_delete_pressed(self, *args):
        '''Event Handler when ActionButton "Delete" is pressed.
        '''

        if self._edit_selected == 'Play':
            self.ui_creator.playground.do_delete()

        elif self._edit_selected == 'KV':
            self.ui_creator.kv_code_input.do_delete()

        elif self._edit_selected == 'Py':
            for code_input in self.designer_content.tab_pannel.list_py_code_inputs:
                if code_input.clicked == True:
                    code_input.clicked = False
                    code_input.do_delete()

    def action_btn_select_all_pressed(self, *args):
        '''Event Handler when ActionButton "Select All" is pressed.
        '''

        if self._edit_selected == 'Play':
            self.ui_creator.playground.do_select_all()

        elif self._edit_selected == 'KV':
            self.ui_creator.kv_code_input.do_select_all()

        elif self._edit_selected == 'Py':
            for code_input in self.designer_content.tab_pannel.list_py_code_inputs:
                if code_input.clicked == True:
                    code_input.clicked = False
                    code_input.do_select_all()

    def action_btn_add_custom_widget_press(self, *args):
        '''Event Handler when ActionButton "Add Custom Widget" is pressed.
        '''

        self._custom_browser = FileBrowser(select_string='Add')
        self._custom_browser.bind(on_success=self._custom_browser_load,
                                  on_canceled=self._cancel_popup)

        self._popup = Popup(title="Add Custom Widget",
                            content = self._custom_browser,
                            size_hint=(0.9, 0.9), auto_dismiss=False)
        self._popup.open()

    def _custom_browser_load(self, instance):
        '''Event Handler for 'on_success' event of self._custom_browser
        '''

        file_path = instance.selection[0]
        self._popup.dismiss()
        
        self.ui_creator.playground.sandbox.error_active = True

        with self.ui_creator.playground.sandbox:
            try:
                self.project_loader.add_custom_widget(file_path)

                self.designer_content.toolbox.cleanup()
                for _rule in (self.project_loader.custom_widgets):
                    widgets.append((_rule.name, 'custom'))

                self.designer_content.toolbox.add_custom()

            except ProjectLoaderException as e:
                self.statusbar.show_message('Cannot load widget. %s'%str(e))
        
        self.ui_creator.playground.sandbox.error_active = False

    def action_chk_btn_toolbox_active(self, chk_btn):
        '''Event Handler when ActionCheckButton "Toolbox" is activated.
        '''

        if chk_btn.checkbox.active:
            self._toolbox_parent.add_widget(self.designer_content.splitter_tree)
            self.designer_content.splitter_tree.width = self._toolbox_width

        else:
            self._toolbox_parent = self.designer_content.splitter_tree.parent
            self._toolbox_parent.remove_widget(self.designer_content.splitter_tree)
            self._toolbox_width = self.designer_content.splitter_tree.width
            self.designer_content.splitter_tree.width = 0

    def action_chk_btn_property_viewer_active(self, chk_btn):
        '''Event Handler when ActionCheckButton "Property Viewer" is activated.
        '''

        if chk_btn.checkbox.active:
            self._toggle_splitter_widget_tree()
            if self.ui_creator.splitter_widget_tree.parent is None:
                self._splitter_widget_tree_parent.add_widget(self.ui_creator.splitter_widget_tree)
                self.ui_creator.splitter_widget_tree.width = self._splitter_widget_tree_width

            add_tree = False
            if self.ui_creator.grid_widget_tree.parent is not None:
                add_tree = True
                self.ui_creator.splitter_property.size_hint_y = None
                self.ui_creator.splitter_property.height = 300

            self._splitter_property_parent.clear_widgets()
            if add_tree:
                self._splitter_property_parent.add_widget(self.ui_creator.grid_widget_tree)

            self._splitter_property_parent.add_widget(self.ui_creator.splitter_property)
        else:
            self._splitter_property_parent = self.ui_creator.splitter_property.parent
            self._splitter_property_parent.remove_widget(self.ui_creator.splitter_property)
            self._toggle_splitter_widget_tree()

    def action_chk_btn_widget_tree_active(self, chk_btn):
        '''Event Handler when ActionCheckButton "Widget Tree" is activated.
        '''

        if chk_btn.checkbox.active:
            self._toggle_splitter_widget_tree()
            add_prop = False
            if self.ui_creator.splitter_property.parent is not None:
                add_prop = True

            self._grid_widget_tree_parent.clear_widgets()
            self._grid_widget_tree_parent.add_widget(self.ui_creator.grid_widget_tree)
            if add_prop:
                self._grid_widget_tree_parent.add_widget(self.ui_creator.splitter_property)
                self.ui_creator.splitter_property.size_hint_y = None
                self.ui_creator.splitter_property.height = 300
        else:
            self._grid_widget_tree_parent = self.ui_creator.grid_widget_tree.parent
            self._grid_widget_tree_parent.remove_widget(self.ui_creator.grid_widget_tree)
            self.ui_creator.splitter_property.size_hint_y = 1
            self._toggle_splitter_widget_tree()

    def _toggle_splitter_widget_tree(self):
        '''To show/hide splitter_widget_tree
        '''

        if self.ui_creator.splitter_widget_tree.parent is not None and\
            self.ui_creator.splitter_property.parent is None and\
            self.ui_creator.grid_widget_tree.parent is None:

            self._splitter_widget_tree_parent = self.ui_creator.splitter_widget_tree.parent
            self._splitter_widget_tree_parent.remove_widget(self.ui_creator.splitter_widget_tree)
            self._splitter_widget_tree_width = self.ui_creator.splitter_widget_tree.width
            self.ui_creator.splitter_widget_tree.width = 0

        elif self.ui_creator.splitter_widget_tree.parent is None:
            self._splitter_widget_tree_parent.add_widget(self.ui_creator.splitter_widget_tree)
            self.ui_creator.splitter_widget_tree.width = self._splitter_widget_tree_width

    def action_chk_btn_status_bar_active(self, chk_btn):
        '''Event Handler when ActionCheckButton "StatusBar" is activated.
        '''

        if chk_btn.checkbox.active:
            self._statusbar_parent.add_widget(self.statusbar)
            self.statusbar.height = self._statusbar_height
        else:
            self._statusbar_parent = self.statusbar.parent
            self._statusbar_height = self.statusbar.height
            self._statusbar_parent.remove_widget(self.statusbar)
            self.statusbar.height = 0
    
    def action_chk_btn_kv_area_active(self, chk_btn):
        '''Event Handler when ActionCheckButton "KVLangArea" is activated.
        '''

        if chk_btn.checkbox.active:
            self.ui_creator.splitter_kv_code_input.height = self._kv_area_height
            self._kv_area_parent.add_widget(self.ui_creator.splitter_kv_code_input)
        else:
            self._kv_area_parent = self.ui_creator.splitter_kv_code_input.parent
            self._kv_area_height = self.ui_creator.splitter_kv_code_input.height
            self.ui_creator.splitter_kv_code_input.height = 0
            self._kv_area_parent.remove_widget(self.ui_creator.splitter_kv_code_input)

    def _error_adding_file(self, *args):
        '''Event Handler for 'on_error' event of self._add_file_dlg
        '''

        self.statusbar.show_message('Error while adding file to project')
        self._popup.dismiss()
    
    def _added_file(self, *args):
        '''Event Handler for 'on_added' event of self._add_file_dlg
        '''

        self.statusbar.show_message('File successfully added to project')
        self._popup.dismiss()
        if self._add_file_dlg.target_file[3:] == '.py':
            self.designer_content.add_file_to_tree_view(
                self._add_file_dlg.target_file)

    def action_btn_add_file_pressed(self, *args):
        '''Event Handler when ActionButton "Add File" is pressed.
        '''

        self._add_file_dlg = AddFileDialog(self.project_loader)
        self._add_file_dlg.bind(on_added=self._added_file,
                                on_error=self._error_adding_file,
                                on_cancel=self._cancel_popup)

        self._popup = Popup(title="Add File",
                            content = self._add_file_dlg,
                            size_hint=(None, None), 
                            size=(400, 300), auto_dismiss=False)

        self._popup.open()
    
    def action_btn_project_pref_pressed(self, *args):
        '''Event Handler when ActionButton "Project Prefences" is pressed.
        '''
        self.proj_settings = ProjectSettings(proj_loader=self.project_loader)
        self.proj_settings.load_proj_settings()
        self.proj_settings.bind(on_close=self._cancel_popup)
        self._popup = Popup(title="Project Preferences",
                            content = self.proj_settings,
                            size_hint=(None, None), 
                            size=(600, 400), auto_dismiss=False)

        self._popup.open()

    def action_btn_run_project_pressed(self, *args):
        '''Event Handler when ActionButton "Run" is pressed.
        '''
        if self.project_loader.file_list == []:
            return
        args = ''
        envs = ''
        
        python_path = self.designer_settings.config_parser.getdefault(
            'global', 'python_shell_path', '')
        
        if python_path == '':
            self.statusbar.show_message("Python Shell Path not specified,"
                                        " please specify it before running"
                                        " project")
            return

        if self.proj_settings and self.proj_settings.config_parser:
            args = self.proj_settings.config_parser.getdefault('arguments', 'arg', '')
            envs = self.proj_settings.config_parser.getdefault('env variables', 'env', '')
            for env in envs.split(' '):
                self.ui_creator.kivy_console.environment[env[:env.find('=')]] = env[env.find('=')+1:]

        for _file in self.project_loader.file_list:
            if 'main.py' in os.path.basename(_file):
                self.ui_creator.kivy_console.stdin.write('%s %s %s'%
                                                         (python_path,
                                                          _file, args))
                self.ui_creator.tab_pannel.switch_to(
                    self.ui_creator.tab_pannel.tab_list[2])
                return

        self.ui_creator.kivy_console.stdin.write('%s %s %s'%
                                                 (python_path, 
                                                  self.project_loader._app_file,
                                                  args))
        self.ui_creator.tab_pannel.switch_to(
            self.ui_creator.tab_pannel.tab_list[2])

    def on_sandbox_getting_exception(self, *args):
        '''Event Handler for 
           :class:`~designer.uix.designer_sandbox.DesignerSandbox`
           on_getting_exception event. This function will add exception 
           string in error_console.
        '''

        s = traceback.format_list(traceback.extract_tb(
            self.ui_creator.playground.sandbox.tb))
        s = '\n'.join(s)
        to_insert = "Exception:\n" + s + '\n' + \
            "{!r}".format(self.ui_creator.playground.sandbox.exception)
        text = self.ui_creator.error_console.text + to_insert + '\n\n'
        self.ui_creator.error_console.text = text
        if self.ui_creator.playground.sandbox.error_active:
            self.ui_creator.tab_pannel.switch_to(
                self.ui_creator.tab_pannel.tab_list[0])
        
        self.ui_creator.playground.sandbox.error_active = False
Esempio n. 23
0
class Buildozer(Builder):
    '''Class to handle Buildozer builder
    '''

    def __init__(self, profiler):
        super(Buildozer, self).__init__(profiler)
        self.buildozer_path = ''

    def _initialize(self):
        '''Try to get the buildozer path and check required variables
        If there is something wrong shows an alert.
        '''

        # first, check if buildozer is set
        self.buildozer_path = self.designer_settings.config_parser.getdefault(
            'buildozer',
            'buildozer_path',
            ''
        )

        if self.buildozer_path == '':
            self.profiler.dispatch('on_error', 'Buildozer Path not specified.'
                                '\n\nUpdate it on \'File\' -> \'Settings\'')
            self.can_run = False
            return

        envs = self.proj_settings.config_parser.getdefault(
            'env variables',
            'env',
            ''
        )

        for env in envs.split(' '):
            self.ui_creator.kivy_console.environment[
                env[:env.find('=')]] = env[env.find('=') + 1:]

        # check if buildozer.spec exists
        if not os.path.isfile(os.path.join(self.profiler.project_path,
                                           'buildozer.spec')):
            self._confirm_dlg = ConfirmationDialog(
                message='buildozer.spec not found.\n'
                            'Do you want to create it now?')
            self._popup = Popup(title='Buildozer', content=self._confirm_dlg,
                                size_hint=(None, None), size=('200pt', '150pt'),
                                auto_dismiss=False)
            self._confirm_dlg.bind(on_ok=self._perform_create_spec,
                                   on_cancel=self._popup.dismiss)
            self._popup.open()
            self.can_run = False
            return

        # TODO check if buildozer source.dir and main file exists

        self.can_run = True

    def _perform_create_spec(self, *args):
        '''Creates the default buildozer.spec file
        '''
        _dir = os.path.dirname(designer.__file__)
        _dir = os.path.split(_dir)[0]
        templates_dir = os.path.join(_dir, 'new_templates')
        shutil.copy(os.path.join(templates_dir, 'default.spec'),
                    os.path.join(self.profiler.project_path, 'buildozer.spec'))

        self.designer.designer_content.update_tree_view(get_current_project())
        self._popup.dismiss()
        self.last_command()

    def _create_command(self, extra):
        '''Generate the buildozer command
        '''
        self.project_watcher.pause_watching()
        self._initialize()
        self.ui_creator.tab_pannel.switch_to(
            self.ui_creator.tab_pannel.tab_list[2])

        cd = 'cd ' + self.profiler.project_path
        args = []
        args.append(self.buildozer_path)
        if self.profiler.pro_verbose:
            args.append('--verbose')
        args.append(self.profiler.pro_target.lower())  # android or ios
        args += extra

        return [cd, " ".join(args)]

    def build(self, *args):
        '''Build the Buildozer project.
        Will read the necessary information from the profile and build the app
        '''
        build_mode = self.profiler.pro_mode.lower()
        cmd = self._create_command([build_mode])
        if not self.can_run:
            self.last_command = self.build
            return
        self.run_command(cmd)

        self.profiler.dispatch('on_message', 'Building project...')
        self.ui_creator.kivy_console.bind(on_command_list_done=self.on_build)

    def rebuild(self, *args):
        '''Update project dependencies, and build it again
        '''
        self.clean()
        self.profiler.bind(on_clean=self._rebuild)

    def _rebuild(self, *args):
        '''Perform the project rebuild
        '''
        cmd = self._create_command(['update'])
        if not self.can_run:
            self.last_command = self.rebuild
            return
        self.run_command(cmd)

        self.profiler.dispatch('on_message',
                               'Updating project dependencies...')
        self.ui_creator.kivy_console.bind(on_command_list_done=self.build)

    def run(self, *args, **kwargs):
        '''Run the build command and then run the application on the device
        '''
        self.build()
        if not self.can_run:
            self.last_command = self.run
            return
        if not self.profiler.pro_install:
            self.profiler.bind(on_build=self.deploy)
        self.profiler.bind(on_deploy=self._run)

    def _run(self, *args):
        '''Perform the buildozer run
        '''
        cmds = ['run']
        if self.profiler.pro_debug and self.profiler.pro_target == 'Android':
            cmds.append('logcat')
        cmd = self._create_command(cmds)
        if not self.can_run:
            return
        self.run_command(cmd)

        self.profiler.dispatch('on_message', 'Running on device...')
        self.ui_creator.kivy_console.bind(on_command_list_done=self.on_run)

    def deploy(self, *args):
        '''Perform the buildozer deploy
        '''
        cmd = self._create_command(['deploy'])
        if not self.can_run:
            return
        self.run_command(cmd)

        self.profiler.dispatch('on_message', 'Installing on device...')
        self.ui_creator.kivy_console.bind(on_command_list_done=self.on_deploy)

    def clean(self, *args):
        '''Clean the project directory
        '''
        cmd = self._create_command(['clean'])
        if not self.can_run:
            self.last_command = self.clean
            return
        self.run_command(cmd)

        self.profiler.dispatch('on_message', 'Cleaning project...')
        self.ui_creator.kivy_console.bind(on_command_list_done=self.on_clean)

    def on_clean(self, *args):
        '''on_clean event handler
        '''
        self.ui_creator.kivy_console.unbind(on_command_list_done=self.on_clean)

        self.project_watcher.resume_watching(delay=0)

        self.profiler.dispatch('on_message', 'Project clean', 5)
        self.profiler.dispatch('on_clean')

    def on_build(self, *args):
        '''on_build event handler
        '''
        self.ui_creator.kivy_console.unbind(on_command_list_done=self.on_build)

        self.project_watcher.resume_watching(delay=0)

        self.profiler.dispatch('on_message', 'Build complete', 5)
        self.profiler.dispatch('on_build')

        if self.profiler.pro_install:
            self.deploy()

    def on_deploy(self, *args):
        '''on_build event handler
        '''
        self.ui_creator.kivy_console.unbind(on_command_list_done=self.on_deploy)

        self.project_watcher.resume_watching(delay=0)

        self.profiler.dispatch('on_message', 'Installed on device', 5)
        self.profiler.dispatch('on_deploy')

    def on_stop(self, *args):
        '''on_stop event handler
        '''
        self.ui_creator.kivy_console.unbind(on_command_list_done=self.on_stop)

        self.profiler.dispatch('on_stop')

    def on_run(self, *args):
        '''on_run event handler
        '''
        self.ui_creator.kivy_console.unbind(on_command_list_done=self.on_run)

        self.project_watcher.resume_watching(delay=0)

        self.profiler.dispatch('on_message', '', 1)
        self.profiler.dispatch('on_run')
        self.designer.ids.actn_btn_stop_proj.disabled = True
Esempio n. 24
0
class Desktop(Builder):
    '''Class to handle Desktop builder
    '''

    def __init__(self, profiler):
        super(Desktop, self).__init__(profiler)
        self.python_path = ''
        self.args = ''
        # TODO check if buildozer source.dir and main file is set, if so
        # use this file

    def _get_python(self):
        '''Initialize python variables
        If there is something wrong shows an alert
        '''
        self.python_path = self.designer_settings.config_parser.getdefault(
            'global',
            'python_shell_path',
            ''
        )

        if self.python_path == '':
            self.profiler.dispatch('on_error', 'Python Shell Path not '
                                   'specified.'
                                   '\n\nUpdate it on \'File\' -> \'Settings\'')
            self.can_run = False
            return

        self.args = self.proj_settings.config_parser.getdefault(
            'arguments',
            'arg',
            ''
        )

        envs = self.proj_settings.config_parser.getdefault(
            'env variables',
            'env',
            ''
        )

        for env in envs.split(' '):
            self.ui_creator.kivy_console.environment[
                env[:env.find('=')]] = env[env.find('=') + 1:]

        self.can_run = True

    def _perform_kill_run(self, *args):
        '''Stop the running project/command and then run the project
        '''
        self._popup.dismiss()
        self.stop()
        Clock.schedule_once(self.run)

    def run(self, *args, **kwargs):
        '''Run the project using Python
        '''
        mod = kwargs.get('mod', '')
        data = kwargs.get('data', [])

        self._get_python()
        if not self.can_run:
            return

        py_main = os.path.join(self.profiler.project_path, 'main.py')

        if not os.path.isfile(py_main):
            self.profiler.dispatch('on_error', 'Cannot find main.py')
            return

        cmd = ''
        if mod == '':
            cmd = '%s %s %s' % (self.python_path, py_main, self.args)
        elif mod == 'screen':
            cmd = '%s %s -m screen:%s %s' % (self.python_path, py_main,
                                             data, self.args)
        else:
            cmd = '%s %s -m %s %s' % (self.python_path, py_main,
                                      mod, self.args)

        status = self.run_command(cmd)

        # popen busy
        if status is False:
            self._confirm_dlg = ConfirmationDialog(
                message="There is another command running.\n"
                        "Do you want to stop it to run your project?")
            self._popup = Popup(title='Kivy Designer',
                                content=self._confirm_dlg,
                                size_hint=(None, None),
                                size=('300pt', '150pt'),
                                auto_dismiss=False)
            self._confirm_dlg.bind(on_ok=self._perform_kill_run,
                                   on_cancel=self._popup.dismiss)
            self._popup.open()
            return

        self.ui_creator.tab_pannel.switch_to(
            self.ui_creator.tab_pannel.tab_list[2])

        self.profiler.dispatch('on_message', 'Running main.py...')
        self.profiler.dispatch('on_run')
        self.ui_creator.kivy_console.bind(on_command_list_done=self.on_stop)

    def stop(self, *args):
        '''If there is a process running, it'll be stopped
        '''
        self.ui_creator.kivy_console.kill_process()
        self.profiler.dispatch('on_stop')
        self.profiler.dispatch('on_message', '', 1)

    def clean(self, *args):
        '''Remove .pyc files and __pycache__ folder
        '''
        # here it's necessary to stop the listener as long as the
        # python is managing files
        self.project_watcher.pause_watching()
        for _file in os.listdir(self.profiler.project_path):
            ext = _file.split('.')[-1]
            if ext == 'pyc':
                os.remove(os.path.join(self.profiler.project_path, _file))
        __pycache__ = os.path.join(self.profiler.project_path, '__pycache__')
        if os.path.exists(__pycache__):
            shutil.rmtree(__pycache__)

        self.project_watcher.resume_watching(delay=0)
        self.profiler.dispatch('on_message', 'Project cleaned', 5)

    def build(self, *args):
        '''Compile all .py to .pyc
        '''
        self._get_python()
        if not self.can_run:
            return

        self.project_watcher.pause_watching()
        proj_path = self.profiler.project_path

        self.run_command(
                    '%s -m compileall -l %s' % (self.python_path, proj_path))

        self.ui_creator.tab_pannel.switch_to(
            self.ui_creator.tab_pannel.tab_list[2])

        self.profiler.dispatch('on_message', 'Building project...')
        self.ui_creator.kivy_console.bind(on_command_list_done=self.on_build)

    def rebuild(self, *args):
        '''Clean and build the project
        '''
        self.clean()
        self.build()

    def on_build(self, *args):
        '''on_build event handler
        '''
        self.project_watcher.resume_watching(delay=0)
        self.profiler.dispatch('on_message', 'Build complete', 5)
        self.profiler.dispatch('on_build')

    def on_stop(self, *args):
        '''on_stop event handler
        '''
        self.profiler.dispatch('on_message', '', 1)
        self.profiler.dispatch('on_stop')
Esempio n. 25
0
class DesignerTools(EventDispatcher):

    designer = ObjectProperty()
    '''Instance of Designer
       :data:`designer` is a :class:`~kivy.properties.ObjectProperty`
    '''

    @ignore_proj_watcher
    def export_png(self):
        '''Export playground widget to png file.
        If there is a selected widget, export it.
        If not, export the root widget
        '''
        playground = self.designer.ui_creator.playground
        proj_dir = self.designer.project_loader.proj_dir
        status = self.designer.statusbar

        wdg = playground.selected_widget
        if wdg is None:
            wdg = playground.root

        name = datetime.datetime.now().strftime("%m-%d-%Y_%H-%M-%S.png")
        if wdg.id:
            name = wdg.id + '_' + name
        wdg.export_to_png(os.path.join(proj_dir, name))
        status.show_message('Image saved at ' + name, 5)

    def check_pep8(self):
        '''Check the PEP8 from current project
        '''
        proj_dir = self.designer.project_loader.proj_dir
        kd_dir = os.path.dirname(designer.__file__)
        kd_dir = os.path.split(kd_dir)[0]
        pep8_dir = os.path.join(kd_dir, 'tools', 'pep8checker',
                                'pep8kivy.py')

        python_path =\
            self.designer.designer_settings.config_parser.getdefault(
                'global',
                'python_shell_path',
                ''
            )

        if python_path == '':
            self.profiler.dispatch('on_error', 'Python Shell Path not '
                                   'specified.'
                                   '\n\nUpdate it on \'File\' -> \'Settings\'')
            return

        cmd = '%s %s %s' % (python_path, pep8_dir, proj_dir)
        self.designer.ui_creator.tab_pannel.switch_to(
            self.designer.ui_creator.tab_pannel.tab_list[2])
        self.designer.ui_creator.kivy_console.run_command(cmd)

    def create_setup_py(self):
        '''Runs the GUI to create a setup.py file
        '''
        proj_loader = self.designer.project_loader
        proj_dir = proj_loader.proj_dir
        designer_content = self.designer.designer_content

        setup_path = os.path.join(proj_dir, 'setup.py')
        if os.path.exists(setup_path):
            show_alert('Create setup.py', 'setup.py already exists!')
            return False

        content = ToolSetupPy(path=setup_path)
        self._popup = Popup(title='Create setup.py', content=content,
                            size_hint=(None, None), size=(550, 400),
                            auto_dismiss=False)
        content.bind(on_cancel=self._popup.dismiss)

        def on_create(*args):
            designer_content.update_tree_view(proj_loader)
            self._popup.dismiss()

        content.bind(on_create=on_create)
        self._popup.open()

    @ignore_proj_watcher
    def create_gitignore(self):
        '''Create .gitignore
        '''
        proj_loader = self.designer.project_loader
        proj_dir = proj_loader.proj_dir
        status = self.designer.statusbar

        gitignore_path = os.path.join(proj_dir, '.gitignore')

        if os.path.exists(gitignore_path):
            show_alert('Create .gitignore', '.gitignore already exists!')
            return False

        gitignore = '''*.pyc
*.pyo
bin/
.designer/
.buildozer/
__pycache__/'''

        f = open(gitignore_path, 'w').write(gitignore)
        status.show_message('.gitignore created successfully', 5)

    def buildozer_init(self):
        '''Checks if the .spec exists or not; and when possible, calls
            _perform_buildozer_init
        '''

        proj_loader = self.designer.project_loader
        proj_dir = proj_loader.proj_dir
        spec_file = os.path.join(proj_dir, 'buildozer.spec')

        if os.path.exists(spec_file):
            self._confirm_dlg = ConfirmationDialog(
                message='The buildozer.spec file already exist.'
                                        '\nDo you want to create a new spec?')
            self._popup = Popup(title='Buildozer init',
                                content=self._confirm_dlg,
                                size_hint=(None, None),
                                size=('250pt', '150pt'),
                                auto_dismiss=False)
            self._confirm_dlg.bind(on_ok=self._perform_buildozer_init,
                                   on_cancel=self._popup.dismiss)
            self._popup.open()
        else:
            self._perform_buildozer_init()

    @ignore_proj_watcher
    def _perform_buildozer_init(self, *args):
        '''Copies the spec from new_templates/default.spec to the project
        folder
        '''
        self._popup.dismiss()

        proj_loader = self.designer.project_loader
        proj_dir = proj_loader.proj_dir
        spec_file = os.path.join(proj_dir, 'buildozer.spec')

        _dir = os.path.dirname(designer.__file__)
        _dir = os.path.split(_dir)[0]
        templates_dir = os.path.join(_dir, 'new_templates')
        shutil.copy(os.path.join(templates_dir, 'default.spec'), spec_file)

        self.designer.designer_content.update_tree_view(
            self.designer.project_loader)
class ProfileSettings(Settings):
    '''Subclass of :class:`kivy.uix.settings.Settings` responsible for
       showing build profile settings of Kivy Designer.
    '''

    config_parsers = DictProperty({})
    '''List of config parsers
    :class:`~kivy.properties.DictProperty` and defaults to {}.
    '''

    selected_config = ObjectProperty(None)
    '''ConfigParser of the selected config
    :class `~kivy.properties.ObjectProperty` and defaults to None.
    '''

    __events__ = ('on_use_this_profile', 'on_changed')

    def __init__(self, **kwargs):
        super(ProfileSettings, self).__init__(**kwargs)
        # list of ConfigParsers. Each file has one to handle the settings
        self.PROFILES_PATH = ''
        self.DEFAULT_PROFILES = ''
        self.interface.bind(on_new=self.on_new)
        self.interface.bind(on_delete=self.on_delete)
        self.interface.bind(
            on_use_this_profile=lambda j: self.dispatch('on_use_this_profile'))
        self.interface.content.bind(on_current_panel=self.on_current_config)
        self.settings_changed = False  # changes in name, new or delete

    def load_profiles(self):
        '''This function loads project settings
        '''
        self.settings_changed = False
        self.PROFILES_PATH = os.path.join(get_kivy_designer_dir(),
            'profiles')

        _dir = os.path.dirname(designer.__file__)
        _dir = os.path.split(_dir)[0]
        self.DEFAULT_PROFILES = os.path.join(_dir, 'profiles')

        if not os.path.exists(self.PROFILES_PATH):
            shutil.copytree(self.DEFAULT_PROFILES, self.PROFILES_PATH)

        self.update_panel()

    def update_panel(self):
        '''Update the MenuSidebar
        '''
        _dir = os.path.dirname(designer.__file__)
        _dir = os.path.split(_dir)[0]

        self.config_parsers = {}
        self.interface.menu.buttons_layout.clear_widgets()
        for _file in os.listdir(self.PROFILES_PATH):
            _file_path = os.path.join(self.PROFILES_PATH, _file)
            config_parser = ConfigParser()
            config_parser.read(_file_path)
            prof_name = config_parser.getdefault('profile', 'name', 'PROFILE')
            if not prof_name.strip():
                prof_name = 'PROFILE'
            self.config_parsers[prof_name + '_' + _file_path] = config_parser

        for _file in sorted(self.config_parsers):
            prof_name = self.config_parsers[_file].getdefault('profile',
                                                              'name',
                                                              'PROFILE')
            if not prof_name.strip():
                prof_name = 'PROFILE'
            self.add_json_panel(prof_name,
                                self.config_parsers[_file],
                                os.path.join(
                                    _dir,
                                    'designer',
                                    'settings',
                                    'build_profile.json')
                                )

        # force to show the first profile
        first_panel = self.interface.menu.buttons_layout.children[-1].uid
        self.interface.content.current_uid = first_panel

    def on_config_change(self, instance, section, key, value, *args):
        '''This function is default handler of on_config_change event.
        '''
        super(ProfileSettings, self).on_config_change(
            instance, section, key, value
        )
        if key == 'name':
            self.update_panel()
            self.settings_changed = True

    def on_new(self, *args):
        '''Handler for "New Profile" button
        '''
        new_name = 'new_profile'
        i = 1
        while os.path.exists(os.path.join(
                self.PROFILES_PATH, new_name + str(i) + '.ini')):
            i += 1
        new_name += str(i)
        new_prof_path = os.path.join(
            self.PROFILES_PATH, new_name + '.ini')

        shutil.copy2(os.path.join(self.DEFAULT_PROFILES, 'desktop.ini'),
                     new_prof_path)
        config_parser = ConfigParser()
        config_parser.read(new_prof_path)
        config_parser.set('profile', 'name', new_name.upper())
        config_parser.write()

        self.update_panel()
        self.settings_changed = True

    def on_delete(self, *args):
        '''Handler to "Delete profile" button
        '''
        self._confirm_dlg = ConfirmationDialog(
            message="Do you want to delete this profile?")
        self._popup = Popup(title='Delete Profile',
                            content=self._confirm_dlg,
                            size_hint=(None, None),
                            size=('200pt', '150pt'),
                            auto_dismiss=False)
        self._confirm_dlg.bind(on_ok=self._perform_delete_prof,
                               on_cancel=self._popup.dismiss)
        self._popup.open()

    def _perform_delete_prof(self, *args):
        '''Delete the selected profile
        '''
        self.selected_config = self.interface.content.current_panel.config
        os.remove(self.selected_config.filename)
        self.update_panel()
        self._popup.dismiss()
        self.settings_changed = True

    def on_use_this_profile(self, *args):
        '''Event handler for button "Use this Profile" press
        '''
        self.selected_config = self.interface.content.current_panel.config
        self.settings_changed = True

    def on_current_config(self, *args):
        ''' Event handler to panel change
        The default profile cannot be deleted, so we watch this event to
        prevent the user to delete desktop.ini
        '''
        self.selected_config = self.interface.content.current_panel.config

    def on_changed(self, *args):
        '''Event handler to Settings changes.
        Will be called when the user delete,
        create or change a name of a profile.
        '''
        pass

    def on_close(self, *args):
        '''Event handler when the settings is closed
        '''
        if self.settings_changed:
            self.dispatch('on_changed')
        self.settings_changed = False