diff options
author | Walter Bender <walter@sugarlabs.org> | 2014-02-12 16:57:12 (GMT) |
---|---|---|
committer | Walter Bender <walter@sugarlabs.org> | 2014-02-12 16:57:12 (GMT) |
commit | ba745c6c112f5620d5866a518fe35dc79aea5f54 (patch) | |
tree | f6242380eaedc78aef40d4d97bf0187c67b9c3ea | |
parent | 8335d339faff28c22a1c3b6cf55ad17909b11f93 (diff) |
more cleaning up of tab load/save
-rw-r--r-- | NEWS | 6 | ||||
-rw-r--r-- | notebook.py | 38 | ||||
-rw-r--r-- | pippy_app.py | 148 |
3 files changed, 128 insertions, 64 deletions
@@ -1,7 +1,11 @@ 57 -ENHANCEMENT: +ENHANCEMENTS: * Set tab label with file name when loading examples +* Set focus on text view + +BUG FIX: +* Sort out numerous cases regarding saving/restoring tabs/tabs content 56 diff --git a/notebook.py b/notebook.py index f2f636e..a916ef6 100644 --- a/notebook.py +++ b/notebook.py @@ -16,6 +16,9 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +import logging +import unicodedata + from gi.repository import Gtk from gi.repository import Gdk from gi.repository import GObject @@ -23,17 +26,14 @@ from gi.repository import Vte from gi.repository import Pango from gi.repository import GtkSource from gettext import gettext as _ -from sugar3.graphics.icon import Icon + from port.style import font_zoom -from sugar3.graphics import style +from sugar3.graphics.icon import Icon +from sugar3.graphics import style from sugar3.graphics.toolbutton import ToolButton -SIZE_X = Gdk.Screen.width() -SIZE_Y = Gdk.Screen.height() - - class TabLabel(Gtk.HBox): __gsignals__ = { 'tab-close': (GObject.SignalFlags.RUN_FIRST, @@ -46,7 +46,7 @@ class TabLabel(Gtk.HBox): self.child = child self.label_text = label - self._path = path + self._path = path # Hide the path in the label self.tabs = tabs self.label_box = Gtk.EventBox() @@ -110,15 +110,13 @@ class TabLabel(Gtk.HBox): self._label.set_text(self.label_text) -""" +class AddNotebook(Gtk.Notebook): + """ AddNotebook ----------- This subclass has a add button which emits tab-added on clicking the button. -""" - - -class AddNotebook(Gtk.Notebook): + """ __gsignals__ = { 'tab-added': (GObject.SignalFlags.RUN_FIRST, None, @@ -144,9 +142,8 @@ class SourceNotebook(AddNotebook): self.set_scrollable(True) def add_tab(self, label=None, buffer_text=None, path=None): - - # Set text_buffer text_buffer = GtkSource.Buffer() + lang_manager = GtkSource.LanguageManager.get_default() if hasattr(lang_manager, 'list_languages'): langs = lang_manager.list_languages() @@ -163,15 +160,13 @@ class SourceNotebook(AddNotebook): text_buffer.set_highlight(True) else: text_buffer.set_highlight_syntax(True) - if buffer_text: text_buffer.set_text(buffer_text) text_buffer.set_modified(False) - # Set up SourceView text_view = GtkSource.View() text_view.set_buffer(text_buffer) - text_view.set_size_request(0, int(SIZE_Y * 0.5)) + text_view.set_size_request(0, int(Gdk.Screen.height() * 0.5)) text_view.set_editable(True) text_view.set_cursor_visible(True) text_view.set_show_line_numbers(True) @@ -187,6 +182,9 @@ class SourceNotebook(AddNotebook): codesw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) codesw.add(text_view) + text_view.show() + text_view.set_can_focus(True) + text_view.grab_focus() tabdex = self.get_n_pages() + 1 if label: @@ -196,7 +194,9 @@ class SourceNotebook(AddNotebook): _("New Source File %d" % tabdex), path, self) tablabel.connect("tab-close", self._tab_closed_cb) + codesw.show_all() + index = self.append_page(codesw, tablabel) self.props.page = index # Set new page as active tab @@ -221,8 +221,6 @@ class SourceNotebook(AddNotebook): return text_view def _purify_file(self, label): - import unicodedata - if not label.endswith(".py"): label = label + ".py" @@ -275,6 +273,8 @@ class SourceNotebook(AddNotebook): index = self.page_num(child) self.remove_page(index) try: + logging.debug('deleting session_data %s' % + str(self.activity.session_data[index])) del self.activity.session_data[index] except IndexError: pass diff --git a/pippy_app.py b/pippy_app.py index c267d8c..9880a85 100644 --- a/pippy_app.py +++ b/pippy_app.py @@ -25,7 +25,7 @@ """Pippy Activity: A simple Python programming activity .""" from __future__ import with_statement -import logging + import re import os import subprocess @@ -89,6 +89,9 @@ DEFAULT_CATEGORIES = [_('graphics'), _('math'), _('python'), _('sound'), from sugar3.graphics.toolbarbox import ToolbarButton from sugar3.graphics.toolbutton import ToolButton +import logging +_logger = logging.getLogger('pippy-activity') + # get screen sizes SIZE_X = Gdk.Screen.width() SIZE_Y = Gdk.Screen.height() @@ -127,15 +130,14 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): self.initial_text_buffer = GtkSource.Buffer() self.loaded_from_journal = False self.py_file = False - self.loaded_session = [] - self.session_data = [] + self.pippy_instance = self + self.loaded_session = [] # Used to manage tabs + self.session_data = [] # Used to manage saving self.dialog = None sys.path.append(os.path.join(self.get_activity_root(), 'Library')) def initialize_display(self): - self._logger = logging.getLogger('pippy-activity') - # Activity toolbar with title input, share button and export buttons: activity_toolbar = self.activity_button.page @@ -287,8 +289,8 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): lang = 'en' else: lang = locale_lang.split('_')[0] - self._logger.debug(locale.getdefaultlocale()) - self._logger.debug(lang) + _logger.debug(locale.getdefaultlocale()) + _logger.debug(lang) # construct the path for both lang_path = os.path.join(data_path, lang) @@ -339,7 +341,8 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): for name, content, path in self.loaded_session: self.source_tabs.add_tab(name, content, path) else: - self.source_tabs.add_tab() + self.session_data.append(None) + self.source_tabs.add_tab() # New instance, ergo empty tab vpane.add1(self.source_tabs) @@ -406,7 +409,9 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): def _add_source_cb(self, button): self.source_tabs.add_tab() + self.session_data.append(None) self.source_tabs.get_nth_page(-1).show_all() + self.source_tabs.get_text_view().grab_focus() def vte_drop_cb(self, widget, context, x, y, selection, targetType, time): if targetType == TARGET_TYPE_TEXT: @@ -414,13 +419,13 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): def selection_cb(self, value): self.save() - self._logger.debug('clicked! %s' % value['path']) + _logger.debug('clicked! %s' % value['path']) _file = open(value['path'], 'r') lines = _file.readlines() text_buffer = self.source_tabs.get_text_buffer() text_buffer.set_text(''.join(lines)) text_buffer.set_modified(False) - self.metadata['title'] = value['name'] + self.pippy_instance.metadata['title'] = value['name'] self.stopbutton_cb(None) self._reset_vte() self.source_tabs.set_current_label(value['name']) @@ -470,7 +475,8 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): text_buffer = self.source_tabs.get_text_buffer() text_buffer.set_text('') text_buffer.set_modified(False) - self.metadata['title'] = _('%s Activity') % get_bundle_name() + self.pippy_instance.metadata['title'] = \ + _('%s Activity') % get_bundle_name() self.stopbutton_cb(None) self._reset_vte() self.source_tabs.get_text_view().grab_focus() @@ -638,8 +644,10 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): file_path = dsitem.get_file_path() content = open(file_path, 'r').read() - self.source_tabs.add_tab(name, content) + self.source_tabs.add_tab(name, content, None) + self.source_tabs.set_current_label(name) self.session_data.append(dsitem.object_id) + _logger.debug('after import py: %r' % self.session_data) chooser.destroy() @@ -648,7 +656,7 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): from tempfile import mkdtemp # Get the name of this pippy program. - title = self.metadata['title'].replace('.py', '') + title = self.pippy_instance.metadata['title'].replace('.py', '') title = title.replace('-', '') if title == 'Pippy Activity': alert = Alert() @@ -677,7 +685,7 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): os.path.join(self.get_activity_root(), TMPDIR)) sourcefile = os.path.join(app_temp, 'xyzzy.py') # invoke ourself to build the activity bundle. - self._logger.debug('writing out source file: %s' % sourcefile) + _logger.debug('writing out source file: %s' % sourcefile) def internal_callback(window=None, event=None): icon = '%s/activity/activity-default.svg' % (get_bundle_path()) @@ -693,7 +701,7 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): os.path.join(self.get_activity_root(), TMPDIR)) sourcefile = os.path.join(app_temp, 'xyzzy.py') # Invoke ourself to build the activity bundle. - self._logger.debug('writing out source file: %s' % sourcefile) + _logger.debug('writing out source file: %s' % sourcefile) # Write out application code self._write_text_buffer(sourcefile) @@ -750,7 +758,7 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): filenames = ','.join([("'"+name[:-3]+"'") for name in data[0]]) - title = self.metadata['title'] + title = self.pippy_instance.metadata['title'] if title is _('Pippy Activity'): from sugar3.graphics.alert import Alert from sugar3.graphics.icon import Icon @@ -797,7 +805,7 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): def _export_example_cb(self, __): # Get the name of this pippy program. - title = self.metadata['title'] + title = self.pippy_instance.metadata['title'] if title == _('Pippy Activity'): from sugar3.graphics.alert import Alert from sugar3.graphics.icon import Icon @@ -846,7 +854,7 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): bundle_file = [f for f in os.listdir(app_temp) if f.endswith('.xo')] if len(bundle_file) != 1: - self._logger.debug("Couldn't find bundle: %s" % + _logger.debug("Couldn't find bundle: %s" % str(bundle_file)) self._vte.feed('\r\n') self._vte.feed(_('Error saving activity to journal.')) @@ -898,55 +906,83 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): self.model.set_value(_iter, 1, entry['name']) def save_to_journal(self, file_path, cloudstring): - _file = open(file_path, 'w') if not self.shared_activity: data = self.source_tabs.get_all_data() zipped_data = zip(data[0], data[1], data[2], data[3]) - sessionlist = [] + session_list = [] app_temp = os.path.join(self.get_activity_root(), 'instance') tmpfile = os.path.join(app_temp, 'pippy-tempfile-storing.py') for zipdata, content in map(None, zipped_data, self.session_data): name, python_code, path, modified = zipdata - if content is not None and content[0] != '/': - self._logger.debug('Saving an existing dsobject') + if content is not None and \ + content == self._jobject.object_id: + _logger.debug('saving to self') + self.metadata['title'] = name + self.metadata['mime_type'] = 'text/x-python' + __file = open(file_path, 'w') + __file.write(python_code) + __file.close() + session_list.append([name, content]) + elif content is not None and content[0] != '/': + _logger.debug('Saving an existing dsobject') dsitem = datastore.get(content) + dsitem.metadata['title'] = name + dsitem.metadata['mime_type'] = 'text/x-python' __file = open(tmpfile, 'w') __file.write(python_code) __file.close() dsitem.set_file_path(tmpfile) - dsitem.metadata['title'] = name datastore.write(dsitem) - sessionlist.append([name, dsitem.object_id]) + session_list.append([name, dsitem.object_id]) elif modified: - self._logger.debug('Creating new dsobj for modified code') + _logger.debug('Creating new dsobj for modified code') if len(python_code) > 0: dsobject = datastore.create() - dsobject.metadata['mime_type'] = 'text/x-python' dsobject.metadata['title'] = name + dsobject.metadata['mime_type'] = 'text/x-python' __file = open(tmpfile, 'w') __file.write(python_code) __file.close() dsobject.set_file_path(tmpfile) datastore.write(dsobject) - sessionlist.append([name, dsobject.object_id]) + session_list.append([name, dsobject.object_id]) elif content is not None or path is not None: - self._logger.debug('Saving reference to sample file') + _logger.debug('Saving reference to sample file') if path is None: # Should not happen, but just in case... - self._logger.error('path is None.') - sessionlist.append([name, content]) + _logger.error('path is None.') + session_list.append([name, content]) else: - sessionlist.append([name, path]) + session_list.append([name, path]) else: # Should not happen, but just in case... - self._logger.error('Nothing to save in tab?') + _logger.error('Nothing to save in tab? %s %s %s %s' % + (str(name), str(python_code), str(path), + str(content))) - self.metadata['mime_type'] = 'application/json' - _file.write(json.dumps(sessionlist)) + self.pippy_instance.metadata['mime_type'] = 'application/json' + pippy_data = json.dumps(session_list) else: - self.metadata['mime_type'] = groupthink_mimetype - _file.write(cloudstring) + self.pippy_instance.metadata['mime_type'] = groupthink_mimetype + pippy_data = cloudstring + + # Override file path if we created a new Pippy instance + if self.loaded_from_journal and self.py_file: + file_path = os.path.join(app_temp, 'pippy-temp-instance-data') + _file = open(file_path, 'w') + _file.write(pippy_data) + _file.close() + if self.loaded_from_journal and self.py_file: + _logger.debug('setting pippy instance file_path to %s' % + file_path) + self.pippy_instance.set_file_path(file_path) + datastore.write(self.pippy_instance) def load_from_journal(self, file_path): + # Either we are opening Python code or a list of objects + # stored (json-encoded) in a Pippy instance, or a shared + # session. if self.metadata['mime_type'] == 'text/x-python': + _logger.debug('Loading Python code') + # Opening some Python code directly try: text = open(file_path).read() except: @@ -961,14 +997,28 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): self.add_alert(alert) return - # discard the '#!/usr/bin/python' and 'coding: utf-8' lines, + # Discard the '#!/usr/bin/python' and 'coding: utf-8' lines, # if present text = re.sub(r'^' + re.escape(PYTHON_PREFIX), '', text) self.initial_text_buffer = text self.initial_title = self.metadata['title'] self.loaded_from_journal = self.py_file = True + + # Since we loaded Python code, we need to create a Pippy instance + self.pippy_instance = datastore.create() + self.pippy_instance.metadata['title'] = self.metadata['title'] + self.pippy_instance.metadata['mime_type'] = 'application/json' + self.pippy_instance.metadata['activity'] = 'org.laptop.Pippy' + datastore.write(self.pippy_instance) + + # Finally, add this Python object to the session data + # FIXME: There must be a better way to get the object_id + self.session_data.append(self._jobject.object_id) + _logger.debug('session_data: %s' % self.session_data) elif self.metadata['mime_type'] == 'application/json': + # Reading file list from Pippy instance + _logger.debug('Loading Pippy instance') data = json.loads(open(file_path).read()) for name, content in data: # content is either a datastore id or the path to some @@ -977,26 +1027,36 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): try: python_code = open(content).read() except: - self._logger.error('Could not open %s; skipping' % - content) + _logger.error('Could not open %s; skipping' % content) path = content else: try: dsitem = datastore.get(content) + if not 'mime_type' in dsitem.metadata: + _logger.error( + 'Warning: %s missing mime_type' % content) + elif dsitem.metadata['mime_type'] != 'text/python': + _logger.error( + 'Warning: %s has unexpected mime_type %s' % + (content, dsitem.metadata['mime_type'])) except: - self._logger.error('Could not open %s; skipping' % - content) + # Could be that the item has subsequently been + # deleted from the datastore, so we skip it. + _logger.error('Could not open %s; skipping' % content) continue try: python_code = open(dsitem.get_file_path()).read() except: - self._logger.error('Could not open %s; skipping' % - dsitem.get_file_path()) + # Malformed bundle? + _logger.error('Could not open %s; skipping' % + dsitem.get_file_path()) continue path = None + + # Queue up the creation of the tabs... self.loaded_session.append([name, python_code, path]) + # And add this content to the session data self.session_data.append(content) - elif self.metadata['mime_type'] == groupthink_mimetype: return open(file_path).read() |