From 5397867451324eccbdfe19f1ca5c53b28e95769f Mon Sep 17 00:00:00 2001 From: Gonzalo Odiard Date: Thu, 13 Feb 2014 12:10:10 +0000 Subject: Merge branch 'gtk3' --- diff --git a/develop-activity/activity_model.py b/develop-activity/activity_model.py deleted file mode 100644 index d20690a..0000000 --- a/develop-activity/activity_model.py +++ /dev/null @@ -1,275 +0,0 @@ -# Copyright 2008 Paul Swartz -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -import gtk -import gobject -import os -import os.path -import logging -from gettext import gettext as _ -import fnmatch - -unwantedPaths = [ - '.*', # hidden files - '*~', # emacs backups - '*.pyc', # compiled python - '*.bak', # SPE backup file - '.git', # git repository info - 'CVS', ] # CVS repository info - - -def _nodefilter(node): - notmatched = True - for path in unwantedPaths: - if fnmatch.fnmatch(node.filename, path): - notmatched = False - break - return notmatched - - -def inmanifestfn(bundle): - activity_path = bundle.get_path() - logging.error('activity path = %s', activity_path) - - allfiles = [] - - def walk_callback(allfiles, directory, files): - for file_name in files: - notmatched = True - for path in unwantedPaths: - if fnmatch.fnmatch(file_name, path): - notmatched = False - break - if notmatched: - allfiles.append(os.path.join(directory, file_name)) - - os.path.walk(activity_path, walk_callback, allfiles) - - #logging.error('allfiles %s', allfiles) - - #allfiles = bundle.get_files() - def nodefilterfn(node): - if os.path.isdir(node.path): - return True - for innerpath in allfiles[:-1]: # truncate MANIFEST - if os.path.join(node.model.root, innerpath) == node.path: - return True - return False - return nodefilterfn - - -def get_selected_file(treeview): - selection = treeview.get_selection() - model, _iter = selection.get_selected() - if not _iter: - return - value = model.get_value(_iter, 0) - return value - - -def get_selected_file_path(treeview): - value = get_selected_file(treeview) - if value: - return value['path'] - - -class DirectoryAndExtraModel(gtk.GenericTreeModel): - - columns = (gobject.TYPE_PYOBJECT, gobject.TYPE_STRING) - - def __init__(self, root, extra_paths=None, nodefilter=_nodefilter): - self.root = root - self.extra_paths = extra_paths - self.nodefilter = nodefilter - self.refresh() - gtk.GenericTreeModel.__init__(self) - - def refresh(self): - self.files = list( - n for n in - (ActivityNode(filename, self, None, self.nodefilter) - for filename in sorted(os.listdir(self.root))) - if self.nodefilter(n)) - - if self.extra_paths: - self.files.extend(ActivityNode( - filename, self, None, - self.nodefilter) for filename in self.extra_paths) - - def get_iter_from_filepath(self, filepath): - if filepath.startswith(self.root): - inpath = os.path.split(filepath[len(self.root):])[1:] - #os.path.split gives empty first element - else: - inpath = os.path.split(filepath) - files = self.files - outpath = [] - try: - for node in inpath: - nodeindex = files.index(node) - files = files[nodeindex]._files - outpath.append(nodeindex) - except ValueError: - print files - print filepath, inpath, outpath - tree_iter = self.get_iter(tuple(outpath)) - return tree_iter - - def on_get_flags(self): - return 0 - - def on_get_n_columns(self): - return len(self.columns) - - def on_get_column_type(self, n): - return self.columns[n] - - def on_get_iter(self, path): - x = self.files - for part in path: - x = x[part] - return x - - def on_get_path(self, rowref): - return rowref.getTreePath() - - def on_get_value(self, rowref, n): - if n == 0: - return {'name': rowref.filename, - 'path': rowref.path} - else: - return rowref.filename - - def on_iter_next(self, rowref): - if rowref.parent is not None: - files = rowref.parent - else: - files = self.files - index = files.index(rowref) + 1 - if index < len(files): - return files[index] - - def on_iter_has_child(self, rowref): - if rowref is not None: - return rowref.isDirectory - else: - return bool(len(self.files)) - - def on_iter_n_chilren(self, rowref): - logging.critical('n children: %s' % rowref) - if rowref is not None: - if rowref.isDirectory: - logging.critical('res: %i' % len(rowref)) - return len(rowref) - else: - return - else: - return len(self.files) - - def on_iter_nth_child(self, rowref, n): - if rowref is not None: - if not rowref.isDirectory: - return - files = rowref - else: - files = self.files - if n < len(files): - return files[n] - - def on_iter_parent(self, child): - return child.parent - - def on_iter_children(self, rowref): - if rowref is not None: - if rowref.isDirectory and len(rowref): - return rowref[0] - else: - return - else: - return self.files[0] - - -class ActivityNode(object): - - def __init__(self, filename, model, parent, nodefilter): - self.filename = filename - self.model = model - self.nodefilter = nodefilter - if parent is not None: - self.path = os.path.join(parent.path, filename) - else: - self.path = os.path.join(model.root, filename) - self.parent = parent - self.isDirectory = os.path.isdir(self.path) - self._files = None - - def _get_files(self): - if not self.isDirectory: - return None - if self._files is None: - files = sorted(os.listdir(self.path)) - self._files = filter( - self.nodefilter, - (ActivityNode(filename, self.model, self, self.nodefilter) - for filename in files)) - if not self._files: - self._files = (DummyActivityNode(self),) - return self._files - files = property(_get_files) # TODO: use a decorator - - def __eq__(self, other): - if not isinstance(other, ActivityNode): - if isinstance(other, str): - return self.filename == other - else: - return False - return self.path == other.path - - def __len__(self): - return len(self.files) - - def index(self, item): - return self.files.index(item) - - def __getitem__(self, n): - return self.files[n] - - def getTreePath(self): - if self.parent is None: - return (self.model.files.index(self),) - parentPath = self.parent.getTreePath() - return parentPath + (self.parent.files.index(self),) - - def __hash__(self): - return hash(self.path) - - def __str__(self): - return '' % self.path - - __repr__ = __str__ - - def __eq__(self, other): - return other == self.path or other == self.filename - - -class DummyActivityNode(ActivityNode): - files = () - filename = _("") - path = "" - isDirectory = False - - def __init__(self, parent): - self.parent = parent diff --git a/develop-activity/develop_app.py b/develop-activity/develop_app.py index 4d0d430..ef7f8b5 100644 --- a/develop-activity/develop_app.py +++ b/develop-activity/develop_app.py @@ -13,39 +13,39 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """Develop Activity: A programming activity.""" -import gtk import logging import os import os.path -import gobject import simplejson - from gettext import gettext as _ -from sugar import profile -from sugar.graphics.toolbarbox import ToolbarBox -from sugar.activity.widgets import ActivityToolbarButton -from sugar.graphics.toolbarbox import ToolbarButton -from sugar.graphics.radiotoolbutton import RadioToolButton -from sugar.activity.widgets import StopButton -from sugar.activity.bundlebuilder import XOPackager, Config, Builder -from sugar.activity import activity -from sugar.graphics.toolbutton import ToolButton -from sugar.graphics.combobox import ComboBox -from sugar.graphics.alert import ConfirmationAlert -from sugar.graphics.alert import Alert -from sugar.graphics import iconentry, notebook -from sugar.graphics.icon import Icon -from sugar.graphics import style -from sugar.datastore import datastore -from sugar.bundle.activitybundle import ActivityBundle +from gi.repository import Gtk +from gi.repository import Gdk +from gi.repository import GObject + +from sugar3 import profile +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.icon import Icon +from sugar3.graphics import style +from sugar3.datastore import datastore +from sugar3.bundle.activitybundle import ActivityBundle import logviewer import sourceview_editor S_WHERE = sourceview_editor.S_WHERE -import activity_model import new_activity - from symbols_tree import SymbolsTree DEBUG_FILTER_LEVEL = 1 @@ -68,7 +68,9 @@ REPLACE_ICONS = {False: "replace-and-find", True: "multi-replace"} TOOLBAR_SEARCH = 2 -OPENFILE_SEPARATOR = u"@ @" +_EXCLUDE_EXTENSIONS = ('.pyc', '.pyo', '.so', '.o', '.a', '.la', '.mo', '~', + '.xo', '.tar', '.bz2', '.zip', '.gz') +_EXCLUDE_NAMES = ['.deps', '.libs'] class Options: @@ -91,14 +93,16 @@ class DevelopActivity(activity.Activity): def __init__(self, handle): """Set up the Develop activity.""" - self.dirty = False + self._dirty = False super(DevelopActivity, self).__init__(handle) self.max_participants = 1 logging.info(repr(handle.get_dict())) # Source buffer - self.editor = sourceview_editor.GtkSourceview2Editor(self) + self.editor = sourceview_editor.GtkSourceview2Editor() + self.editor.connect('tab-changed', self.__editor_tab_changed_cb) + self.editor.connect('changed', self.__editor_changed_cb) toolbarbox = ToolbarBox() activity_button = ActivityToolbarButton(self) @@ -117,7 +121,7 @@ class DevelopActivity(activity.Activity): search_btn.props.label = _('Search') toolbarbox.toolbar.insert(search_btn, -1) - toolbarbox.toolbar.insert(gtk.SeparatorToolItem(), -1) + toolbarbox.toolbar.insert(Gtk.SeparatorToolItem(), -1) show_files_btn = RadioToolButton() show_files_btn.props.icon_name = 'sources' @@ -133,7 +137,7 @@ class DevelopActivity(activity.Activity): show_symbols_btn.set_active(False) show_symbols_btn.set_tooltip(_('Show file symbols')) toolbarbox.toolbar.insert(show_symbols_btn, -1) - show_symbols_btn.connect('clicked', self.explore_code) + show_symbols_btn.connect('clicked', self._explore_code) show_log_btn = RadioToolButton() show_log_btn.props.icon_name = 'logs' @@ -143,7 +147,7 @@ class DevelopActivity(activity.Activity): toolbarbox.toolbar.insert(show_log_btn, -1) show_log_btn.connect('clicked', self._change_treenotebook_page, 2) - toolbarbox.toolbar.insert(gtk.SeparatorToolItem(), -1) + toolbarbox.toolbar.insert(Gtk.SeparatorToolItem(), -1) create_file_btn = ToolButton('text-x-generic') create_file_btn.set_tooltip(_('Create empty file')) @@ -157,7 +161,7 @@ class DevelopActivity(activity.Activity): erase_btn.show() erase_btn.connect('clicked', self.__remove_file_cb) - separator = gtk.SeparatorToolItem() + separator = Gtk.SeparatorToolItem() separator.set_draw(False) separator.set_expand(True) toolbarbox.toolbar.insert(separator, -1) @@ -174,8 +178,8 @@ class DevelopActivity(activity.Activity): toolbarbox.show_all() # Main layout. - hbox = gtk.HPaned() - vbox = gtk.VBox() + hbox = Gtk.HPaned() + vbox = Gtk.VBox() #The treeview and selected pane reflect each other. self.numb = False @@ -185,39 +189,30 @@ class DevelopActivity(activity.Activity): self.save_unchanged = False # The sidebar - sidebar = gtk.VBox() + sidebar = Gtk.VBox() self.treenotebook = notebook.Notebook(can_close_tabs=False) self.treenotebook.set_show_tabs(False) - sidebar.pack_start(self.treenotebook) - - self.model = gtk.TreeStore(gobject.TYPE_PYOBJECT, gobject.TYPE_STRING) - self.treeview = gtk.TreeView(self.model) - cellrenderer = gtk.CellRendererText() - self.treecolumn = gtk.TreeViewColumn(_("Activities"), cellrenderer, - text=1) - self.treeview.append_column(self.treecolumn) - self.treeview.set_size_request(gtk.gdk.screen_width() / 4, -1) - - # Create scrollbars around the tree view. - scrolled = gtk.ScrolledWindow() - scrolled.add(self.treeview) - scrolled.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) - self.treenotebook.add_page(_("Activity"), scrolled) + sidebar.pack_start(self.treenotebook, True, True, 0) + + self.activity_tree_view = FileViewer() + #self.activity_tree_view = ActivityTreeView() + self.treenotebook.add_page(_("Activity"), self.activity_tree_view) + self.treenotebook.set_size_request(Gdk.Screen.width() / 5, -1) # Symbols tree self._symbolstree = SymbolsTree() self._symbolstree.connect('symbol-selected', self.editor.symbol_selected_cb) - scrolled = gtk.ScrolledWindow() + scrolled = Gtk.ScrolledWindow() scrolled.add(self._symbolstree) - scrolled.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + scrolled.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.treenotebook.add_page(_('Symbols Tree'), scrolled) - hbox.pack1(sidebar, resize=True, shrink=True) + hbox.pack1(sidebar, resize=True, shrink=False) sidebar.show() logging.info('finished check') - vbox.pack_start(self.editor) + vbox.pack_start(self.editor, True, True, 0) self.editor.show() hbox.pack2(vbox, resize=True, shrink=True) vbox.show() @@ -228,15 +223,16 @@ class DevelopActivity(activity.Activity): self.show() if not handle.object_id or not self.metadata.get('source'): - gobject.timeout_add(10, self._show_welcome) + GObject.timeout_add(10, self._show_welcome) def _change_treenotebook_page(self, button, page): self.treenotebook.set_current_page(page) - def explore_code(self, btn, switch_page=True): + def _explore_code(self, btn, switch_page=True): from ninja import introspection text = self.editor.get_text() path = self.editor.get_file_path() + logging.error('Analyzing %s', path) symbols = introspection.obtain_symbols(text, filename=path) self._symbolstree.load_symbols(symbols) if switch_page: @@ -266,9 +262,9 @@ class DevelopActivity(activity.Activity): def _show_welcome(self): """_show_welcome: when opened without a bundle, ask open/new/cancel """ - vbox = gtk.VBox() + vbox = Gtk.VBox() - edit_label = gtk.Label( + edit_label = Gtk.Label( _('' 'Edit a installed activity\n\n' 'You can modify a activity, and if there are errors the ' @@ -278,23 +274,23 @@ class DevelopActivity(activity.Activity): edit_label.set_line_wrap(True) vbox.pack_start(edit_label, expand=False, fill=True, padding=10) - hbox_edit = gtk.HBox() - hbox_edit.pack_start(gtk.Label('Select the activity'), expand=False, - fill=False, 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 = 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(xalign=0.5, yalign=0.5) + align = Gtk.Alignment.new(0.5, 0.5, 0, 0) align.add(hbox_edit) vbox.pack_start(align, expand=False, fill=False, padding=10) - new_project_label = gtk.Label( + new_project_label = Gtk.Label( _('' 'Create a new activity\n\n' 'You can create something new, ' @@ -303,34 +299,34 @@ class DevelopActivity(activity.Activity): new_project_label.set_line_wrap(True) vbox.pack_start(new_project_label, expand=False, fill=True, padding=10) - hbox_create = gtk.HBox() - hbox_create.pack_start(gtk.Label('Select the type'), + 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(xalign=0.5, yalign=0.5) + align = Gtk.Alignment.new(0.5, 0.5, 0, 0) align.add(hbox_create) vbox.pack_start(align, expand=False, fill=False, padding=10) - hbox_name = gtk.HBox() - hbox_name.pack_start(gtk.Label(_('Name the activity'))) - activity_name_entry = gtk.Entry() + 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 = 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(xalign=0.5, yalign=0.5) + align = Gtk.Alignment.new(0.5, 0.5, 0, 0) align.add(hbox_name) vbox.pack_start(align, expand=False, fill=False, padding=10) vbox.show_all() - self.editor.append_page(vbox, gtk.Label(_('Start'))) + self.editor.append_page(vbox, Gtk.Label(label=_('Start'))) return False def _load_activities_installed_combo(self, activities_combo): @@ -392,7 +388,7 @@ class DevelopActivity(activity.Activity): title = _('Atention') alert.props.title = title alert.props.msg = message - alert.add_button(gtk.RESPONSE_OK, _('Ok')) + alert.add_button(Gtk.ResponseType.OK, _('Ok')) self.add_alert(alert) alert.connect('response', self._alert_response_cb) @@ -420,10 +416,12 @@ class DevelopActivity(activity.Activity): activity_dir = activity_dir + '/' self.activity_dir = activity_dir name = os.path.basename(activity_dir) - self.treecolumn.set_title(name) + self.activity_tree_view.set_title(name) self.metadata['title'] = 'Develop %s' % name self.refresh_files() - self.treeview.get_selection().connect("changed", self.selection_cb) + + self.activity_tree_view.connect('file_selected', + self.__file_selected_cb) return name def first_open_activity(self, activity_dir): @@ -432,17 +430,18 @@ class DevelopActivity(activity.Activity): """ self.open_activity(activity_dir) namefilter = ActivityBundle(activity_dir).get_bundle_id() - self.logview = logviewer.LogMinder(self, namefilter) - self.set_dirty(False) + self._log_files_viewer = logviewer.LogFilesViewer(namefilter) + self._log_files_viewer.connect('file-selected', + self.__log_file_selected_cb) + self.treenotebook.add_page(_("Log"), self._log_files_viewer) + + self._set_dirty(False) def refresh_files(self): """Refresh the treeview of activity files. """ self.bundle = ActivityBundle(self.activity_dir) - self.model = activity_model.DirectoryAndExtraModel( - self.activity_dir, - nodefilter=activity_model.inmanifestfn(self.bundle)) - self.treeview.set_model(self.model) + self.activity_tree_view.load_activity(self.activity_dir, self.bundle) def load_file(self, full_path): """Load one activity subfile into the editor view. @@ -458,19 +457,32 @@ class DevelopActivity(activity.Activity): logging.error('load_file filename %s', filename) self.editor.load_object(full_path, filename) - def selection_cb(self, column): + def __file_selected_cb(self, file_viewer, path): """User selected an item in the treeview. Load it. """ if self.numb: #Choosing in the notebook selects in the list, and vice versa. #Avoid infinite recursion. return - path = activity_model.get_selected_file_path(self.treeview) if path and not os.path.isdir(path): self.numb = True self.load_file(path) self.numb = False + def __log_file_selected_cb(self, log_files_viewer, path): + if not path: + return + + if os.path.isdir(path): + #do not try to open folders + return + + # Set buffer and scroll down + if self.editor.set_to_page_like(path): + return + + self.editor.load_log_file(path, log_files_viewer) + def save_bundle(self, btn): #create bundle builder = XOPackager(Builder(Config(self.activity_dir, '/tmp'))) @@ -544,17 +556,19 @@ class DevelopActivity(activity.Activity): def write_file(self, file_path): """Wrap up the activity as a bundle and save it to journal. """ + logging.error('WRITE_FILE') if self.activity_dir is None: return - if not self.save_unchanged: + if self.save_unchanged: self.editor.save_all() - filenames = OPENFILE_SEPARATOR.join(self.editor.get_all_filenames()) + filenames = self.editor.get_all_filenames() logging.debug('activity_dir %s, file_path %s, filenames %s' % - (self.activity_dir, file_path, len(filenames))) + (self.activity_dir, file_path, filenames)) self._jobject = self.save_source_jobject( self.activity_dir, file_path, filenames) self.metadata['source'] = self.activity_dir - self.set_dirty(False) + self._set_dirty(False) + self.save_unchanged = False def read_file(self, file_path): self.activity_dir = self.metadata['source'] @@ -564,45 +578,39 @@ class DevelopActivity(activity.Activity): f = open(file_path, 'r') try: session_data = simplejson.load(f) - for filename in \ - session_data['open_filenames'].split(OPENFILE_SEPARATOR): + logging.error('read_file session_data %s', session_data) + for filename in session_data['open_filenames']: if filename: logging.info('opening : %s', filename) self.load_file(filename) finally: f.close() - self.set_dirty(False) - - def is_dirty(self): - return self.dirty + self._set_dirty(False) - def set_dirty(self, dirty): + def _set_dirty(self, dirty): logging.debug("Setting dirty to %s; activity_dir is %s" % (str(dirty), str(self.activity_dir))) - self.dirty = dirty + self._dirty = dirty if dirty: self.save_unchanged = True - try: - logging.debug("Saving a pristine copy for safety") - self.save() - finally: - self.save_unchanged = False - self.dirty = dirty - def update_sidebar_to_page(self, page): + def __editor_tab_changed_cb(self, editor, new_full_path): if self.numb: #avoid infinite recursion return - if isinstance(page, sourceview_editor.GtkSourceview2Page): - source = page.full_path - tree_iter = self.model.get_iter_from_filepath(source) - if tree_iter: - tree_selection = self.treeview.get_selection() - tree_selection.unselect_all() - self.numb = True - tree_selection.select_iter(tree_iter) - self.numb = False + self.numb = True + self.activity_tree_view.select_by_file_path(new_full_path) + logging.error('new tab %s', new_full_path) + self.numb = False + + # TODO: change by a constant + if self.treenotebook.get_current_page() == 1: # symbols + GObject.idle_add(self._explore_code, None) + + def __editor_changed_cb(self, editor): + logging.error('Editor text changed') + self._set_dirty(True) def __create_empty_file_cb(self, button): alert = Alert() @@ -611,19 +619,19 @@ class DevelopActivity(activity.Activity): #HACK alert._hbox.remove(alert._buttons_box) - alert.entry = gtk.Entry() - alert._hbox.pack_start(alert.entry) + alert.entry = Gtk.Entry() + alert._hbox.pack_start(alert.entry, True, True, 0) - alert._buttons_box = gtk.HButtonBox() - alert._buttons_box.set_layout(gtk.BUTTONBOX_END) + alert._buttons_box = Gtk.HButtonBox() + alert._buttons_box.set_layout(Gtk.ButtonBoxStyle.END) alert._buttons_box.set_spacing(style.DEFAULT_SPACING) - alert._hbox.pack_start(alert._buttons_box) + alert._hbox.pack_start(alert._buttons_box, True, True, 0) icon = Icon(icon_name='dialog-cancel') - alert.add_button(gtk.RESPONSE_CANCEL, _('Cancel'), icon) + alert.add_button(Gtk.ResponseType.CANCEL, _('Cancel'), icon) icon = Icon(icon_name='dialog-ok') - alert.add_button(gtk.RESPONSE_OK, _('Ok'), icon) + alert.add_button(Gtk.ResponseType.OK, _('Ok'), icon) alert.show_all() # @@ -631,31 +639,32 @@ class DevelopActivity(activity.Activity): alert.connect('response', self.__create_file_alert_cb) def __create_file_alert_cb(self, alert, response_id): - file_name = alert.entry.get_text() - try: - path = os.path.dirname(self.editor.get_file_path()) - except: - path = self.activity_dir + if response_id is Gtk.ResponseType.OK: + file_name = alert.entry.get_text() + try: + path = os.path.dirname(self.editor.get_file_path()) + except: + path = self.activity_dir - file_path = os.path.join(path, file_name) - with open(file_path, 'w') as new_file: - new_file.write('') + file_path = os.path.join(path, file_name) + with open(file_path, 'w') as new_file: + new_file.write('') - self.refresh_files() - self.editor.load_object(file_path, file_name) + self.refresh_files() + self.editor.load_object(file_path, file_name) self.remove_alert(alert) def __remove_file_cb(self, button): file_path = self.editor.get_file_path() - msg = _('The action you will do can not be revereted.\n' - 'Do you want remove the file %s?') % file_path - alert = self.create_confirmation_alert(msg, _('WARNING')) + title = _('WARNING: The action you will do can not be reverted.') + msg = _('Do you want remove the file %s?') % file_path + alert = self.create_confirmation_alert(msg, title) alert.show() alert.connect('response', self.__remove_file_alert_cb, file_path) def __remove_file_alert_cb(self, alert, response_id, file_path): - if response_id is gtk.RESPONSE_OK: + if response_id is Gtk.ResponseType.OK: if os.path.isfile(file_path): os.unlink(file_path) self.refresh_files() @@ -663,10 +672,123 @@ class DevelopActivity(activity.Activity): self.remove_alert(alert) -class DevelopEditToolbar(activity.EditToolbar): +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() + + self._tree_view.props.headers_visible = False + 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' + + 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 + + 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): - activity.EditToolbar.__init__(self) + EditToolbar.__init__(self) self._activity = _activity self._activity.editor.connect('changed', self._changed_cb) @@ -679,7 +801,7 @@ class DevelopEditToolbar(activity.EditToolbar): # make expanded non-drawn visible separator to make #the search stuff right-align - separator = gtk.SeparatorToolItem() + separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) self.insert(separator, -1) @@ -706,7 +828,7 @@ class DevelopEditToolbar(activity.EditToolbar): # 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 = Gtk.ToolItem() tool_item.set_expand(expand) tool_item.add(widget) @@ -716,10 +838,10 @@ class DevelopEditToolbar(activity.EditToolbar): tool_item.show() -class DevelopSearchToolbar(gtk.Toolbar): +class DevelopSearchToolbar(Gtk.Toolbar): def __init__(self, _activity): - gtk.Toolbar.__init__(self) + GObject.GObject.__init__(self) self._activity = _activity @@ -790,7 +912,7 @@ class DevelopSearchToolbar(gtk.Toolbar): (_('Advanced search'), ssho, True, "regex"), ): if not name: - menuitem = gtk.SeparatorMenuItem() + menuitem = Gtk.SeparatorMenuItem() else: menuitem = MenuItem(name, icon) menuitem.connect('activate', function, options) @@ -799,7 +921,7 @@ class DevelopSearchToolbar(gtk.Toolbar): # make expanded non-drawn visible separator to make the replace #stuff right-align - separator = gtk.SeparatorToolItem() + separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) self.insert(separator, -1) @@ -829,7 +951,7 @@ class DevelopSearchToolbar(gtk.Toolbar): (_('Replace all'), ssro, True, "multi-replace"), ): if not name: - menuitem = gtk.SeparatorMenuItem() + menuitem = Gtk.SeparatorMenuItem() else: menuitem = MenuItem(name, icon) menuitem.connect('activate', function, options) @@ -842,7 +964,7 @@ class DevelopSearchToolbar(gtk.Toolbar): self._activity.connect('key_press_event', self._on_key_press_event) def _on_key_press_event(self, widget, event): - keyname = gtk.gdk.keyval_name(event.keyval) + keyname = Gdk.keyval_name(event.keyval) if "F5" <= keyname and keyname <= "F8": if keyname == "F5": self._go_to_search_entry_cb() @@ -959,7 +1081,6 @@ class DevelopSearchToolbar(gtk.Toolbar): pass #self._replace_button.set_sensitive(True) - def _findnext_cb(self, button=None): ftext = self._search_entry.props.text if ftext: @@ -969,7 +1090,7 @@ class DevelopSearchToolbar(gtk.Toolbar): # 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 = Gtk.ToolItem() tool_item.set_expand(expand) tool_item.add(widget) diff --git a/develop-activity/logviewer.py b/develop-activity/logviewer.py index 73d3007..d4e30f8 100644 --- a/develop-activity/logviewer.py +++ b/develop-activity/logviewer.py @@ -22,155 +22,154 @@ import os.path import logging from gettext import gettext as _ -import gtk -import gio +from gi.repository import Gdk +from gi.repository import Gtk +from gi.repository import Gio +from gi.repository import GObject -import activity_model -from sourceview_editor import TabLabel +from sugar3.graphics import style +from sugar3 import env -#does not import develop_app, but references internals from the activity, -# as passed to init. -#In other words, needs refactoring. +from sourceview_editor import TabLabel def _get_filename_from_path(path): return os.path.split(path)[-1] -class LogMinder(gtk.VBox): - def __init__(self, activity, namefilter, path=None, extra_files=None): - self.activity = activity +class LogFilesViewer(Gtk.ScrolledWindow): + __gtype_name__ = 'LogFileViewer' + + __gsignals__ = { + 'file-selected': (GObject.SignalFlags.RUN_FIRST, + None, + ([str])), + } + + def __init__(self, namefilter): + self._openlogs = [] - logging.info('creating MultiLogView') - if not path: - # Main path to watch: ~/.sugar/someuser/logs... - path = os.path.join(os.path.expanduser("~"), ".sugar", "default", - "logs") - - if not extra_files: - # extra files to watch in logviewer - extra_files = [] - extra_files.append("/var/log/Xorg.0.log") - extra_files.append("/var/log/syslog") - extra_files.append("/var/log/messages") - - self._logs_path = path + '/' - self._active_log = None - self._extra_files = extra_files + logging.info('creating LogFilesViewer namefilter %s', namefilter) + self._path = env.get_logs_path() + logging.error('LOGS PATH %s', self._path) + + self._extra_files = [os.path.join(self._path, 'shell.log')] self._namefilter = namefilter - # Creating Main treeview with Actitivities list - self._tv_menu = gtk.TreeView() - self._tv_menu.connect('cursor-changed', self._load_log) - self._tv_menu.set_rules_hint(True) - cellrenderer = gtk.CellRendererText() - self.treecolumn = gtk.TreeViewColumn(_("Sugar logs"), cellrenderer, - text=1) - self._tv_menu.append_column(self.treecolumn) - self._tv_menu.set_size_request(220, 900) + Gtk.ScrolledWindow.__init__(self) - # Create scrollbars around the tree view. - scrolled = gtk.ScrolledWindow() - scrolled.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) - scrolled.add(self._tv_menu) + self.props.hscrollbar_policy = Gtk.PolicyType.AUTOMATIC + self.props.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC + self.set_size_request(style.GRID_CELL_SIZE * 3, -1) - # the internals of the treeview - self._model = activity_model.DirectoryAndExtraModel( - path, extra_files, self._filter_by_name) + self._tree_view = Gtk.TreeView() + self._tree_view.connect('cursor-changed', self.__cursor_changed_cb) + self.add(self._tree_view) + self._tree_view.show() - self._tv_menu.set_model(self._model) + self._tree_view.props.headers_visible = False + selection = self._tree_view.get_selection() + selection.connect('changed', self.__selection_changed_cb) - self._logs = {} - self._monitors = [] + 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) - # Activities menu - self.activity.treenotebook.add_page(_("Log"), scrolled) + # Configuration + self.set_title(_("Sugar logs")) + self.init_logs(self._filter_by_name) + self._monitors = [] self._configure_watcher() def _configure_watcher(self): - logging.error('Monitor directory %s', self._logs_path) - dir_monitor = gio.File(self._logs_path).monitor_directory() + logging.error('Monitor directory %s', self._path) + directory = Gio.File.new_for_path(self._path) + dir_monitor = directory.monitor_directory( + flags=Gio.FileMonitorFlags.NONE, cancellable=None) dir_monitor.set_rate_limit(2000) dir_monitor.connect('changed', self._log_file_changed_cb) self._monitors.append(dir_monitor) - for f in self._extra_files: logging.error('Monitor file %s', f) - file_monitor = gio.File(f).monitor_file() + gio_file = Gio.File.new_for_path(f) + file_monitor = gio_file.monitor_file( + Gio.FileMonitorFlags.NONE, None) file_monitor.set_rate_limit(2000) file_monitor.connect('changed', self._log_file_changed_cb) self._monitors.append(file_monitor) def _log_file_changed_cb(self, monitor, path1, path2, event): - _directory, logfile = os.path.split(str(path1)) - - if event == gio.FILE_MONITOR_EVENT_CHANGED: + if event == Gio.FileMonitorEvent.CHANGED: for log in self._openlogs: - if logfile in log.full_path: + if path1.get_path() == log.full_path: + logging.debug('updating logfile %s', path1.get_path()) log.update() - elif (event == gio.FILE_MONITOR_EVENT_DELETED - or event == gio.FILE_MONITOR_EVENT_CREATED): - self._model.refresh() - #If the log is open, just leave it that way - - # Load the log information in View (text_view) - def _load_log(self, treeview): - node = activity_model.get_selected_file(self._tv_menu) - print node - path = node["path"] - - if os.path.isdir(path): - #do not try to open folders - logging.debug("Cannot open a folder as text :)") + elif (event == Gio.FileMonitorEvent.DELETED + or event == Gio.FileMonitorEvent.CREATED): + self.load_model() + + def _filter_by_name(self, filename): + return self._namefilter in filename or filename in self._extra_files + + def init_logs(self, filter_function): + self._filter_function = filter_function + self.load_model() + + def load_model(self): + self._tree_view.set_model(Gtk.TreeStore(str, str)) + self._model = self._tree_view.get_model() + self._add_dir_to_model(self._path, self._filter_function) + + def _add_dir_to_model(self, dir_path, filter_function, parent=None): + for f in os.listdir(dir_path): + 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, filter_function, new_iter) + else: + if filter_function(full_path): + self._model.append(parent, [f, full_path]) + + 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, treeview): + selection = treeview.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 treeview.row_expanded(path): + treeview.collapse_row(path) + else: + treeview.expand_row(path, False) - if not path: - #DummyActivityNode - return + def set_title(self, title): + self._column.set_title(title) - # Set buffer and scroll down - if self.activity.editor.set_to_page_like(path): - return - newlogview = LogView(path, self) - - scrollwnd = gtk.ScrolledWindow() - scrollwnd.set_policy(gtk.POLICY_AUTOMATIC, - gtk.POLICY_AUTOMATIC) - scrollwnd.add(newlogview) - scrollwnd.page = newlogview - tablabel = TabLabel(newlogview, label=node["name"]) - tablabel.connect( - 'tab-close', - lambda widget, child: self.activity.editor.remove_page( - self.activity.editor.page_num(child))) - self.activity.editor.append_page(scrollwnd, tablabel) - self._active_log = newlogview - self.activity.editor.show_all() - self.activity.editor.set_current_page(-1) - - def _filter_by_name(self, node): - return (self._namefilter in node.filename) or node.isDirectory - - # Insert a Row in our TreeView - def _insert_row(self, store, parent, name): - iter = store.insert_before(parent, None) - index = 0 - store.set_value(iter, index, name) - - return iter - - def _remove_logview(self, logview): + def remove_logview(self, logview): try: self._openlogs.remove(logview) except ValueError: logging.debug("_remove_logview failed") -class LogBuffer(gtk.TextBuffer): - def __init__(self, logfile, tagtable): - gtk.TextBuffer.__init__(self, table=tagtable) +class LogBuffer(Gtk.TextBuffer): + + def __init__(self, logfile): + Gtk.TextBuffer.__init__(self) self._logfile = logfile self._pos = 0 @@ -193,62 +192,62 @@ class LogBuffer(gtk.TextBuffer): self._written = 0 -class LogView(gtk.TextView): +class LogView(Gtk.TextView): - def __init__(self, full_path, logminder): - gtk.TextView.__init__(self) + def __init__(self, full_path, log_file_viewer): + GObject.GObject.__init__(self) - self.logminder = logminder + self._log_file_viewer = log_file_viewer self.full_path = full_path - self.logminder._openlogs.append(self) + self._log_file_viewer._openlogs.append(self) - self.set_wrap_mode(gtk.WRAP_WORD) - - # Tags for search - tagtable = gtk.TextTagTable() - hilite_tag = gtk.TextTag('search-hilite') - hilite_tag.props.background = '#FFFFB0' - tagtable.add(hilite_tag) - select_tag = gtk.TextTag('search-select') - select_tag.props.background = '#B0B0FF' - tagtable.add(select_tag) + self.set_wrap_mode(Gtk.WrapMode.WORD) - newbuffer = self._create_log_buffer(full_path, tagtable) + newbuffer = self._create_log_buffer(full_path) if newbuffer: self.set_buffer(newbuffer) self.text_buffer = newbuffer # Set background color - bgcolor = gtk.gdk.color_parse("#EEEEEE") - self.modify_base(gtk.STATE_NORMAL, bgcolor) + bgcolor = Gdk.color_parse("#EEEEEE") + self.modify_base(Gtk.StateType.NORMAL, bgcolor) self.set_editable(False) self.show() def remove(self): - self.logminder._remove_logview(self) + self._log_file_viewer.remove_logview(self) - def _create_log_buffer(self, path, tagtable): + def _create_log_buffer(self, path): self._written = False if os.path.isdir(path): return False if not os.path.exists(path): - logging.error("ERROR: %s don't exists", path) + logging.error("_create_log_buffer: %s don't exists", path) return False if not os.access(path, os.R_OK): - logging.error("ERROR: I can't read '%s' file", path) + logging.error("_create_log_buffer: I can't read '%s' file", path) return False self.filename = _get_filename_from_path(path) - self._logbuffer = logbuffer = LogBuffer(path, tagtable) + self._logbuffer = LogBuffer(path) + + # Tags for search + tagtable = self._logbuffer.get_tag_table() + hilite_tag = Gtk.TextTag.new('search-hilite') + hilite_tag.props.background = '#FFFFB0' + tagtable.add(hilite_tag) + select_tag = Gtk.TextTag.new('search-select') + select_tag.props.background = '#B0B0FF' + tagtable.add(select_tag) - self._written = logbuffer._written + self._written = self._logbuffer._written - return logbuffer + return self._logbuffer def replace(self, *args, **kw): return (False, False) @@ -267,7 +266,8 @@ class LogView(gtk.TextView): text_iter = _buffer.get_start_iter() while True: - next_found = text_iter.forward_search(text, 0) + next_found = text_iter.forward_search( + text, Gtk.TextSearchFlags.CASE_INSENSITIVE, None) if next_found is None: break start, end = next_found @@ -291,9 +291,11 @@ class LogView(gtk.TextView): text_iter = _buffer.get_iter_at_mark(_buffer.get_insert()) if direction == 'backward': - return text_iter.backward_search(self.search_text, 0) + return text_iter.backward_search( + self.search_text, Gtk.TextSearchFlags.CASE_INSENSITIVE, None) else: - return text_iter.forward_search(self.search_text, 0) + return text_iter.forward_search( + self.search_text, Gtk.TextSearchFlags.CASE_INSENSITIVE, None) def search_next(self, direction): next_found = self.get_next_result(direction) @@ -306,5 +308,4 @@ class LogView(gtk.TextView): _buffer.apply_tag_by_name('search-select', start, end) _buffer.place_cursor(start) - self.scroll_to_iter(start, 0.1) - self.scroll_to_iter(end, 0.1) + self.scroll_to_iter(start, 0.1, False, 0, 0) diff --git a/develop-activity/new_activity.py b/develop-activity/new_activity.py index e939005..24f8a29 100644 --- a/develop-activity/new_activity.py +++ b/develop-activity/new_activity.py @@ -17,7 +17,7 @@ import os import shutil import logging -from sugar.activity import activity +from sugar3.activity import activity def class_template(name): diff --git a/develop-activity/setup.py b/develop-activity/setup.py index 530f97c..c60f4d0 100755 --- a/develop-activity/setup.py +++ b/develop-activity/setup.py @@ -16,6 +16,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -from sugar.activity import bundlebuilder +from sugar3.activity import bundlebuilder bundlebuilder.start() diff --git a/develop-activity/sourceview_editor.py b/develop-activity/sourceview_editor.py index e29caed..e1278c7 100644 --- a/develop-activity/sourceview_editor.py +++ b/develop-activity/sourceview_editor.py @@ -15,40 +15,48 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import logging -import gtk -import gobject -import pango -import gtksourceview2 +from gi.repository import Gtk +from gi.repository import Gdk +from gi.repository import GObject +from gi.repository import Pango +from gi.repository import GtkSource import os.path import re import mimetypes from exceptions import ValueError, TypeError, IOError, OSError +from sugar3 import profile +from sugar3.graphics.icon import Icon + from widgets import TabLabel +import logviewer class S_WHERE: selection, file, multifile = range(3) # an enum -class GtkSourceview2Editor(gtk.Notebook): +class GtkSourceview2Editor(Gtk.Notebook): __gsignals__ = { - 'changed': (gobject.SIGNAL_RUN_FIRST, None, []) + 'changed': (GObject.SignalFlags.RUN_FIRST, None, []), + 'tab-changed': (GObject.SignalFlags.RUN_FIRST, None, [str]) } - def __init__(self, activity): - gtk.Notebook.__init__(self) - self.activity = activity - self.set_size_request(gtk.gdk.screen_width(), -1) + def __init__(self): + GObject.GObject.__init__(self) + self.set_size_request(Gdk.Screen.width(), -1) self.connect('page-removed', self._page_removed_cb) self.connect('switch-page', self._switch_page_cb) def _page_removed_cb(self, __notebook, page, n): - page.page.remove() + try: + page.page.remove() + except: + pass + # the welcome page do not have a page property def _switch_page_cb(self, __notebook, page_gptr, page_num): - self.activity.update_sidebar_to_page(self._get_page(page_num)) - self.activity.explore_code(None, switch_page=False) + self.emit('tab-changed', self._get_page(page_num).full_path) def set_to_page_like(self, full_path): for n in range(self.get_n_pages()): @@ -61,15 +69,23 @@ class GtkSourceview2Editor(gtk.Notebook): def load_object(self, full_path, filename): if self.set_to_page_like(full_path): return - scrollwnd = gtk.ScrolledWindow() - scrollwnd.set_policy(gtk.POLICY_AUTOMATIC, - gtk.POLICY_AUTOMATIC) + scrollwnd = Gtk.ScrolledWindow() + scrollwnd.set_policy(Gtk.PolicyType.AUTOMATIC, + Gtk.PolicyType.AUTOMATIC) page = GtkSourceview2Page(full_path) + + vbox = Gtk.VBox() + if full_path.endswith('.svg'): + icon = Icon(file=full_path, pixel_size=100, + xo_color=profile.get_color()) + vbox.pack_start(icon, False, False, 0) + + vbox.pack_start(scrollwnd, True, True, 0) scrollwnd.add(page) - scrollwnd.page = page + vbox.page = page label = filename - page.text_buffer.connect('changed', self._changed_cb) + page.text_buffer.connect('changed', self.__text_changed_cb) tablabel = TabLabel(scrollwnd, label) tablabel.connect( @@ -77,17 +93,30 @@ class GtkSourceview2Editor(gtk.Notebook): lambda widget, child: self.remove_page(self.page_num(child))) tablabel.page = page - self.append_page(scrollwnd, tablabel) + self.append_page(vbox, tablabel) + + self.__text_changed_cb(page.text_buffer) + self.show_all() + self.set_current_page(-1) - self._changed_cb(page.text_buffer) + def load_log_file(self, full_path, log_files_viewer): + logview = logviewer.LogView(full_path, log_files_viewer) + scrollwnd = Gtk.ScrolledWindow() + scrollwnd.set_policy(Gtk.PolicyType.AUTOMATIC, + Gtk.PolicyType.AUTOMATIC) + scrollwnd.add(logview) + scrollwnd.page = logview + tablabel = TabLabel(logview, os.path.basename(full_path)) + tablabel.connect( + 'tab-close', lambda widget, child: + self.remove_page(self.page_num(child))) + self.append_page(scrollwnd, tablabel) self.show_all() self.set_current_page(-1) - def _changed_cb(self, buffer): + def __text_changed_cb(self, buffer): if not buffer.can_undo(): buffer.set_modified(False) - elif not self.activity.dirty: - self.activity.set_dirty(True) self.emit('changed') def _get_page(self, order=-1): @@ -96,7 +125,7 @@ class GtkSourceview2Editor(gtk.Notebook): else: n = order if self.get_nth_page(n) is not None: - return self.get_nth_page(n).get_children()[0] + return self.get_nth_page(n).page else: return None @@ -120,13 +149,13 @@ class GtkSourceview2Editor(gtk.Notebook): def copy(self): page = self._get_page() if page: - clip = gtk.Clipboard() + clip = Gtk.Clipboard() page.get_buffer().copy_clipboard(clip) def paste(self): page = self._get_page() if page: - clip = gtk.Clipboard() + clip = Gtk.Clipboard() text = clip.wait_for_text() page.get_buffer().insert_at_cursor(text) @@ -201,7 +230,8 @@ class GtkSourceview2Editor(gtk.Notebook): def get_text(self): buff = self._get_page().text_buffer - return buff.get_text(buff.get_start_iter(), buff.get_end_iter()) + return buff.get_text(buff.get_start_iter(), buff.get_end_iter(), + False) def get_file_path(self): return self._get_page().full_path @@ -213,16 +243,16 @@ class GtkSourceview2Editor(gtk.Notebook): page = self._get_page() _buffer = page.get_buffer() _iter = _buffer.get_iter_at_line(line - 1) - page.scroll_to_iter(_iter, 0.0) + page.scroll_to_iter(_iter, 0.1, False, 0, 0) -class GtkSourceview2Page(gtksourceview2.View): +class GtkSourceview2Page(GtkSource.View): def __init__(self, full_path): ''' Do any initialization here. ''' - gtksourceview2.View.__init__(self) + GtkSource.View.__init__(self) self.full_path = full_path @@ -232,22 +262,23 @@ class GtkSourceview2Page(gtksourceview2.View): self.set_show_line_numbers(True) self.set_insert_spaces_instead_of_tabs(True) + self.text_buffer = GtkSource.Buffer() + # Tags for search - tagtable = gtk.TextTagTable() - hilite_tag = gtk.TextTag('search-hilite') + tagtable = self.text_buffer.get_tag_table() + hilite_tag = Gtk.TextTag.new('search-hilite') hilite_tag.props.background = '#FFFFB0' tagtable.add(hilite_tag) - select_tag = gtk.TextTag('search-select') + select_tag = Gtk.TextTag.new('search-select') select_tag.props.background = '#B0B0FF' tagtable.add(select_tag) - self.text_buffer = gtksourceview2.Buffer(tag_table=tagtable) self.set_buffer(self.text_buffer) self.set_tab_width(4) self.set_auto_indent(True) - self.modify_font(pango.FontDescription('Monospace 10')) + self.modify_font(Pango.FontDescription('Monospace 10')) self.load_text() self.show() @@ -266,7 +297,7 @@ class GtkSourceview2Page(gtksourceview2.View): self.text_buffer.set_highlight_syntax(False) mime_type = mimetypes.guess_type(self.full_path)[0] if mime_type: - lang_manager = gtksourceview2.language_manager_get_default() + lang_manager = GtkSource.LanguageManager.get_default() lang_ids = lang_manager.get_language_ids() langs = [lang_manager.get_language(i) for i in lang_ids] for lang in langs: @@ -284,7 +315,8 @@ class GtkSourceview2Page(gtksourceview2.View): def save(self): if self.text_buffer.can_undo(): # only save if there's something to buff = self.text_buffer - text = buff.get_text(buff.get_start_iter(), buff.get_end_iter()) + text = buff.get_text(buff.get_start_iter(), buff.get_end_iter(), + False) _file = file(self.full_path, 'w') try: _file.write(text) @@ -384,7 +416,8 @@ class GtkSourceview2Page(gtksourceview2.View): text_iter = _buffer.get_start_iter() while True: - next_found = text_iter.forward_search(text, 0) + next_found = text_iter.forward_search( + text, Gtk.TextSearchFlags.CASE_INSENSITIVE, None) if next_found is None: break start, end = next_found @@ -408,9 +441,11 @@ class GtkSourceview2Page(gtksourceview2.View): text_iter = _buffer.get_iter_at_mark(_buffer.get_insert()) if direction == 'backward': - return text_iter.backward_search(self.search_text, 0) + return text_iter.backward_search( + self.search_text, Gtk.TextSearchFlags.CASE_INSENSITIVE, None) else: - return text_iter.forward_search(self.search_text, 0) + return text_iter.forward_search( + self.search_text, Gtk.TextSearchFlags.CASE_INSENSITIVE, None) def search_next(self, direction): next_found = self.get_next_result(direction) @@ -423,5 +458,4 @@ class GtkSourceview2Page(gtksourceview2.View): _buffer.apply_tag_by_name('search-select', start, end) _buffer.place_cursor(start) - self.scroll_to_iter(start, 0.1) - self.scroll_to_iter(end, 0.1) + self.scroll_to_iter(start, 0.1, False, 0, 0) diff --git a/develop-activity/symbols_tree.py b/develop-activity/symbols_tree.py index 939debf..eb234d3 100644 --- a/develop-activity/symbols_tree.py +++ b/develop-activity/symbols_tree.py @@ -14,30 +14,32 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -import gtk -import gobject +from gi.repository import Gtk +from gi.repository import GdkPixbuf +from gi.repository import GObject -class SymbolsTree(gtk.TreeView): +class SymbolsTree(Gtk.TreeView): - __gsignals__ = {'symbol-selected': (gobject.SIGNAL_RUN_FIRST, None, [int])} + __gsignals__ = {'symbol-selected': (GObject.SignalFlags.RUN_FIRST, None, + [int])} def __init__(self): - gtk.TreeView.__init__(self) + GObject.GObject.__init__(self) - self._model = gtk.TreeStore(gtk.gdk.Pixbuf, str, str) + self._model = Gtk.TreeStore(GdkPixbuf.Pixbuf, str, int) self.set_model(self._model) - column = gtk.TreeViewColumn('Symbols') - icon_cell = gtk.CellRendererPixbuf() + column = Gtk.TreeViewColumn('Symbols') + icon_cell = Gtk.CellRendererPixbuf() column.pack_start(icon_cell, False) column.add_attribute(icon_cell, 'pixbuf', 0) - name_cell = gtk.CellRendererText() + name_cell = Gtk.CellRendererText() column.pack_start(name_cell, True) column.add_attribute(name_cell, 'text', 1) - line_cell = gtk.CellRendererText() + line_cell = Gtk.CellRendererText() line_cell.props.visible = False column.pack_start(line_cell, False) column.add_attribute(line_cell, 'text', 2) @@ -46,28 +48,29 @@ class SymbolsTree(gtk.TreeView): self.connect('cursor-changed', self._symbol_selected_cb) def _add_class(self, name, line): - pixbuf = gtk.gdk.pixbuf_new_from_file_at_size('icons/class.png', 24, - 24) + pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size('icons/class.png', 24, + 24) parent = self._model.append(None, (pixbuf, name, line)) return parent def _add_method(self, name, line, parent=None): - pixbuf = gtk.gdk.pixbuf_new_from_file_at_size('icons/function.png', - 24, 24) + pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size('icons/function.png', + 24, 24) self._model.append(parent, (pixbuf, name, line)) def _add_attribute(self, name, line, parent=None): - pixbuf = gtk.gdk.pixbuf_new_from_file_at_size('icons/attribute.png', - 24, 24) + pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size('icons/attribute.png', + 24, 24) self._model.append(parent, (pixbuf, name, line)) def _symbol_selected_cb(self, widget): selection = self.get_selection() - model, _iter = selection.get_selected() - line = int(model.get_value(_iter, 2)) - if line is 0: - return - self.emit('symbol-selected', line) + model, iter = selection.get_selected() + if iter is not None: + line = model.get_value(iter, 2) + if line is 0: + return + self.emit('symbol-selected', line) def load_symbols(self, data): self._model.clear() diff --git a/develop-activity/widgets.py b/develop-activity/widgets.py index 4e7da2e..27382c4 100644 --- a/develop-activity/widgets.py +++ b/develop-activity/widgets.py @@ -17,37 +17,37 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -import gtk -import gobject +from gi.repository import Gtk +from gi.repository import GObject -from sugar.graphics.icon import Icon +from sugar3.graphics.icon import Icon -class TabLabel(gtk.HBox): +class TabLabel(Gtk.HBox): __gtype_name__ = 'BrowseTabLabel' __gsignals__ = { - 'tab-close': (gobject.SIGNAL_RUN_FIRST, + 'tab-close': (GObject.SignalFlags.RUN_FIRST, None, ([object])), } def __init__(self, child, label=""): - gtk.HBox.__init__(self) + GObject.GObject.__init__(self) self._child = child - self._label = gtk.Label(label) + self._label = Gtk.Label(label=label) self._label.set_alignment(0, 0.5) self.pack_start(self._label, True, True, 0) self._label.show() - self.modify_base(gtk.STATE_NORMAL, gtk.gdk.Color(0, 0, 0, 1)) + #self.modify_base(Gtk.StateType.NORMAL, Gdk.Color(0, 0, 0, 1)) close_tab_icon = Icon(icon_name='close-tab') - button = gtk.Button() - button.props.relief = gtk.RELIEF_NONE + button = Gtk.Button() + button.props.relief = Gtk.ReliefStyle.NONE button.props.focus_on_click = False - icon_box = gtk.HBox() + icon_box = Gtk.HBox() icon_box.pack_start(close_tab_icon, True, False, 0) button.add(icon_box) button.connect('clicked', self.__button_clicked_cb) -- cgit v0.9.1