Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSai Vineet <saivineet89@gmail.com>2013-12-20 20:33:18 (GMT)
committer Sai Vineet <saivineet89@gmail.com>2013-12-21 19:56:24 (GMT)
commitdbf8573535e0e8e2a29ce113ac6cc5d8f7e74d76 (patch)
treed6c85b7e3fc6e399c9023bcec8a71c5f53b2841d
parentd775a04062871bb4265ad1e05a8ced04b2315e33 (diff)
Added multiple Source File editing to Pippy
-rw-r--r--Notebook.py163
-rw-r--r--icons/close-tab.svg27
-rw-r--r--pippy_app.py173
3 files changed, 236 insertions, 127 deletions
diff --git a/Notebook.py b/Notebook.py
new file mode 100644
index 0000000..3deb3a1
--- /dev/null
+++ b/Notebook.py
@@ -0,0 +1,163 @@
+from gi.repository import Gtk
+from gi.repository import Gdk
+from gi.repository import GObject
+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.toolbutton import ToolButton
+
+
+SIZE_X = Gdk.Screen.width()
+SIZE_Y = Gdk.Screen.height()
+
+
+class TabLabel(Gtk.HBox):
+ __gsignals__ = {
+ 'tab-close': (GObject.SignalFlags.RUN_FIRST,
+ None,
+ ([GObject.TYPE_PYOBJECT])),
+ }
+
+ def __init__(self, child, label):
+ GObject.GObject.__init__(self)
+
+ self.child = child
+ self._label = Gtk.Label(label=label)
+ self._label.set_alignment(0, 0.5)
+ self.pack_start(self._label, True, True, 5)
+ self._label.show()
+
+ button = ToolButton("close-tab")
+ button.connect('clicked', self.__button_clicked_cb)
+ self.pack_start(button, False, True, 0)
+ button.show()
+ self._close_button = button
+
+ def set_text(self, title):
+ self._label.set_text(title)
+
+ def update_size(self, size):
+ self.set_size_request(size, -1)
+
+ def hide_close_button(self):
+ self._close_button.hide()
+
+ def show_close_button(self):
+ self._close_button.show()
+
+ def __button_clicked_cb(self, button):
+ self.emit('tab-close', self.child)
+
+
+"""
+ 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,
+ ([])),
+ }
+
+ def __init__(self):
+ Gtk.Notebook.__init__(self)
+
+ self._add_tab = ToolButton("gtk-add")
+ self._add_tab.connect("clicked", self._add_tab_cb)
+ self._add_tab.show()
+ self.set_action_widget(self._add_tab, Gtk.PackType.END)
+
+ def _add_tab_cb(self, button):
+ self.emit("tab-added")
+
+
+class SourceNotebook(AddNotebook):
+ def __init__(self, activity):
+ AddNotebook.__init__(self)
+ self.activity = activity
+
+ self.add_tab()
+
+ def add_tab(self, label=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()
+ else:
+ lang_ids = lang_manager.get_language_ids()
+ langs = [lang_manager.get_language(lang_id)
+ for lang_id in lang_ids]
+ for lang in langs:
+ for m in lang.get_mime_types():
+ if m == "text/x-python":
+ text_buffer.set_language(lang)
+
+ if hasattr(text_buffer, 'set_highlight'):
+ text_buffer.set_highlight(True)
+ else:
+ text_buffer.set_highlight_syntax(True)
+
+ # 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_editable(True)
+ text_view.set_cursor_visible(True)
+ text_view.set_show_line_numbers(True)
+ text_view.set_wrap_mode(Gtk.WrapMode.CHAR)
+ text_view.set_insert_spaces_instead_of_tabs(True)
+ text_view.set_tab_width(2)
+ text_view.set_auto_indent(True)
+ text_view.modify_font(
+ Pango.FontDescription("Monospace " +
+ str(font_zoom(style.FONT_SIZE))))
+
+ codesw = Gtk.ScrolledWindow()
+ codesw.set_policy(Gtk.PolicyType.AUTOMATIC,
+ Gtk.PolicyType.AUTOMATIC)
+ codesw.add(text_view)
+
+ tabdex = self.get_n_pages()
+ if label:
+ tablabel = TabLabel(codesw, label)
+ else:
+ tablabel = TabLabel(codesw,
+ _("New Source File %d" % tabdex))
+ 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
+
+ def get_text_buffer(self):
+ tab = self.get_nth_page(self.get_current_page()).get_children()
+ text_buffer = tab[0].get_buffer()
+ return text_buffer
+
+ def get_text_view(self):
+ tab = self.get_nth_page(self.get_current_page()).get_children()
+ text_view = tab[0]
+ return text_view
+
+ def child_exited_cb(self, *args):
+ """Called whenever a child exits. If there's a handler, runadd it."""
+ h, self.activity._child_exited_handler = \
+ self.activity._child_exited_handler, None
+ if h is not None:
+ h()
+
+ def _tab_closed_cb(self, notebook, child):
+ index = self.page_num(child)
+ self.remove_page(index)
diff --git a/icons/close-tab.svg b/icons/close-tab.svg
new file mode 100644
index 0000000..782ad24
--- /dev/null
+++ b/icons/close-tab.svg
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
+ <!ENTITY fill_color "#FFFFFF">
+ <!ENTITY stroke_color "#010101">
+]>
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ width="22.16"
+ height="22.16"
+ viewBox="0 0 22.16 22.16"
+ id="browse-close-tab"
+ xml:space="preserve">
+ <g
+ transform="matrix(1.3,0,0,1.3,-3.2682282,-3.3351543)"
+ id="browse-dialog-cancel"
+ style="stroke:&fill_color;;stroke-width:2.69230771;stroke-miterlimit:4;stroke-dasharray:none">
+ <path
+ d="M 14.798121,7.2131543 6.9900671,15.021208"
+ id="path2986"
+ style="fill:none;stroke:&fill_color;;stroke-width:2.69230771;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ <path
+ d="M 6.9900671,7.2131543 14.798121,15.021208"
+ id="path3756"
+ style="fill:none;stroke:&fill_color;;stroke-width:2.69230771;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ </g>
+</svg>
diff --git a/pippy_app.py b/pippy_app.py
index e03516a..0349d86 100644
--- a/pippy_app.py
+++ b/pippy_app.py
@@ -78,6 +78,8 @@ SIZE_Y = Gdk.Screen.height()
groupthink_mimetype = 'pickle/groupthink-pippy'
+from Notebook import SourceNotebook, AddNotebook
+
class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity):
"""Pippy Activity as specified in activity.info"""
@@ -200,9 +202,10 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity):
stop = StopButton(self)
self.get_toolbar_box().toolbar.insert(stop, -1)
- # Main layout.
- self.vpane = Gtk.Paned.new(orientation=Gtk.Orientation.VERTICAL)
- self.vpane.set_position(400) # setting initial position
+ self.paths = []
+
+ vpane = Gtk.Paned.new(orientation=Gtk.Orientation.VERTICAL)
+ vpane.set_position(400) # setting initial position
self.paths = []
@@ -251,56 +254,13 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity):
root = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'], 'data')
self.paths.append([_('My examples'), root])
- # Source buffer
- from gi.repository import GtkSource
- global text_buffer
- lang_manager = GtkSource.LanguageManager.get_default()
- if hasattr(lang_manager, 'list_languages'):
- langs = lang_manager.list_languages()
- else:
- lang_ids = lang_manager.get_language_ids()
- langs = [lang_manager.get_language(lang_id)
- for lang_id in lang_ids]
- for lang in langs:
- for m in lang.get_mime_types():
- if m == "text/x-python":
- text_buffer.set_language(lang)
-
- if hasattr(text_buffer, 'set_highlight'):
- text_buffer.set_highlight(True)
- else:
- text_buffer.set_highlight_syntax(True)
-
- # The GTK source view window
- self.text_view = GtkSource.View()
- self.text_view.set_buffer(text_buffer)
- self.text_view.set_size_request(0, int(SIZE_Y * 0.5))
- self.text_view.set_editable(True)
- self.text_view.set_cursor_visible(True)
- self.text_view.set_show_line_numbers(True)
- self.text_view.set_wrap_mode(Gtk.WrapMode.CHAR)
- self.text_view.set_insert_spaces_instead_of_tabs(True)
- self.text_view.set_tab_width(2)
- self.text_view.set_auto_indent(True)
- self.text_view.modify_font(
- Pango.FontDescription("Monospace " +
- str(font_zoom(style.FONT_SIZE))))
-
- # We could change the color theme here, if we want to.
- #mgr = GtkSource.style_manager_get_default()
- #style_scheme = mgr.get_scheme('kate')
- #self.text_buffer.set_style_scheme(style_scheme)
-
- codesw = Gtk.ScrolledWindow()
- codesw.set_policy(Gtk.PolicyType.AUTOMATIC,
- Gtk.PolicyType.AUTOMATIC)
- codesw.add(self.text_view)
- self.vpane.add1(codesw)
-
- # An hbox to hold the vte window and its scrollbar.
- self.outbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
-
- # The vte python window
+
+ self.source_tabs = SourceNotebook(self)
+ self.source_tabs.connect("tab-added", self._add_source_cb)
+
+ vpane.add1(self.source_tabs)
+
+ outbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
self._vte = Vte.Terminal()
self._vte.set_encoding('utf-8')
self._vte.set_size(30, 5)
@@ -310,24 +270,19 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity):
Gdk.color_parse('#E7E7E7'),
[])
self._vte.connect('child_exited', self.child_exited_cb)
+
self._child_exited_handler = None
-
- # FIXME It does not work because it expects and receives StructMeta
- # Gtk.TargetEntry
- #
- # self._vte.drag_dest_set(Gtk.DestDefaults.ALL,
- # [("text/plain", 0, TARGET_TYPE_TEXT)],
- # Gdk.DragAction.COPY)
-
self._vte.connect('drag_data_received', self.vte_drop_cb)
- self.outbox.pack_start(self._vte, True, True, 0)
+ outbox.pack_start(self._vte, True, True, 0)
outsb = Gtk.Scrollbar(orientation=Gtk.Orientation.VERTICAL)
outsb.set_adjustment(self._vte.get_vadjustment())
outsb.show()
- self.outbox.pack_start(outsb, False, False, 0)
- self.vpane.add2(self.outbox)
- return self.vpane
+ outbox.pack_start(outsb, False, False, 0)
+ vpane.add2(outbox)
+ self.outbox = outbox
+
+ return vpane
def after_init(self):
self.outbox.hide()
@@ -352,7 +307,7 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity):
self._select_func_cb(path)
def when_shared(self):
- global text_buffer
+ text_buffer = self.source_tabs.get_text_buffer()
self.cloud.sharefield = \
groupthink.gtk_tools.TextBufferSharePoint(text_buffer)
# HACK : There are issues with undo/redoing while in shared
@@ -361,6 +316,10 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity):
self._edit_toolbar.undo.set_sensitive(False)
self._edit_toolbar.redo.set_sensitive(False)
+ def _add_source_cb(self, button):
+ self.source_tabs.add_tab()
+ self.source_tabs.get_nth_page(-1).show_all()
+
def vte_drop_cb(self, widget, context, x, y, selection, targetType, time):
if targetType == TARGET_TYPE_TEXT:
self._vte.feed_child(selection.data)
@@ -370,7 +329,7 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity):
self._logger.debug("clicked! %s" % value['path'])
_file = open(value['path'], 'r')
lines = _file.readlines()
- global text_buffer
+ text_buffer = self.source_tabs.get_text_buffer()
text_buffer.set_text("".join(lines))
text_buffer.set_modified(False)
self.metadata['title'] = value['name']
@@ -379,13 +338,13 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity):
self.text_view.grab_focus()
def _select_func_cb(self, path):
- global text_buffer
+ text_buffer = self.source_tabs.get_text_buffer()
if text_buffer.get_modified():
from sugar3.graphics.alert import ConfirmationAlert
alert = ConfirmationAlert()
- alert.props.title = _('Example-selection Warning')
- alert.props.msg = _('You have modified the currently selected \
-file. Discard changes?')
+ alert.props.title = _('Example selection Warning')
+ alert.props.msg = _('You have modified the currently selected file. \
+ Discard changes?')
alert.connect('response', self._discard_changes_cb, path)
self.add_alert(alert)
return False
@@ -404,7 +363,7 @@ file. Discard changes?')
values['name'] = os.path.basename(path)
values['path'] = path
self.selection_cb(values)
- global text_buffer
+ text_buffer = self.source_tabs.get_text_buffer()
text_buffer.set_modified(False)
def timer_cb(self, button, icons):
@@ -419,16 +378,16 @@ file. Discard changes?')
def clearbutton_cb(self, button):
self.save()
- global text_buffer
+ 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.stopbutton_cb(None)
self._reset_vte()
- self.text_view.grab_focus()
+ self.source_tabs.get_text_view().grab_focus()
def _write_text_buffer(self, filename):
- global text_buffer
+ text_buffer = self.source_tabs.get_text_buffer()
start, end = text_buffer.get_bounds()
text = text_buffer.get_text(start, end, True)
@@ -444,25 +403,23 @@ file. Discard changes?')
self._vte.grab_focus()
self._vte.feed("\x1B[H\x1B[J\x1B[0;39m")
- def __undobutton_cb(self, button):
- global text_buffer
+ def __undobutton_cb(self, butston):
+ text_buffer = self.source_tabs.get_text_buffer()
if text_buffer.can_undo():
text_buffer.undo()
def __redobutton_cb(self, button):
- global text_buffer
+ text_buffer = self.source_tabs.get_text_buffer()
if text_buffer.can_redo():
text_buffer.redo()
def __copybutton_cb(self, button):
- global text_buffer
- clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
- text_buffer.copy_clipboard(clipboard)
+ text_buffer = self.source_tabs.get_text_buffer()
+ text_buffer.copy_clipboard(Gtk.Clipboard())
def __pastebutton_cb(self, button):
- global text_buffer
- clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
- text_buffer.paste_clipboard(clipboard, None, True)
+ text_buffer = self.source_tabs.get_text_buffer()
+ text_buffer.paste_clipboard(Gtk.Clipboard(), None, True)
def gobutton_cb(self, button):
from shutil import copy2
@@ -503,19 +460,9 @@ file. Discard changes?')
def _export_document_cb(self, __):
self.copy()
- alert = NotifyAlert()
- alert.props.title = _('Saved')
- alert.props.msg = _('The document has been saved to journal.')
- alert.connect('response', lambda x, i: self.remove_alert(x))
- self.add_alert(alert)
def _create_bundle_cb(self, __):
- self.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
-
- GObject.idle_add(self._create_bundle)
-
- def _create_bundle(self):
- from shutil import rmtree
+ from shutil import copytree, copy2, rmtree
from tempfile import mkdtemp
# get the name of this pippy program.
@@ -532,7 +479,6 @@ file. Discard changes?')
alert.add_button(Gtk.ResponseType.OK, _('Ok'), ok_icon)
alert.connect('response', self.dismiss_alert_cb)
self.add_alert(alert)
- self.get_window().set_cursor(None)
return
self.stopbutton_cb(None) # try stopping old code first.
@@ -563,11 +509,8 @@ file. Discard changes?')
rmtree(app_temp, ignore_errors=True) # clean up!
self._vte.feed(_('Save as Activity Error'))
self._vte.feed("\r\n")
- self.get_window().set_cursor(None)
raise
- self.get_window().set_cursor(None)
-
def _export_example_cb(self, __):
# get the name of this pippy program.
title = self.metadata['title']
@@ -685,20 +628,7 @@ Do you want to overwrite it?')
def load_from_journal(self, file_path):
if self.metadata['mime_type'] == 'text/x-python':
- try:
- text = open(file_path).read()
- except:
- alert = NotifyAlert(10)
- alert.props.title = _('Error')
- alert.props.msg = _('Error reading data.')
-
- def remove_alert(alert, response_id):
- self.remove_alert(alert)
-
- alert.connect("response", remove_alert)
- self.add_alert(alert)
- return
-
+ text = open(file_path).read()
# discard the '#!/usr/bin/python' and 'coding: utf-8' lines,
# if present
text = re.sub(r'^' + re.escape(PYTHON_PREFIX), '', text)
@@ -732,20 +662,7 @@ viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block"
id="activity-pippy">
- <path d="M28.497,48.507
- c5.988,0,14.88-2.838,14.88-11.185c0-9.285-7.743-10.143-10.954-11.083\
-c-3.549-0.799-5.913-1.914-6.055-3.455
- c-0.243-2.642,1.158-3.671,3.946-3.671c0,0,6.632,3.664,12.266,0.74\
-c1.588-0.823,4.432-4.668,4.432-7.32
- c0-2.653-9.181-5.719-11.967-5.719c-2.788,0-5.159,3.847-5.159,3.847\
-c-5.574,0-11.149,5.306-11.149,10.612
- c0,5.305,5.333,9.455,11.707,10.612c2.963,0.469,5.441,2.22,4.878,\
-5.438c-0.457,2.613-2.995,5.306-8.361,5.306
- c-4.252,0-13.3-0.219-14.745-4.079c-0.929-2.486,0.168-5.205,\
-1.562-5.205l-0.027-0.16c-1.42-0.158-5.548,0.16-5.548,5.465
- C8.202,45.452,17.347,48.507,28.497,48.507z"
- fill="&fill_color;" stroke="&stroke_color;" stroke-linecap="round"
- stroke-linejoin="round" stroke-width="3.5"/>
+ <path d="M28.497,48.507 c5.988,0,14.88-2.838,14.88-11.185c0-9.285-7.743-10.143-10.954-11.083c-3.549-0.799-5.913-1.914-6.055-3.455 c-0.243-2.642,1.158-3.671,3.946-3.671c0,0,6.632,3.664,12.266,0.74c1.588-0.823,4.432-4.668,4.432-7.32 c0-2.653-9.181-5.719-11.967-5.719c-2.788,0-5.159,3.847-5.159,3.847c-5.574,0-11.149,5.306-11.149,10.612 c0,5.305,5.333,9.455,11.707,10.612c2.963,0.469,5.441,2.22,4.878,5.438c-0.457,2.613-2.995,5.306-8.361,5.306 c-4.252,0-13.3-0.219-14.745-4.079c-0.929-2.486,0.168-5.205,1.562-5.205l-0.027-0.16c-1.42-0.158-5.548,0.16-5.548,5.465 C8.202,45.452,17.347,48.507,28.497,48.507z" fill="&fill_color;" stroke="&stroke_color;" stroke-linecap="round" stroke-linejoin="round" stroke-width="3.5"/>
<path d="M42.579,19.854c-2.623-0.287-6.611-2-7.467-5.022" fill="none"
stroke="&stroke_color;" stroke-linecap="round" stroke-width="3"/>
<circle cx="35.805" cy="10.96" fill="&stroke_color;" r="1.676"/>
@@ -876,6 +793,7 @@ def main():
from pyclbr import readmodule_ex
from tempfile import mkdtemp
from shutil import copytree, copy2, rmtree
+ from sugar3 import profile
from sugar3.activity import bundlebuilder
import sys
@@ -992,3 +910,4 @@ if __name__ == '__main__':
main()
print(_("done!"))
sys.exit(0)
+