diff options
Diffstat (limited to 'develop-activity/develop_app.py')
-rw-r--r-- | develop-activity/develop_app.py | 575 |
1 files changed, 4 insertions, 571 deletions
diff --git a/develop-activity/develop_app.py b/develop-activity/develop_app.py index 2642941..b55e7a7 100644 --- a/develop-activity/develop_app.py +++ b/develop-activity/develop_app.py @@ -28,15 +28,14 @@ from sugar3.graphics.toolbarbox import ToolbarBox from sugar3.graphics.toolbarbox import ToolbarButton from sugar3.graphics.radiotoolbutton import RadioToolButton from sugar3.activity.widgets import ActivityToolbarButton -from sugar3.activity.widgets import EditToolbar + from sugar3.activity.widgets import StopButton from sugar3.activity.bundlebuilder import XOPackager, Config, Builder from sugar3.activity import activity from sugar3.graphics.toolbutton import ToolButton -from sugar3.graphics.combobox import ComboBox from sugar3.graphics.alert import ConfirmationAlert from sugar3.graphics.alert import Alert -from sugar3.graphics import iconentry, notebook +from sugar3.graphics import notebook from sugar3.graphics.icon import Icon from sugar3.graphics import style from sugar3.datastore import datastore @@ -48,8 +47,9 @@ from sugar3.activity import activityfactory import logviewer import sourceview_editor S_WHERE = sourceview_editor.S_WHERE -import new_activity from symbols_tree import SymbolsTree +from toolbars import DevelopEditToolbar, DevelopSearchToolbar +from widgets import FileViewer, WelcomePage SEARCH_ICONS = {False: {S_WHERE.selection: "search-in-selection", S_WHERE.file: "system-search", @@ -62,24 +62,6 @@ SEARCH_ICONS = {False: {S_WHERE.selection: "search-in-selection", #CAP_ICONS = {False: "use-caps", True: "ignore-caps"} #REPLACE_ICONS = {False: "replace-and-find", True: "multi-replace"} -_EXCLUDE_EXTENSIONS = ('.pyc', '.pyo', '.so', '.o', '.a', '.la', '.mo', '~', - '.xo', '.tar', '.bz2', '.zip', '.gz') -_EXCLUDE_NAMES = ['.deps', '.libs'] - -try: - activities_path = os.environ['SUGAR_ACTIVITIES_PATH'] -except KeyError: - activities_path = os.path.join(os.path.expanduser("~"), "Activities") - -class SearchOptions: - - def __init__(self, template=None, **kw): - if template: - self.__dict__ = template.__dict__.copy() - else: - self.__dict__ = {} - self.__dict__.update(kw) - class DevelopActivity(activity.Activity): """Develop Activity as specified in activity.info""" @@ -549,552 +531,3 @@ class DevelopActivity(activity.Activity): self.refresh_files() self.editor.close_page() self.remove_alert(alert) - - -class WelcomePage(Gtk.VBox): - - __gsignals__ = { - 'open-activity': (GObject.SignalFlags.RUN_FIRST, - None, - ([str])), - 'show-alert': (GObject.SignalFlags.RUN_FIRST, - None, - ([str])), - } - - def __init__(self): - Gtk.VBox.__init__(self) - - edit_label = Gtk.Label( - _('<span weight="bold" size="larger">' - 'Edit an installed activity</span>\n\n' - 'You can modify an activity, and if there are errors the ' - 'activity can stop working. If you are not sure, clone the ' - 'activity to have a backup.')) - edit_label.set_use_markup(True) - edit_label.set_line_wrap(True) - self.pack_start(edit_label, expand=False, fill=True, padding=10) - - hbox_edit = Gtk.HBox() - hbox_edit.pack_start(Gtk.Label(_('Select the activity')), True, - True, 10) - activity_name_combo = ComboBox() - self._load_activities_installed_combo(activity_name_combo) - hbox_edit.pack_start(activity_name_combo, expand=False, fill=False, - padding=10) - edit_btn = Gtk.Button(_('Start')) - edit_btn.connect('clicked', self._pick_existing_activity, - activity_name_combo) - hbox_edit.pack_start(edit_btn, expand=False, fill=False, - padding=10) - align = Gtk.Alignment.new(0.5, 0.5, 0, 0) - align.add(hbox_edit) - self.pack_start(align, expand=False, fill=False, padding=10) - - new_project_label = Gtk.Label( - _('<span weight="bold" size="larger">' - 'Create a new activity</span>\n\n' - 'You can create something new, ' - 'just select the type of project.')) - new_project_label.set_use_markup(True) - new_project_label.set_line_wrap(True) - self.pack_start(new_project_label, expand=False, fill=True, padding=10) - - hbox_create = Gtk.HBox() - hbox_create.pack_start(Gtk.Label(_('Select the type')), - expand=False, fill=False, padding=10) - project_type_combo = ComboBox() - self._load_skeletons_combo(project_type_combo) - hbox_create.pack_start(project_type_combo, expand=False, fill=False, - padding=10) - align = Gtk.Alignment.new(0.5, 0.5, 0, 0) - align.add(hbox_create) - self.pack_start(align, expand=False, fill=False, padding=10) - - hbox_name = Gtk.HBox() - hbox_name.pack_start(Gtk.Label(_('Name the activity')), True, True, 0) - activity_name_entry = Gtk.Entry() - hbox_name.pack_start(activity_name_entry, expand=True, fill=True, - padding=10) - - create_btn = Gtk.Button(_('Start')) - create_btn.connect('clicked', self._create_new_activity, - activity_name_entry, project_type_combo) - hbox_name.pack_start(create_btn, expand=True, fill=True, - padding=10) - align = Gtk.Alignment.new(0.5, 0.5, 0, 0) - align.add(hbox_name) - self.pack_start(align, expand=False, fill=False, padding=10) - - self.show_all() - - def _load_activities_installed_combo(self, activities_combo): - for dir_name in sorted(os.listdir(activities_path)): - if dir_name.endswith('.activity'): - activity_name = dir_name[:- len('.activity')] - # search the icon - info_file_name = os.path.join(activities_path, dir_name, - 'activity/activity.info') - try: - info_file = open(info_file_name, 'r') - icon_name = None - for line in info_file.readlines(): - if line.strip().startswith('icon'): - icon_name = line.split()[-1] - info_file.close() - icon_file_name = None - if icon_name is not None: - icon_file_name = os.path.join( - activities_path, dir_name, 'activity', - '%s.svg' % icon_name) - activities_combo.append_item(0, activity_name, - file_name=icon_file_name) - except: - logging.error('Error trying to read information about %s', - activity_name) - - def _load_skeletons_combo(self, skeletons_combo): - skeletons_path = os.path.join(activity.get_bundle_path(), 'skeletons') - for dir_name in sorted(os.listdir(skeletons_path)): - skeletons_combo.append_item(0, dir_name) - - def _create_new_activity(self, button, name_entry, combo_skeletons): - """create and open a new activity in working dir - """ - if name_entry.get_text() == '': - self.emit('show-alert', - _('You must type the name for the new activity')) - return - if combo_skeletons.get_active() == -1: - self.emit('show-alert', _('You must select the project type')) - return - - activity_name = name_entry.get_text().strip() - skel_iter = combo_skeletons.get_active_iter() - skeleton = combo_skeletons.get_model().get_value(skel_iter, 1) - - activity_dir = new_activity.create_activity(activity_name, - activities_path, skeleton) - self.emit('open-activity', activity_dir) - - def _pick_existing_activity(self, button, combo_activities): - if combo_activities.get_active() == -1: - self.emit('show-alert', _('You must select the activity')) - else: - selected = combo_activities.get_active_iter() - activity_name = combo_activities.get_model().get_value(selected, 1) - logging.error('Activity selected %s', activity_name) - activity_dir = os.path.join(activities_path, - "%s.activity" % activity_name) - self.emit('open-activity', activity_dir) - - -class FileViewer(Gtk.ScrolledWindow): - __gtype_name__ = 'ActivityFileViewer' - - __gsignals__ = { - 'file-selected': (GObject.SignalFlags.RUN_FIRST, - None, - ([str])), - } - - def __init__(self): - Gtk.ScrolledWindow.__init__(self) - - self.props.hscrollbar_policy = Gtk.PolicyType.AUTOMATIC - self.props.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC - self.set_size_request(style.GRID_CELL_SIZE * 3, -1) - - self._path = None - self._initial_filename = None - - self._tree_view = Gtk.TreeView() - self._tree_view.connect('cursor-changed', self.__cursor_changed_cb) - self.add(self._tree_view) - self._tree_view.show() - - selection = self._tree_view.get_selection() - selection.connect('changed', self.__selection_changed_cb) - - cell = Gtk.CellRendererText() - self._column = Gtk.TreeViewColumn() - self._column.pack_start(cell, True) - self._column.add_attribute(cell, 'text', 0) - self._tree_view.append_column(self._column) - self._tree_view.set_search_column(0) - # map between file_path and iter - self._opened_files = {} - - def load_activity(self, path, bundle): - self._search_initial_filename(path, bundle) - self._path = path - - self._tree_view.set_model(Gtk.TreeStore(str, str)) - self._model = self._tree_view.get_model() - self._add_dir_to_model(path) - - def _add_dir_to_model(self, dir_path, parent=None): - for f in os.listdir(dir_path): - if f.endswith(_EXCLUDE_EXTENSIONS) or f in _EXCLUDE_NAMES: - continue - - full_path = os.path.join(dir_path, f) - if os.path.isdir(full_path): - new_iter = self._model.append(parent, [f, full_path]) - self._add_dir_to_model(full_path, new_iter) - else: - current_iter = self._model.append(parent, [f, full_path]) - self._opened_files[full_path] = current_iter - if full_path == self._initial_filename: - selection = self._tree_view.get_selection() - selection.select_iter(current_iter) - - def __selection_changed_cb(self, selection): - model, tree_iter = selection.get_selected() - if tree_iter is None: - file_path = None - else: - file_path = model.get_value(tree_iter, 1) - self.emit('file-selected', file_path) - - def __cursor_changed_cb(self, tree_view): - selection = tree_view.get_selection() - store, iter_ = selection.get_selected() - if iter_ is None: - # Nothing selected. This happens at startup - return - if store.iter_has_child(iter_): - path = store.get_path(iter_) - if tree_view.row_expanded(path): - tree_view.collapse_row(path) - else: - tree_view.expand_row(path, False) - - def select_by_file_path(self, file_path): - if file_path in self._opened_files: - tree_iter = self._opened_files[file_path] - tree_selection = self._tree_view.get_selection() - tree_selection.unselect_all() - tree_selection.select_iter(tree_iter) - - def _search_initial_filename(self, activity_path, bundle): - command = bundle.get_command() - - if self._is_web_activity(bundle): - file_name = 'index.html' - - elif len(command.split(' ')) > 1: - name = command.split(' ')[1].split('.')[-1] - tmppath = command.split(' ')[1].replace('.', '/') - file_name = tmppath[0:-(len(name) + 1)] + '.py' - else: - file_name = command - - if file_name: - path = os.path.join(activity_path, file_name) - if os.path.exists(path): - logging.error('INITIAL_FILENAME %s', path) - self._initial_filename = path - self.emit('file-selected', path) - - def set_title(self, title): - self._column.set_title(title) - - def _is_web_activity(self, activity_bundle): - return activity_bundle.get_command() == 'sugar-activity-web' - - -class DevelopEditToolbar(EditToolbar): - - def __init__(self, _activity): - EditToolbar.__init__(self) - - self._activity = _activity - self._activity.editor.connect('changed', self._changed_cb) - self._changed_cb(None) - - self.undo.connect('clicked', self._undo_cb) - self.redo.connect('clicked', self._redo_cb) - self.copy.connect('clicked', self._copy_cb) - self.paste.connect('clicked', self._paste_cb) - - def _changed_cb(self, _buffer): - can_undo, can_redo = self._activity.editor.can_undo_redo() - self.undo.set_sensitive(can_undo) - self.redo.set_sensitive(can_redo) - - def _undo_cb(self, button): - self._activity.editor.undo() - self._changed_cb(None) - - def _redo_cb(self, button): - self._activity.editor.redo() - self._changed_cb(None) - - def _copy_cb(self, button): - self._activity.editor.copy() - - def _paste_cb(self, button): - self._activity.editor.paste() - - -class DevelopSearchToolbar(Gtk.Toolbar): - - def __init__(self, _activity): - GObject.GObject.__init__(self) - - self._activity = _activity - - # setup the search options - self.s_opts = SearchOptions( - where=S_WHERE.multifile, - use_regex=False, - ignore_caps=True, - replace_all=False, - #defaults to avoid creating - #a new SearchOptions object for normal searches - #should never be changed, just make a copy like: - #SearchOptions(self.s_opts, forward=False) - forward=True, - stay=False) - - self.safe_to_replace = False - - self._search_entry = iconentry.IconEntry() - self._search_entry.set_icon_from_name( - iconentry.ICON_ENTRY_PRIMARY, - SEARCH_ICONS[self.s_opts.use_regex][self.s_opts.where]) - - self._search_entry.add_clear_button() - self._search_entry.connect('activate', self._search_entry_activated_cb) - self._search_entry.connect('changed', self._search_entry_changed_cb) - self._add_widget(self._search_entry, expand=True) - - self._findprev = ToolButton('go-previous') - self._findprev.set_tooltip(_('Find previous')) - self.insert(self._findprev, -1) - self._findprev.show() - self._findprev.connect('clicked', self._findprev_cb) - - self._findnext = ToolButton('go-next') - self._findnext.set_tooltip(_('Find next')) - self.insert(self._findnext, -1) - self._findnext.show() - self._findnext.connect('clicked', self._findnext_cb) - - """ - self._settings = ToolButton(CAP_ICONS[self.s_opts.ignore_caps]) - self._settings.set_tooltip(_('Search settings')) - self.insert(self._settings, -1) - self._settings.show() - self._settings.connect('clicked', self._settings_cb) - - # Search settings menu - # This menu should attach to something else beside findnext - - #location is temporary. - palette = self._settings.get_palette() - sswo = self._set_where_options - ssho = self._set_how_options - ssco = self._set_cap_options - #TODO: move data structure to a member and the logic to a function - for name, function, options, icon in ( - (_('Ignore capitalization'), ssco, True, "ignore-caps"), - (_('Match capitalization'), ssco, False, "use-caps"), - (None, None, None, None), - (_('Search in selection'), sswo, S_WHERE.selection, - "search-in-selection"), - (_('Search in current file'), sswo, S_WHERE.file, - "system-search"), - (_('Search in all open files'), sswo, S_WHERE.multifile, - "multi-search"), - (None, None, None, None), - (_('Simple search'), ssho, False, "system-search"), - (_('Advanced search'), ssho, True, "regex"), - ): - if not name: - menuitem = Gtk.SeparatorMenuItem() - else: - menuitem = MenuItem(name, icon) - menuitem.connect('activate', function, options) - palette.menu.append(menuitem) - menuitem.show() - - # make expanded non-drawn visible separator to make the replace - #stuff right-align - separator = Gtk.SeparatorToolItem() - separator.props.draw = False - separator.set_expand(True) - self.insert(separator, -1) - separator.show() - - # replace entry - self._replace_entry = iconentry.IconEntry() - self._replace_entry.set_icon_from_name(iconentry.ICON_ENTRY_PRIMARY, - 'system-replace') - self._replace_entry.connect('changed', self._replace_entry_changed_cb) - self._replace_entry.add_clear_button() - self._add_widget(self._replace_entry, expand=True) - - #replace button - self._replace_button = ToolButton(REPLACE_ICONS[ - self.s_opts.replace_all]) - self._replace_button.set_tooltip(_('Replace')) - self.insert(self._replace_button, -1) - self._replace_button.show() - self._replace_button.connect('clicked', self._replace_cb) - - palette = self._replace_button.get_palette() - ssro = self._set_replace_options - #TODO: move data structure to a member and the logic to a function - for name, function, options, icon in ( - (_('Replace one'), ssro, False, "replace-and-find"), - (_('Replace all'), ssro, True, "multi-replace"), - ): - if not name: - menuitem = Gtk.SeparatorMenuItem() - else: - menuitem = MenuItem(name, icon) - menuitem.connect('activate', function, options) - palette.menu.append(menuitem) - menuitem.show() - """ - - self._activity.editor.connect('changed', self._changed_cb) - - self._activity.connect('key_press_event', self._on_key_press_event) - - def _on_key_press_event(self, widget, event): - keyname = Gdk.keyval_name(event.keyval) - if "F5" <= keyname and keyname <= "F8": - if keyname == "F5": - self._go_to_search_entry_cb() - elif keyname == "F6": - self._findprev_cb() - elif keyname == "F7": - self._findnext_cb() - elif keyname == "F8": - self._replace_or_go_to_replace_entry_cb() - return True - - def _go_to_search_entry_cb(self): - entry = self._search_entry - text = self._activity.editor.get_selected() - entry.grab_focus() - if text: - entry.delete_text(0, -1) - entry.insert_text(text) - entry.select_region(0, -1) - else: - entry.delete_text(0, 0) - entry.set_position(-1) - #for some reason, grab_focus doesn't work otherwise - - def _replace_or_go_to_replace_entry_cb(self): - if self.safe_to_replace: - self._replace_cb() - else: - self._replace_entry.select_region(0, -1) - self._replace_entry.grab_focus() - - def _reset_search_icons(self): - self._search_entry.set_icon_from_name( - iconentry.ICON_ENTRY_PRIMARY, - SEARCH_ICONS[self.s_opts.use_regex][self.s_opts.where]) - #self._settings.set_icon(CAP_ICONS[self.s_opts.ignore_caps]) - #self._replace_button.set_icon(REPLACE_ICONS[self.s_opts.replace_all]) - self._reset_replace_sensitivity() - - def _reset_replace_sensitivity(self): - pass - """ - self._replace_button.set_sensitive( - self.s_opts.where == S_WHERE.selection or self.s_opts.replace_all) - """ - - def _set_where_options(self, menu, option): - self.s_opts.where = option # IGNORE:W0201 - self._reset_search_icons() - - def _set_how_options(self, menu, option): - self.s_opts.use_regex = option # IGNORE:W0201 - self._reset_search_icons() - - def _set_cap_options(self, menu, option): - self.s_opts.ignore_caps = option # IGNORE:W0201 - self._reset_search_icons() - - def _set_replace_options(self, menu, option): - self.s_opts.replace_all = option # IGNORE:W0201 - if option and self.s_opts.where == S_WHERE.multifile: - self.s_opts.where = S_WHERE.file # for safety: - #do not replace all in multifile except explicitly - self._reset_search_icons() - - def _changed_cb(self, _buffer): - self._reset_replace_sensitivity() - #if self.s_opts.where == S_WHERE.selection: - # self._set_where_options(None, S_WHERE.file) - - def _settings_cb(self, button): - self._set_cap_options(None, not self.s_opts.ignore_caps) - - def _replace_cb(self, button=None): - pass - """ - ftext = self._search_entry.props.text - rtext = self._replace_entry.props.text - __replaced, found = self._activity.editor.replace(ftext, rtext, - self.s_opts) - if found: - self._replace_button.set_sensitive(True) - """ - - def _search_entry_activated_cb(self, entry): - text = self._search_entry.props.text - if text: - self._findnext_cb(None) - - def _search_entry_changed_cb(self, entry): - self.safe_to_replace = False - text = self._search_entry.props.text - if not text: - self._findprev.set_sensitive(False) - self._findnext.set_sensitive(False) - else: - self._findprev.set_sensitive(True) - self._findnext.set_sensitive(True) - if not self.s_opts.use_regex: - #do not do partial searches for regex - if self._activity.editor.find_next(text): - #no multifile, or focus gets grabbed - pass - #self._replace_button.set_sensitive(True) - - def _replace_entry_changed_cb(self, entry): - if self._replace_entry.props.text: - self.safe_to_replace = True - - def _findprev_cb(self, button=None): - ftext = self._search_entry.props.text - if ftext: - if self._activity.editor.find_next(ftext, direction='backward'): - pass - #self._replace_button.set_sensitive(True) - - def _findnext_cb(self, button=None): - ftext = self._search_entry.props.text - if ftext: - if self._activity.editor.find_next(ftext, direction='forward'): - pass - #self._replace_button.set_sensitive(True) - - # bad paul! this function was copied from sugar's activity.py via Write - def _add_widget(self, widget, expand=False): - tool_item = Gtk.ToolItem() - tool_item.set_expand(expand) - - tool_item.add(widget) - widget.show() - - self.insert(tool_item, -1) - tool_item.show() |