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)
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)
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()
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
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 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 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()
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()
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 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 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()
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
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')
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)
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())
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
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
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')
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