[Sugar-devel] [PATCH] Add cpu and memory resource indicator to frame

2010-07-28 Thread anishmangal2002
This patch adds an icon to the frame, whose palette
menu displays the memory and cpu resources. For computing
free memory, the code reads the /proc/meminfo file (thanks
quozl) and for computing cpu usage, the code reads the
/proc/stat file.

The frame icon is updated after every 5 seconds if required.
Similarly, the palette menu entries are updated after every
5 seconds as well.

Signed-off-by: anishmangal2002 anishmangal2...@gmail.com
---
 extensions/deviceicon/Makefile.am  |3 +-
 extensions/deviceicon/resources.py |  206 
 2 files changed, 208 insertions(+), 1 deletions(-)
 create mode 100644 extensions/deviceicon/resources.py

diff --git a/extensions/deviceicon/Makefile.am 
b/extensions/deviceicon/Makefile.am
index 8a2e765..038c059 100644
--- a/extensions/deviceicon/Makefile.am
+++ b/extensions/deviceicon/Makefile.am
@@ -5,4 +5,5 @@ sugar_PYTHON =  \
battery.py  \
network.py  \
speaker.py  \
-   volume.py
+   volume.py   \
+   resources.py
diff --git a/extensions/deviceicon/resources.py 
b/extensions/deviceicon/resources.py
new file mode 100644
index 000..331459d
--- /dev/null
+++ b/extensions/deviceicon/resources.py
@@ -0,0 +1,206 @@
+# Copyright (C) Anish Mangal anishmangal2...@gmail.com
+#
+# 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
+
+from gettext import gettext as _
+import logging
+import os
+
+import gobject
+import gtk
+import gconf
+
+from sugar.graphics.tray import TrayIcon
+from sugar.graphics.xocolor import XoColor
+from sugar.graphics.palette import Palette
+from sugar.graphics import style
+
+_SYSTEM_MOODS = ['-sad', '-normal', '-happy']
+_ICON_NAME = 'computer'
+
+class DeviceView(TrayIcon):
+
+FRAME_POSITION_RELATIVE = 500
+
+def __init__(self):
+client = gconf.client_get_default()
+self._color = XoColor(client.get_string('/desktop/sugar/user/color'))
+TrayIcon.__init__(self, icon_name=_ICON_NAME, xo_color=self._color)
+self.create_palette()
+
+def create_palette(self):
+logging.debug('palette created')
+self.palette = ResourcePalette(_('System resources'))
+self.palette.set_group_id('frame')
+self.palette.add_timer()
+self.palette.connect('system-mood-changed',
+self._system_mood_changed_cb)
+return self.palette
+
+def _system_mood_changed_cb(self, gobject, mood):
+self.icon.props.icon_name = _ICON_NAME + mood
+
+class ResourcePalette(Palette):
+__gsignals__ = {
+'system-mood-changed': (gobject.SIGNAL_RUN_FIRST,
+   gobject.TYPE_NONE,
+   ([str]))
+}
+
+def __init__(self, primary_text):
+Palette.__init__(self, label=primary_text)
+
+self.vbox = gtk.VBox()
+self.set_content(self.vbox)
+
+self._cpu_text = gtk.Label()
+self.vbox.pack_start(self._cpu_text, padding=style.DEFAULT_PADDING)
+self._cpu_bar = gtk.ProgressBar()
+self._cpu_bar.set_size_request(
+style.zoom(style.GRID_CELL_SIZE * 4), -1)
+self.vbox.pack_start(self._cpu_bar, padding=style.DEFAULT_PADDING)
+
+self._memory_text = gtk.Label()
+self.vbox.pack_start(self._memory_text, padding=style.DEFAULT_PADDING)
+self._memory_bar = gtk.ProgressBar()
+self._memory_bar.set_size_request(
+style.zoom(style.GRID_CELL_SIZE * 4), -1)
+self.vbox.pack_start(self._memory_bar, padding=style.DEFAULT_PADDING)
+
+try:
+self._cpu_times = self._get_cpu_times_list()
+except IOError:
+logging.exception('An error ocurred while attempting to '
+'read /proc/stat')
+self._stop_computing_statistics()
+
+self.vbox.show()
+self._cpu_text.show()
+self._cpu_bar.show()
+self._memory_text.show()
+self._memory_bar.show()
+
+def add_timer(self):
+self._timer = gobject.timeout_add(5000, self.__timer_cb)
+
+def _get_cpu_times_list(self):
+Return various cpu times as read from /proc/stat
+
+This method returns the following cpu times measured
+in jiffies (1/100 of a second for x86 systems)
+as an ordered list of numbers - [user, nice

[Sugar-devel] [PATCH] Add icons for memory and cpu resource indicator

2010-07-28 Thread anishmangal2002
This patch adds the following for svg icons for the memory and cpu
usage indicator frame icon.

computer-happy
computer-normal
computer-sad
computer-error

Signed-off-by: anishmangal2002 anishmangal2...@gmail.com
---
 icons/scalable/device/Makefile.am |4 
 icons/scalable/device/computer-error.svg  |   11 +++
 icons/scalable/device/computer-happy.svg  |   13 +
 icons/scalable/device/computer-normal.svg |   11 +++
 icons/scalable/device/computer-sad.svg|   12 
 5 files changed, 51 insertions(+), 0 deletions(-)
 create mode 100644 icons/scalable/device/computer-error.svg
 create mode 100644 icons/scalable/device/computer-happy.svg
 create mode 100644 icons/scalable/device/computer-normal.svg
 create mode 100644 icons/scalable/device/computer-sad.svg

diff --git a/icons/scalable/device/Makefile.am 
b/icons/scalable/device/Makefile.am
index 28818ab..4ab0a56 100644
--- a/icons/scalable/device/Makefile.am
+++ b/icons/scalable/device/Makefile.am
@@ -38,6 +38,10 @@ icon_DATA =  \
battery-charging-100.svg\
camera-external.svg \
camera.svg  \
+   computer-error.svg  \
+   computer-happy.svg  \
+   computer-normal.svg \
+   computer-sad.svg\
computer.svg\
computer-xo.svg \
drive.svg   \
diff --git a/icons/scalable/device/computer-error.svg 
b/icons/scalable/device/computer-error.svg
new file mode 100644
index 000..ca280d3
--- /dev/null
+++ b/icons/scalable/device/computer-error.svg
@@ -0,0 +1,11 @@
+?xml version=1.0 ?
+!-- Created with Inkscape (http://www.inkscape.org/) --!DOCTYPE svg
+  PUBLIC '-//W3C//DTD SVG 1.1//EN'
+  'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+   !ENTITY stroke_color #010101
+   !ENTITY fill_color #ff
+]
+svg height=55 id=Layer_1 version=1.1 viewBox=0 0 55 55 width=55 
xml:space=preserve xmlns=http://www.w3.org/2000/svg; 
xmlns:svg=http://www.w3.org/2000/svg;defs id=defs9/g id=computer 
style=display:block
+   path d=m 51.322,41.549 h 0.002 l -0.022,-0.018 c -0.15,-0.109 
-12.64,-7.878 -12.64,-7.878 V 9.734 c 0,-1.618 -1.31,-2.932 -2.929,-2.932 h 
-30.9 c -1.619,0 -2.931,1.314 -2.931,2.932 v 26.313 c 0,1.096 0.608,2.037 
1.498,2.541 l -0.02,0.004 14.603,9.102 c 0.691,0.436 1.528,0.688 2.428,0.688 h 
28.212 c 2.352,0 4.278,-1.733 4.278,-3.85 10e-4,-1.202 -0.618,-2.275 
-1.579,-2.983 z id=module-about_x5F_my_x5F_xo 
style=fill:fill_color;;stroke:stroke_color;;stroke-width:3.48670006;stroke-linejoin:round/
+   path d=m 7.604,13.446 c 0,-0.616 0.504,-1.12 1.12,-1.12 h 23.117 c 
0.615,0 1.118,0.503 1.118,1.12 v 16.499 c 0,0.614 -0.503,1.122 -1.118,1.122 H 
8.723 c -0.615,0 -1.12,-0.508 -1.12,-1.122 l 0.001,-16.499 0,0 z id=path5 
style=fill:stroke_color;/
+/gg id=g3651g id=g3603 
transform=matrix(0.80645161,0,0,0.80645161,10.129032,3.6774194)path d=m 
42,7 12,12 0,0 id=path3599 
style=fill:none;stroke:stroke_color;;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none/path
 d=M 42,19 54,7 id=path3601 
style=fill:none;stroke:stroke_color;;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none//g/g/svg
\ No newline at end of file
diff --git a/icons/scalable/device/computer-happy.svg 
b/icons/scalable/device/computer-happy.svg
new file mode 100644
index 000..4f23ce1
--- /dev/null
+++ b/icons/scalable/device/computer-happy.svg
@@ -0,0 +1,13 @@
+?xml version=1.0 ?
+!-- Created with Inkscape (http://www.inkscape.org/) --!DOCTYPE svg
+  PUBLIC '-//W3C//DTD SVG 1.1//EN'
+  'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+   !ENTITY stroke_color #ff
+   !ENTITY fill_color #010101
+]
+svg height=55 id=Layer_1 version=1.1 viewBox=0 0 55 55 width=55 
xml:space=preserve xmlns=http://www.w3.org/2000/svg; 
xmlns:svg=http://www.w3.org/2000/svg;defs id=defs9/g id=computer 
style=display:block
+   path d=m 51.322,41.549 h 0.002 l -0.022,-0.018 c -0.15,-0.109 
-12.64,-7.878 -12.64,-7.878 V 9.734 c 0,-1.618 -1.31,-2.932 -2.929,-2.932 h 
-30.9 c -1.619,0 -2.931,1.314 -2.931,2.932 v 26.313 c 0,1.096 0.608,2.037 
1.498,2.541 l -0.02,0.004 14.603,9.102 c 0.691,0.436 1.528,0.688 2.428,0.688 h 
28.212 c 2.352,0 4.278,-1.733 4.278,-3.85 10e-4,-1.202 -0.618,-2.275 
-1.579,-2.983 z id=module-about_x5F_my_x5F_xo 
style=fill:stroke_color;;stroke:fill_color;;stroke-width:3.48670006;stroke-linejoin:round/
+   path d=m 7.604,13.446 c 0,-0.616 0.504,-1.12 1.12,-1.12 h 23.117 c 
0.615,0 1.118,0.503 1.118,1.12 v 16.499 c 0,0.614 -0.503,1.122 -1.118,1.122 H 
8.723 c -0.615,0 -1.12,-0.508 -1.12,-1.122 l 0.001,-16.499 0,0 z id=path5 
style=fill:fill_color;/
+/gg id=g3651path d=m 22,21.5 a 0.5,0.5 0 1 1 -1,0 0.5,0.5 0 1 1 1,0 z 
id=path2825-3 
style

[Sugar-devel] [PATCH] Browse: Add support for creating multiple tabs

2010-07-24 Thread anishmangal2002
This patch adds support to create multiple tabbed windows
in Browse. A tab may be added by either clicking the add tab
('+') icon in the activity toolbar or by pressing 'ctrl+t'.

HACK: Currently, the multiple tabs feature crashes the Browse activity
on cairo versions 1.8.10 or later. The exact cause for this
isn't exactly known. Thus, this patch disables the multiple tabs feature
if we are using cairo versions = 1.08.10
More information can be found here:
[1] http://lists.sugarlabs.org/archive/sugar-devel/2010-July/025187.html

Signed-off-by: anishmangal2002 anishmangal2...@gmail.com
---
 icons/tab-add.svg |   12 
 webactivity.py|   35 ---
 webtoolbar.py |   19 +++
 3 files changed, 59 insertions(+), 7 deletions(-)
 create mode 100644 icons/tab-add.svg

diff --git a/icons/tab-add.svg b/icons/tab-add.svg
new file mode 100644
index 000..c1457bd
--- /dev/null
+++ b/icons/tab-add.svg
@@ -0,0 +1,12 @@
+?xml version=1.0 ?!DOCTYPE svg  PUBLIC '-//W3C//DTD SVG 1.1//EN'  
'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'[
+   !ENTITY stroke_color #010101
+   !ENTITY fill_color #FF
+]svg enable-background=new 0 0 55.125 55 height=55px version=1.1 
viewBox=0 0 55.125 55 width=55.125px 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=tab-add
+g transform=scale(.80)
+g transform=translate(6.5, 6.5)
+   path d=M0,50 l55,0 l0,-15 l-5,0 l0,-25 q0,-5 -5,-5 l-35,0 q-5,0 -5,5 
l0,25 l-5,0z 
M30.768,38.767c-0.002,1.774-1.438,3.216-3.214,3.214c-0.889,0.001-1.693-0.359-2.275-0.941c-0.582-0.581-0.94-1.385-0.94-2.27
   
l0-8.146h-8.146c-0.886-0.001-1.689-0.359-2.271-0.94c-0.582-0.583-0.942-1.388-0.942-2.276c0-1.773,1.439-3.213,3.217-3.211h8.143
   
v-8.143c-0.003-1.776,1.438-3.217,3.212-3.217c1.774,0,3.218,1.438,3.215,3.215l0.001,8.145l8.146,0.001
   
c1.775-0.005,3.212,1.438,3.213,3.213c0.002,1.775-1.441,3.214-3.215,3.215h-8.143V38.767z
 fill=fill_color;/
+/g
+/g
+/g
+/svg
\ No newline at end of file
diff --git a/webactivity.py b/webactivity.py
index d7d8651..bba1032 100644
--- a/webactivity.py
+++ b/webactivity.py
@@ -31,6 +31,7 @@ import sqlite3
 import cjson
 import gconf
 import locale
+import cairo
 
 # HACK: Needed by http://dev.sugarlabs.org/ticket/456
 import gnome
@@ -154,6 +155,7 @@ def _set_accept_languages():
 logging.debug('LANG set')
 
 from browser import TabbedView
+from browser import Browser
 from webtoolbar import PrimaryToolbar
 from edittoolbar import EditToolbar
 from viewtoolbar import ViewToolbar
@@ -192,9 +194,24 @@ class WebActivity(activity.Activity):
 branch = pref_service.getBranch(mozilla.widget.)
 branch.setBoolPref(disable-native-theme, True)
 
-self._primary_toolbar = PrimaryToolbar(self._tabbed_view, self)
+# HACK
+# Currently, the multiple tabs feature crashes the Browse activity
+# on cairo versions 1.8.10 or later. The exact cause for this
+# isn't exactly known. Thus, disable the multiple tabs feature
+# if we come across cairo versions = 1.08.10
+# More information can be found here:
+# [1] 
http://lists.sugarlabs.org/archive/sugar-devel/2010-July/025187.html
+self._disable_multiple_tabs = cairo.cairo_version() = 10810
+if self._disable_multiple_tabs:
+logging.warning('Not enabling the multiple tabs feature due'
+' to a bug in cairo/mozilla')
+
+self._primary_toolbar = PrimaryToolbar(self._tabbed_view, self,
+self._disable_multiple_tabs)
 self._primary_toolbar.connect('add-link', self._link_add_button_cb)
 
+self._primary_toolbar.connect('add-tab', self._new_tab_cb)
+
 self._tray = HTray()
 self.set_tray(self._tray, gtk.POS_BOTTOM)
 self._tray.show()
@@ -258,6 +275,9 @@ class WebActivity(activity.Activity):
 else:
 _logger.debug('Created activity')
 
+def _new_tab_cb(self, gobject):
+self._load_homepage(new_tab=True)
+
 def _shared_cb(self, activity_):
 _logger.debug('My activity was shared')
 self.initiating = True
@@ -354,8 +374,14 @@ class WebActivity(activity.Activity):
 self.messenger = Messenger(self.tube_conn, self.initiating,
self.model)
 
-def _load_homepage(self):
-browser = self._tabbed_view.current_browser
+def _load_homepage(self, new_tab=False):
+# If new_tab is True, open the homepage in a new tab.
+if new_tab:
+browser = Browser()
+self._tabbed_view._append_tab(browser)
+else:
+browser = self._tabbed_view.current_browser
+
 if os.path.isfile(_LIBRARY_PATH):
 browser.load_uri('file://' + _LIBRARY_PATH)
 else:
@@ -451,6 +477,9 @@ class WebActivity(activity.Activity):
 elif key_name == 'r

[Sugar-devel] [PATCH] Add cpu and memory resource indicator to frame

2010-07-02 Thread anishmangal2002
This patch adds an icon to the frame, whose palette
menu displays the memory and cpu resources. For computing
free memory, the code reads the /proc/meminfo file (thanks
quozl) and for computing cpu usage, the code reads the
/proc/stat file.

The palette menu entries are only updated (in one second
intervals) when the palette menu is visible thus
possibly saving cpu cycles.

Signed-off-by: anishmangal2002 anishmangal2...@gmail.com
---
 extensions/deviceicon/Makefile.am  |3 +-
 extensions/deviceicon/resources.py |  159 
 2 files changed, 161 insertions(+), 1 deletions(-)
 create mode 100644 extensions/deviceicon/resources.py

diff --git a/extensions/deviceicon/Makefile.am 
b/extensions/deviceicon/Makefile.am
index 8a2e765..038c059 100644
--- a/extensions/deviceicon/Makefile.am
+++ b/extensions/deviceicon/Makefile.am
@@ -5,4 +5,5 @@ sugar_PYTHON =  \
battery.py  \
network.py  \
speaker.py  \
-   volume.py
+   volume.py   \
+   resources.py
diff --git a/extensions/deviceicon/resources.py 
b/extensions/deviceicon/resources.py
new file mode 100644
index 000..ab3fc08
--- /dev/null
+++ b/extensions/deviceicon/resources.py
@@ -0,0 +1,159 @@
+# Copyright (C) Anish Mangal anishmangal2...@gmail.com
+#
+# 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
+
+from gettext import gettext as _
+
+import logging
+import gobject
+import gtk
+import gconf
+import os
+
+from sugar.graphics.tray import TrayIcon
+from sugar.graphics.xocolor import XoColor
+from sugar.graphics.palette import Palette
+from sugar.graphics import style
+from jarabe.frame.frameinvoker import FrameWidgetInvoker
+
+class DeviceView(TrayIcon):
+
+FRAME_POSITION_RELATIVE = 500
+
+def __init__(self):
+icon_name = 'computer'
+
+client = gconf.client_get_default()
+color = XoColor(client.get_string('/desktop/sugar/user/color'))
+TrayIcon.__init__(self, icon_name=icon_name, xo_color=color)
+self.set_palette_invoker(FrameWidgetInvoker(self))
+
+def create_palette(self):
+palette = ResourcePalette(_('System resources'))
+palette.set_group_id('frame')
+return palette
+
+class ResourcePalette(Palette):
+
+def __init__(self, primary_text):
+Palette.__init__(self, label=primary_text)
+
+self.connect('popup', self._popup_cb)
+self.connect('popdown', self._popdown_cb)
+
+self._popped_up = False
+self._cpu_times = self._get_cpu_times_list()
+
+vbox = gtk.VBox()
+self.set_content(vbox)
+
+self._cpu_text = gtk.Label()
+vbox.pack_start(self._cpu_text, padding=10)
+self._cpu_text.show()
+
+self._cpu_bar = gtk.ProgressBar()
+self._cpu_bar.set_size_request(
+style.zoom(style.GRID_CELL_SIZE * 4), -1)
+vbox.pack_start(self._cpu_bar, padding=10)
+self._cpu_bar.show()
+
+self._memory_text = gtk.Label()
+vbox.pack_start(self._memory_text, padding=10)
+self._memory_text.show()
+
+self._memory_bar = gtk.ProgressBar()
+self._memory_bar.set_size_request(
+style.zoom(style.GRID_CELL_SIZE * 4), -1)
+vbox.pack_start(self._memory_bar, padding=10)
+self._memory_bar.show()
+
+vbox.show()
+
+def _get_cpu_times_list(self):
+Return various cpu times as read from /proc/stat
+
+This method returns the following cpu times as an ordered
+list of numbers - [user, nice, system, idle, iowait] where,
+
+user: normal processes executing in user mode
+nice: niced processes executing in user mode
+system: processes executing in kernel mode
+idle: twiddling thumbs
+iowait: waiting for I/O to complete
+
+
+return [int(count)
+   for count in file('/proc/stat').readline().split()[1:6]]
+
+def _percentage_cpu_available(self):
+
+Return free CPU resources as a percentage
+
+
+_cpu_times_new = self._get_cpu_times_list()
+_cpu_times_current = [(new - old)
+for new, old in zip(_cpu_times_new,
+self._cpu_times)]
+user, nice, system, idle, iowait = _cpu_times_current
+cpu_free = (idle + iowait

[Sugar-devel] [PATCH] Journal:show error message on write failure: #1842

2010-07-02 Thread anishmangal2002
volumestoolbar.py now catches the IOError and ValueError
exceptions and emits 'volume-error'signal. This signal is
caught in journalactivity.py which displays the error as
an ErrorAlert message.

Signed-off-by: anishmangal2002 anishmangal2...@gmail.com
---
 src/jarabe/journal/journalactivity.py |   16 
 src/jarabe/journal/volumestoolbar.py  |   22 +-
 2 files changed, 37 insertions(+), 1 deletions(-)

diff --git a/src/jarabe/journal/journalactivity.py 
b/src/jarabe/journal/journalactivity.py
index 0559560..eab292b 100644
--- a/src/jarabe/journal/journalactivity.py
+++ b/src/jarabe/journal/journalactivity.py
@@ -27,6 +27,9 @@ import statvfs
 import os
 
 from sugar.graphics.window import Window
+from sugar.graphics.alert import ErrorAlert
+from sugar.graphics.icon import Icon
+
 from sugar.bundle.bundle import ZipExtractException, RegistrationException
 from sugar import env
 from sugar.activity import activityfactory
@@ -138,6 +141,17 @@ class JournalActivity(Window):
 self._critical_space_alert = None
 self._check_available_space()
 
+def _alert_notify_cb(self, gobject, strerror, severity):
+alert = ErrorAlert()
+alert.props.title= severity
+alert.props.msg = strerror
+alert.connect('response', self._alert_response_cb)
+self.add_alert(alert)
+alert.show()
+
+def _alert_response_cb(self, alert, response_id):
+self.remove_alert(alert)
+
 def __realize_cb(self, window):
 wm.set_bundle_id(window.window, _BUNDLE_ID)
 activity_id = activityfactory.create_activity_id()
@@ -161,6 +175,8 @@ class JournalActivity(Window):
 self._volumes_toolbar = VolumesToolbar()
 self._volumes_toolbar.connect('volume-changed',
   self.__volume_changed_cb)
+self._volumes_toolbar.connect('volume-error', self._alert_notify_cb,
+  'Error')
 self._main_view.pack_start(self._volumes_toolbar, expand=False)
 
 search_toolbar = self._main_toolbox.search_toolbar
diff --git a/src/jarabe/journal/volumestoolbar.py 
b/src/jarabe/journal/volumestoolbar.py
index 74b974c..a6acebe 100644
--- a/src/jarabe/journal/volumestoolbar.py
+++ b/src/jarabe/journal/volumestoolbar.py
@@ -35,6 +35,9 @@ class VolumesToolbar(gtk.Toolbar):
 __gsignals__ = {
 'volume-changed': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE,
+   ([str])),
+'volume-error': (gobject.SIGNAL_RUN_FIRST,
+   gobject.TYPE_NONE,
([str]))
 }
 
@@ -81,6 +84,7 @@ class VolumesToolbar(gtk.Toolbar):
 button = VolumeButton(mount)
 button.props.group = self._volume_buttons[0]
 button.connect('toggled', self._button_toggled_cb)
+button.connect('volume-error', self._volume_error_cb)
 position = self.get_item_index(self._volume_buttons[-1]) + 1
 self.insert(button, position)
 button.show()
@@ -90,6 +94,9 @@ class VolumesToolbar(gtk.Toolbar):
 if len(self.get_children())  1:
 self.show()
 
+def _volume_error_cb(self, button, strerror):
+self.emit('volume-error', strerror)
+
 def _button_toggled_cb(self, button):
 if button.props.active:
 self.emit('volume-changed', button.mount_point)
@@ -123,6 +130,12 @@ class VolumesToolbar(gtk.Toolbar):
 button.props.active = True
 
 class BaseButton(RadioToolButton):
+__gsignals__ = {
+'volume-error': (gobject.SIGNAL_RUN_FIRST,
+   gobject.TYPE_NONE,
+   ([str]))
+}
+
 def __init__(self, mount_point):
 RadioToolButton.__init__(self)
 
@@ -137,7 +150,14 @@ class BaseButton(RadioToolButton):
info, timestamp):
 object_id = selection_data.data
 metadata = model.get(object_id)
-model.copy(metadata, self.mount_point)
+try:
+model.copy(metadata, self.mount_point)
+except IOError as (errno, strerror):
+logging.error('BaseButton._drag_data_received_cb: IOError: %s; %s' 
% (errno, strerror))
+self.emit('volume-error', strerror)
+except ValueError as (strerror):
+logging.error('BaseButton._drag_data_received_cb: ValueError: %s' 
% (strerror))
+self.emit('volume-error', strerror)
 
 class VolumeButton(BaseButton):
 def __init__(self, mount):
-- 
1.7.0.1

___
Sugar-devel mailing list
Sugar-devel@lists.sugarlabs.org
http://lists.sugarlabs.org/listinfo/sugar-devel


[Sugar-devel] [PATCH] Add ErrorAlert inherited from Alert

2010-07-02 Thread anishmangal2002
Adds the ErrorAlert class which is an alert inherited from
the base Alert class. This is very similar to the
ConfirmationAlert class with the difference being that it
only displays an 'Ok' button in the Alert popup.

Signed-off-by: anishmangal2002 anishmangal2...@gmail.com
---
 src/sugar/graphics/alert.py |   44 +++
 1 files changed, 44 insertions(+), 0 deletions(-)

diff --git a/src/sugar/graphics/alert.py b/src/sugar/graphics/alert.py
index 4441909..4dfa515 100644
--- a/src/sugar/graphics/alert.py
+++ b/src/sugar/graphics/alert.py
@@ -290,6 +290,50 @@ class ConfirmationAlert(Alert):
 self.add_button(gtk.RESPONSE_OK, _('Ok'), icon)
 icon.show()
 
+class ErrorAlert(Alert):
+
+This is a ready-made one button (Ok) alert.
+
+An error alert is a nice shortcut from a standard Alert because it
+comes with the 'OK' button already built-in. When clicked, the
+'OK' button will emit a response with a response_id of gtk.RESPONSE_OK.
+
+Examples
+
+
+.. code-block:: python
+  from sugar.graphics.alert import ErrorAlert
+  ...
+ Method: _alert_error, create a Error alert (with ok
+ button standard)
+# and add it to the UI.
+def _alert_error(self):
+alert = ErrorAlert()
+alert.props.title=_('Title of Alert Goes Here')
+alert.props.msg = _('Text message of alert goes here')
+alert.connect('response', self._alert_response_cb)
+self.add_alert(alert)
+
+
+ Method: _alert_response_cb, called when an alert object throws a
+ response event.
+def _alert_response_cb(self, alert, response_id):
+#remove the alert from the screen, since either a response button
+#was clicked or there was a timeout
+self.remove_alert(alert)
+
+#Do any work that is specific to the response_id.
+if response_id is gtk.RESPONSE_OK:
+print 'Ok Button was clicked. Do any work upon ok here ...'
+
+
+
+def __init__(self, **kwargs):
+Alert.__init__(self, **kwargs)
+
+icon = Icon(icon_name='dialog-ok')
+self.add_button(gtk.RESPONSE_OK, _('Ok'), icon)
+icon.show()
 
 class _TimeoutIcon(hippo.CanvasText, hippo.CanvasItem):
 An icon with a round border
-- 
1.7.0.1

___
Sugar-devel mailing list
Sugar-devel@lists.sugarlabs.org
http://lists.sugarlabs.org/listinfo/sugar-devel


[Sugar-devel] [PATCH] Browse: Add support for creating multiple tabs

2010-06-29 Thread anishmangal2002
This patch adds support to create multiple tabbed windows
in Browse. A tab may be added by either clicking the add tab
('+') icon in the activity toolbar or by pressing 'ctrl+t'.

Signed-off-by: anishmangal2002 anishmangal2...@gmail.com
---
 icons/add-tab.svg |   86 +
 webactivity.py|   11 +++
 webtoolbar.py |   21 +
 3 files changed, 118 insertions(+), 0 deletions(-)
 create mode 100644 icons/add-tab.svg

diff --git a/icons/add-tab.svg b/icons/add-tab.svg
new file mode 100644
index 000..0220993
--- /dev/null
+++ b/icons/add-tab.svg
@@ -0,0 +1,86 @@
+?xml version=1.0 encoding=UTF-8 standalone=no?
+!-- Created with Inkscape (http://www.inkscape.org/) --
+
+svg
+   xmlns:dc=http://purl.org/dc/elements/1.1/;
+   xmlns:cc=http://creativecommons.org/ns#;
+   xmlns:rdf=http://www.w3.org/1999/02/22-rdf-syntax-ns#;
+   xmlns:svg=http://www.w3.org/2000/svg;
+   xmlns=http://www.w3.org/2000/svg;
+   xmlns:sodipodi=http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd;
+   xmlns:inkscape=http://www.inkscape.org/namespaces/inkscape;
+   version=1.1
+   width=55
+   height=55
+   id=svg2
+   inkscape:version=0.47 r22583
+   sodipodi:docname=add-tab.svg
+  metadata
+ id=metadata10
+rdf:RDF
+  cc:Work
+ rdf:about=
+dc:formatimage/svg+xml/dc:format
+dc:type
+   rdf:resource=http://purl.org/dc/dcmitype/StillImage; /
+  /cc:Work
+/rdf:RDF
+  /metadata
+  sodipodi:namedview
+ pagecolor=#ff
+ bordercolor=#66
+ borderopacity=1
+ objecttolerance=10
+ gridtolerance=10
+ guidetolerance=10
+ inkscape:pageopacity=0
+ inkscape:pageshadow=2
+ inkscape:window-width=1280
+ inkscape:window-height=721
+ id=namedview8
+ showgrid=false
+ inkscape:zoom=4.2909091
+ inkscape:cx=27.5
+ inkscape:cy=27.033898
+ inkscape:window-x=0
+ inkscape:window-y=27
+ inkscape:window-maximized=1
+ inkscape:current-layer=layer1 /
+  defs
+ id=defs4
+inkscape:perspective
+   sodipodi:type=inkscape:persp3d
+   inkscape:vp_x=0 : 27.5 : 1
+   inkscape:vp_y=0 : 1000 : 0
+   inkscape:vp_z=55 : 27.5 : 1
+   inkscape:persp3d-origin=27.5 : 18.33 : 1
+   id=perspective12 /
+  /defs
+  g
+ transform=translate(0,-997.36218)
+ id=layer1
+rect
+   width=55
+   height=55
+   x=0
+   y=0
+   transform=translate(0,997.36218)
+   id=rect2818
+   style=fill:none;fill-opacity:1;fill-rule:evenodd;stroke:none /
+rect
+   width=9
+   height=38
+   x=23
+   y=1005.8622
+   id=rect3599
+   style=fill:#ff;fill-opacity:1;stroke:none /
+rect
+   width=8.94349
+   height=37.99044
+   x=1020.3485
+   y=-47.595592
+   transform=matrix(-0.00107369,0.9942,-0.9889,-0.00148761,0,0)
+   id=rect3599-4
+   style=fill:#ff;fill-opacity:1;stroke:none /
+  /g
+/svg
diff --git a/webactivity.py b/webactivity.py
index 4be551e..5f4f917 100644
--- a/webactivity.py
+++ b/webactivity.py
@@ -152,6 +152,7 @@ def _set_accept_languages():
 logging.debug('LANG set')
 
 from browser import TabbedView
+from browser import Browser
 from webtoolbar import PrimaryToolbar
 from edittoolbar import EditToolbar
 from viewtoolbar import ViewToolbar
@@ -443,6 +444,16 @@ class WebActivity(activity.Activity):
 _logger.debug('keyboard: Zoom in')
 self._tabbed_view.props.current_browser.zoom_in()
 return True
+elif gtk.gdk.keyval_name(event.keyval) == t:
+browser = Browser()
+self._tabbed_view._append_tab(browser)
+if os.path.isfile(_LIBRARY_PATH):
+browser.load_uri('file://' + _LIBRARY_PATH)
+else:
+default_page = os.path.join(activity.get_bundle_path(),
+data/index.html)
+browser.load_uri(default_page)
+
 return False
 
 def _add_link(self):
diff --git a/webtoolbar.py b/webtoolbar.py
index 854345c..99979ca 100644
--- a/webtoolbar.py
+++ b/webtoolbar.py
@@ -18,6 +18,9 @@
 
 from gettext import gettext as _
 
+_LIBRARY_PATH = '/usr/share/library-common/index.html'
+
+import os
 import gobject
 import gtk
 import pango
@@ -31,6 +34,7 @@ from sugar.graphics.toolbarbox import ToolbarBox
 from sugar.activity.widgets import ActivityToolbarButton
 from sugar.activity.widgets import StopButton
 from sugar.activity import activity
+from browser import Browser
 
 import filepicker
 import places
@@ -267,6 +271,13 @@ class PrimaryToolbar(ToolbarBox):
 self.toolbar.insert(self._forward, -1)
 self._forward.show()
 
+self._add_tab = ToolButton('add-tab')
+self._add_tab.set_tooltip(_('Add a tab'))
+self._add_tab.props.sensitive = True
+self._add_tab.connect('clicked', self._add_tab_cb

[Sugar-devel] [PATCH] Add cpu and memory resource indicator to frame

2010-06-28 Thread anishmangal2002
This patch adds an icon to the frame, whose palette
menu displays the memory and cpu resources. For computing
free memory, the code reads the /proc/meminfo file (thanks
quozl) and for computing cpu usage, the code reads the
/proc/stat file.

The palette menu entries are only updated (in one second
intervals) when the palette menu is visible thus
possibly saving cpu cycles.

Signed-off-by: anishmangal2002 anishmangal2...@gmail.com
---
 extensions/deviceicon/resources.py |  142 
 1 files changed, 142 insertions(+), 0 deletions(-)
 create mode 100644 extensions/deviceicon/resources.py

diff --git a/extensions/deviceicon/resources.py 
b/extensions/deviceicon/resources.py
new file mode 100644
index 000..5da55ef
--- /dev/null
+++ b/extensions/deviceicon/resources.py
@@ -0,0 +1,142 @@
+# Copyright (C) 2010 Activity Central (http://activitycentral.org/)
+# Author: Anish Mangal anishmangal2...@gmail.com
+#
+# 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
+
+from gettext import gettext as _
+
+import logging
+import gobject
+import gtk
+import gconf
+
+from sugar.graphics.tray import TrayIcon
+from sugar.graphics.xocolor import XoColor
+from sugar.graphics.palette import Palette
+from sugar.graphics import style
+from jarabe.frame.frameinvoker import FrameWidgetInvoker
+
+class DeviceView(TrayIcon):
+
+FRAME_POSITION_RELATIVE = 500
+
+def __init__(self):
+icon_name = 'computer'
+
+client = gconf.client_get_default()
+color = XoColor(client.get_string('/desktop/sugar/user/color'))
+TrayIcon.__init__(self, icon_name=icon_name, xo_color=color)
+self.set_palette_invoker(FrameWidgetInvoker(self))
+self.connect('button-release-event', self.__button_release_event_cb)
+self.connect('expose-event', self.__expose_event_cb)
+
+def create_palette(self):
+palette = ResourcePalette(_('System Resources'))
+palette.set_group_id('frame')
+return palette
+
+def __button_release_event_cb(self, widget, event):
+return True
+
+def __expose_event_cb(self, *args):
+pass
+
+class ResourcePalette(Palette):
+
+def __init__(self, primary_text):
+Palette.__init__(self, label=primary_text)
+
+self.connect('popup', self.__popup_cb)
+self.connect('popdown', self.__popdown_cb)
+
+self.updating = False
+self.proc_stat_old = []
+self.proc_stat_new = []
+
+vbox = gtk.VBox()
+self.set_content(vbox)
+
+self._cpu_text = gtk.Label()
+vbox.pack_start(self._cpu_text, padding=10)
+self._cpu_text.show()
+self._cpu_bar = gtk.ProgressBar()
+self._cpu_bar.set_size_request(
+style.zoom(style.GRID_CELL_SIZE * 4), -1)
+vbox.pack_start(self._cpu_bar, padding=10)
+self._cpu_bar.show()
+
+self._memory_text = gtk.Label()
+vbox.pack_start(self._memory_text, padding=10)
+self._memory_text.show()
+self._memory_bar = gtk.ProgressBar()
+self._memory_bar.set_size_request(
+style.zoom(style.GRID_CELL_SIZE * 4), -1)
+vbox.pack_start(self._memory_bar, padding=10)
+self._memory_bar.show()
+
+vbox.show()
+gobject.timeout_add(1000, self.__timer_cb)
+
+def __getTimeList(self):
+statFile = file(/proc/stat, r)
+timeList = statFile.readline().split( )[2:6]
+statFile.close()
+for i in range(len(timeList)) :
+timeList[i] = int(timeList[i])
+return timeList
+
+def __timer_cb(self):
+if self.updating:
+# Computing CPU usage statistics
+self.proc_stat_new = self.__getTimeList()
+
+for i in range(len(self.proc_stat_new)) :
+self.proc_stat_new[i] -= self.proc_stat_old[i]
+
+cpu_free = (self.proc_stat_new[len(self.proc_stat_new) - 1] * 
100.00 /
+sum(self.proc_stat_new))
+
+self._cpu_text.set_label('CPU free: %d%%' % cpu_free)
+self._cpu_text.show()
+self._cpu_bar.set_fraction(cpu_free/100.0)
+
+memory_free = self.__percentage_memory_available()
+self._memory_text.set_label('Memory free: %d%%' % memory_free)
+self._memory_text.show

[Sugar-devel] [PATCH] Dynamically set number of control panel columns

2010-06-20 Thread anishmangal2002
From: anishmangal2002 anishmangal2...@gmail.com

This patch sets the number of icon-columns in the control
panel based on the screen resolution. This patch also sets
the table row spacing to GRID_CELL_SIZE.

How the number of columns are calculated:
Let 'W' be the screen width, 's' be the GRID_CELL_SIZE and
'n' be the number of icon columns that can be comfortably
accomodated. Further, lets assume that the width an icon
and its text-label occupies a horizontal space equivalent to
(2.5 * s). We may represent 'W', 'n' and 's' by the following
expression:

 W - (2 * s) =  (n * s + s) + (2.5 * n * s)

where 'W - (2 * s)' is the width of the control panel menu,
'(n * s + s)' is the cumulative column spacing of 'n' icons,
and '(2.5 * n * s)' is the width occupied by 'n' icons and
their text-labels. From the above, 'n' may be computed as

 n = (1/3.5) * ( w/s - 3 )

Signed-off-by: anishmangal2002 anishmangal2...@gmail.com
---
 src/jarabe/controlpanel/gui.py |   18 ++
 1 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/src/jarabe/controlpanel/gui.py b/src/jarabe/controlpanel/gui.py
index 51d9820..4a54310 100644
--- a/src/jarabe/controlpanel/gui.py
+++ b/src/jarabe/controlpanel/gui.py
@@ -33,7 +33,6 @@ from jarabe.controlpanel.toolbar import SectionToolbar
 from jarabe import config
 
 _logger = logging.getLogger('ControlPanel')
-_MAX_COLUMNS = 5
 
 class ControlPanel(gtk.Window):
 __gtype_name__ = 'SugarControlPanel'
@@ -41,6 +40,9 @@ class ControlPanel(gtk.Window):
 def __init__(self):
 gtk.Window.__init__(self)
 
+self._MAX_COLUMNS = int( 0.285 * ( ( gtk.gdk.screen_width() /
+style.GRID_CELL_SIZE ) - 3.0 ) )
+
 self.set_border_width(style.LINE_WIDTH)
 offset = style.GRID_CELL_SIZE
 width = gtk.gdk.screen_width() - offset * 2
@@ -110,6 +112,7 @@ class ControlPanel(gtk.Window):
 
 self._table = gtk.Table()
 self._table.set_col_spacings(style.GRID_CELL_SIZE)
+self._table.set_row_spacings(style.GRID_CELL_SIZE)
 self._table.set_border_width(style.GRID_CELL_SIZE)
 
 self._scrolledwindow = gtk.ScrolledWindow()
@@ -134,8 +137,15 @@ class ControlPanel(gtk.Window):
 except ImportError:
 del self._options['keyboard']
 
-row = 0
-column = 2
+# If the screen width only supports two columns, start
+# placing from the second row.
+if self._MAX_COLUMNS == 2:
+row = 1
+column = 0
+else:
+row = 0
+column = 2
+
 options = self._options.keys()
 options.sort()
 
@@ -157,7 +167,7 @@ class ControlPanel(gtk.Window):
column, column + 1,
row, row + 1)
 column += 1
-if column == _MAX_COLUMNS:
+if column == self._MAX_COLUMNS:
 column = 0
 row += 1
 
-- 
1.7.0.1

___
Sugar-devel mailing list
Sugar-devel@lists.sugarlabs.org
http://lists.sugarlabs.org/listinfo/sugar-devel


[Sugar-devel] [PATCH] Journal: Fix for sl#1842

2010-06-15 Thread anishmangal2002
From: anishmangal2002 anishmangal2...@gmail.com

volumestoolbar.py now catches the IOError and ValueError
exceptions and emits 'volume-error' which is caught in
journalactivity.py which inturn displayes the error as a
NotifyRedAlert message.

Signed-off-by: anishmangal2002 anishmangal2...@gmail.com
---
 src/jarabe/journal/journalactivity.py |   13 +
 src/jarabe/journal/volumestoolbar.py  |   22 +-
 2 files changed, 34 insertions(+), 1 deletions(-)

diff --git a/src/jarabe/journal/journalactivity.py 
b/src/jarabe/journal/journalactivity.py
index 0559560..d14adf7 100644
--- a/src/jarabe/journal/journalactivity.py
+++ b/src/jarabe/journal/journalactivity.py
@@ -27,6 +27,7 @@ import statvfs
 import os
 
 from sugar.graphics.window import Window
+from sugar.graphics.alert import NotifyRedAlert
 from sugar.bundle.bundle import ZipExtractException, RegistrationException
 from sugar import env
 from sugar.activity import activityfactory
@@ -138,6 +139,17 @@ class JournalActivity(Window):
 self._critical_space_alert = None
 self._check_available_space()
 
+def _alert_notify_cb(self, gobject, strerror):
+alert = NotifyRedAlert(10)
+alert.props.title=_('Alert')
+alert.props.msg = strerror
+alert.connect('response', self._alert_response_cb)
+self.add_alert(alert)
+alert.show()
+
+def _alert_response_cb(self, alert, response_id):
+self.remove_alert(alert)
+
 def __realize_cb(self, window):
 wm.set_bundle_id(window.window, _BUNDLE_ID)
 activity_id = activityfactory.create_activity_id()
@@ -161,6 +173,7 @@ class JournalActivity(Window):
 self._volumes_toolbar = VolumesToolbar()
 self._volumes_toolbar.connect('volume-changed',
   self.__volume_changed_cb)
+self._volumes_toolbar.connect('volume-error', self._alert_notify_cb)
 self._main_view.pack_start(self._volumes_toolbar, expand=False)
 
 search_toolbar = self._main_toolbox.search_toolbar
diff --git a/src/jarabe/journal/volumestoolbar.py 
b/src/jarabe/journal/volumestoolbar.py
index 74b974c..2182c78 100644
--- a/src/jarabe/journal/volumestoolbar.py
+++ b/src/jarabe/journal/volumestoolbar.py
@@ -35,6 +35,9 @@ class VolumesToolbar(gtk.Toolbar):
 __gsignals__ = {
 'volume-changed': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE,
+   ([str])),
+'volume-error': (gobject.SIGNAL_RUN_FIRST,
+   gobject.TYPE_NONE,
([str]))
 }
 
@@ -81,6 +84,7 @@ class VolumesToolbar(gtk.Toolbar):
 button = VolumeButton(mount)
 button.props.group = self._volume_buttons[0]
 button.connect('toggled', self._button_toggled_cb)
+button.connect('volume-error', self._data_ioerror_cb)
 position = self.get_item_index(self._volume_buttons[-1]) + 1
 self.insert(button, position)
 button.show()
@@ -90,6 +94,9 @@ class VolumesToolbar(gtk.Toolbar):
 if len(self.get_children())  1:
 self.show()
 
+def _data_ioerror_cb(self, button, strerror):
+self.emit('volume-error', strerror)
+
 def _button_toggled_cb(self, button):
 if button.props.active:
 self.emit('volume-changed', button.mount_point)
@@ -123,6 +130,12 @@ class VolumesToolbar(gtk.Toolbar):
 button.props.active = True
 
 class BaseButton(RadioToolButton):
+__gsignals__ = {
+'volume-error': (gobject.SIGNAL_RUN_FIRST,
+   gobject.TYPE_NONE,
+   ([str]))
+}
+
 def __init__(self, mount_point):
 RadioToolButton.__init__(self)
 
@@ -137,7 +150,14 @@ class BaseButton(RadioToolButton):
info, timestamp):
 object_id = selection_data.data
 metadata = model.get(object_id)
-model.copy(metadata, self.mount_point)
+try:
+model.copy(metadata, self.mount_point)
+except IOError as (errno, strerror):
+logging.error('BaseButton._drag_data_received_cb: IOError: %s; %s' 
% (errno, strerror))
+self.emit('volume-error', strerror)
+except ValueError as (strerror):
+logging.error('BaseButton._drag_data_received_cb: ValueError: %s' 
% (strerror))
+self.emit('volume-error', strerror)
 
 class VolumeButton(BaseButton):
 def __init__(self, mount):
-- 
1.7.0.1

___
Sugar-devel mailing list
Sugar-devel@lists.sugarlabs.org
http://lists.sugarlabs.org/listinfo/sugar-devel


[Sugar-devel] [PATCH] Journal: Fix for sl#1842

2010-06-13 Thread anishmangal2002
From: anishmangal2002 anishmangal2...@gmail.com

volumestoolbar.py now catches the IOError exception and emits
'data-ioerror' which is caught in journalactivity.py which
displayes the error as a NotifyRedAlert message.

Signed-off-by: anishmangal2002 anishmangal2...@gmail.com
---
 src/jarabe/journal/journalactivity.py |   13 +
 src/jarabe/journal/volumestoolbar.py  |   19 ++-
 2 files changed, 31 insertions(+), 1 deletions(-)

diff --git a/src/jarabe/journal/journalactivity.py 
b/src/jarabe/journal/journalactivity.py
index 0559560..9536ca3 100644
--- a/src/jarabe/journal/journalactivity.py
+++ b/src/jarabe/journal/journalactivity.py
@@ -27,6 +27,7 @@ import statvfs
 import os
 
 from sugar.graphics.window import Window
+from sugar.graphics.alert import NotifyRedAlert
 from sugar.bundle.bundle import ZipExtractException, RegistrationException
 from sugar import env
 from sugar.activity import activityfactory
@@ -138,6 +139,17 @@ class JournalActivity(Window):
 self._critical_space_alert = None
 self._check_available_space()
 
+def _alert_notify_cb(self, _volumes_toolbar, strerror):
+alert = NotifyRedAlert(10)
+alert.props.title=_('Alert')
+alert.props.msg = _(strerror)
+alert.connect('response', self._alert_response_cb)
+self.add_alert(alert)
+alert.show()
+
+def _alert_response_cb(self, alert, response_id):
+self.remove_alert(alert)
+
 def __realize_cb(self, window):
 wm.set_bundle_id(window.window, _BUNDLE_ID)
 activity_id = activityfactory.create_activity_id()
@@ -161,6 +173,7 @@ class JournalActivity(Window):
 self._volumes_toolbar = VolumesToolbar()
 self._volumes_toolbar.connect('volume-changed',
   self.__volume_changed_cb)
+self._volumes_toolbar.connect('data-ioerror', self._alert_notify_cb)
 self._main_view.pack_start(self._volumes_toolbar, expand=False)
 
 search_toolbar = self._main_toolbox.search_toolbar
diff --git a/src/jarabe/journal/volumestoolbar.py 
b/src/jarabe/journal/volumestoolbar.py
index 74b974c..33e7b88 100644
--- a/src/jarabe/journal/volumestoolbar.py
+++ b/src/jarabe/journal/volumestoolbar.py
@@ -35,6 +35,9 @@ class VolumesToolbar(gtk.Toolbar):
 __gsignals__ = {
 'volume-changed': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE,
+   ([str])),
+'data-ioerror': (gobject.SIGNAL_RUN_FIRST,
+   gobject.TYPE_NONE,
([str]))
 }
 
@@ -81,6 +84,7 @@ class VolumesToolbar(gtk.Toolbar):
 button = VolumeButton(mount)
 button.props.group = self._volume_buttons[0]
 button.connect('toggled', self._button_toggled_cb)
+button.connect('data-ioerror', self._data_ioerror_cb)
 position = self.get_item_index(self._volume_buttons[-1]) + 1
 self.insert(button, position)
 button.show()
@@ -90,6 +94,9 @@ class VolumesToolbar(gtk.Toolbar):
 if len(self.get_children())  1:
 self.show()
 
+def _data_ioerror_cb(self, button, strerror):
+self.emit('data-ioerror', strerror)
+
 def _button_toggled_cb(self, button):
 if button.props.active:
 self.emit('volume-changed', button.mount_point)
@@ -123,6 +130,12 @@ class VolumesToolbar(gtk.Toolbar):
 button.props.active = True
 
 class BaseButton(RadioToolButton):
+__gsignals__ = {
+'data-ioerror': (gobject.SIGNAL_RUN_FIRST,
+   gobject.TYPE_NONE,
+   ([str]))
+}
+
 def __init__(self, mount_point):
 RadioToolButton.__init__(self)
 
@@ -137,7 +150,11 @@ class BaseButton(RadioToolButton):
info, timestamp):
 object_id = selection_data.data
 metadata = model.get(object_id)
-model.copy(metadata, self.mount_point)
+try:
+model.copy(metadata, self.mount_point)
+except IOError as (errno, strerror):
+logging.error('BaseButton._drag_data_received_cb: %s; %s' % 
(errno, strerror))
+self.emit('data-ioerror', strerror)
 
 class VolumeButton(BaseButton):
 def __init__(self, mount):
-- 
1.7.0.4

___
Sugar-devel mailing list
Sugar-devel@lists.sugarlabs.org
http://lists.sugarlabs.org/listinfo/sugar-devel


[Sugar-devel] [PATCH] Add NotifyRedAlert inherited from NotifyAlert

2010-06-13 Thread anishmangal2002
From: anishmangal2002 anishmangal2...@gmail.com

Adds the NotifyRedAlert class which is an alert inherited from
 NotifyAlert. When the alert message is displayed, it glows the
alert bar Red before slowly fading out to black, thus resulting
in a more visible notification.

Signed-off-by: anishmangal2002 anishmangal2...@gmail.com
---
 src/sugar/graphics/alert.py |   46 +++
 1 files changed, 46 insertions(+), 0 deletions(-)

diff --git a/src/sugar/graphics/alert.py b/src/sugar/graphics/alert.py
index 4441909..b4dfee1 100644
--- a/src/sugar/graphics/alert.py
+++ b/src/sugar/graphics/alert.py
@@ -432,3 +432,49 @@ class NotifyAlert(Alert):
 self._response(gtk.RESPONSE_OK)
 return False
 return True
+
+class NotifyRedAlert(NotifyAlert):
+
+Timeout alert with only an OK button and a glowing Red border- just for 
notifications
+
+Examples
+
+
+.. code-block:: python
+  from sugar.graphics.alert import NotifyRedAlert
+  ...
+ Method: _alert_notify, create a NotifyRed alert (with only an 'OK'
+ button)
+# and add it to the UI.
+def _alert_notify(self):
+#Notice that for a NotifyRedAlert, you pass the number of seconds 
in
+#which to notify. By default, this is 5.
+alert = NotifyRedAlert(10)
+alert.props.title=_('Title of Alert Goes Here')
+alert.props.msg = _('Text message of notify alert goes here')
+alert.connect('response', self._alert_response_cb)
+self.add_alert(alert)
+
+
+
+def __init__(self, timeout=5, **kwargs):
+NotifyAlert.__init__(self, timeout, **kwargs)
+self.saturation = 255
+
+gobject.timeout_add(20, self.__modify_color_timeout)
+
+def __modify_color_timeout(self):
+if self.saturation:
+self.saturation -= 1
+
+# Form the hex color representation
+if self.saturation = 15:
+color = '#0%s' % hex(self.saturation)[2:]
+else:
+color = '#%s' % hex(self.saturation)[2:]
+else:
+return False
+
+self.modify_bg( gtk.STATE_NORMAL,  gtk.gdk.Color(color))
+self.show()
+return True
-- 
1.7.0.4

___
Sugar-devel mailing list
Sugar-devel@lists.sugarlabs.org
http://lists.sugarlabs.org/listinfo/sugar-devel


[Sugar-devel] [PATCH] Enhancements to Pippy UI

2010-06-10 Thread anishmangal2002
From: anishmangal2002 anishmangal2...@gmail.com

[1] Added a standard 'Edit' toolbar having undo, redo, copy and
paste buttons which also work when the activity is shared.

[2] When the activity is shared, the treeview in the activity host's
window does not disappear so he can load examples by clicking
on them. For other participants, the treeview is kept hidden.

[3] Bump version to v37

Tested alone on sugar-jhbuild-0.88 and as a shared session with
another sugar-jhbuild-0.88 session. (Thanks walterbender)

Signed-off-by: anishmangal2002 anishmangal2...@gmail.com
---
 NEWS   |7 +++
 activity/activity.info |2 +-
 pippy_app.py   |   34 --
 3 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/NEWS b/NEWS
index b19533b..ab6ba9e 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,10 @@
+37
+* Added a standard 'Edit' toolbar having undo, redo, copy and  
+  paste buttons which also work when the activity is shared.
+* When the activity is shared, the treeview in the activity host's
+  window does not disappear so he can load examples by clicking 
+  on them. For other participants, the treeview is kept hidden.
+
 36
 * Add COPYING based on activity.info license field, verify source file
   licenses, include LICENSE from Elements upstream SVN, fixes
diff --git a/activity/activity.info b/activity/activity.info
index 26108f7..1664fd6 100644
--- a/activity/activity.info
+++ b/activity/activity.info
@@ -4,7 +4,7 @@ bundle_id = org.laptop.Pippy
 service_name = org.laptop.Pippy
 class = pippy_app.PippyActivity
 icon = activity-icon
-activity_version = 36
+activity_version = 37
 mime_types = text/x-python, pickle/groupthink-pippy
 show_launcher = yes
 
diff --git a/pippy_app.py b/pippy_app.py
index 8edad4e..8f3580e 100644
--- a/pippy_app.py
+++ b/pippy_app.py
@@ -33,6 +33,7 @@ from gettext import gettext as _
 from activity import ViewSourceActivity, TARGET_TYPE_TEXT
 from sugar.activity.activity import ActivityToolbox, \
  get_bundle_path, get_bundle_name
+from sugar.activity import activity
 from sugar.graphics import style
 from sugar.graphics.toolbutton import ToolButton
 
@@ -80,6 +81,16 @@ class PippyActivity(ViewSourceActivity, 
groupthink.sugar_tools.GroupActivity):
 palette.menu.append(menu_item)
 menu_item.show()
 
+ EDIT TOOLBAR
+self._edit_toolbar = activity.EditToolbar()
+toolbox.add_toolbar(_('Edit'), self._edit_toolbar)
+self._edit_toolbar.show()
+
+self._edit_toolbar.undo.connect('clicked', self.undobutton_cb)
+self._edit_toolbar.redo.connect('clicked', self.redobutton_cb)
+self._edit_toolbar.copy.connect('clicked', self.copybutton_cb)
+self._edit_toolbar.paste.connect('clicked', self.pastebutton_cb)
+
 # The go button
 goicon_bw = gtk.Image()
 goicon_bw.set_from_file(%s/icons/run_bw.svg % os.getcwd())
@@ -241,7 +252,8 @@ class PippyActivity(ViewSourceActivity, 
groupthink.sugar_tools.GroupActivity):
 return self.hpane
 
 def when_shared(self):
-self.hpane.remove(self.hpane.get_child1())
+if not self.initiating:
+self.hpane.remove(self.hpane.get_child1())
 global text_buffer
 self.cloud.sharefield = 
groupthink.gtk_tools.TextBufferSharePoint(text_buffer)
 
@@ -297,6 +309,24 @@ class PippyActivity(ViewSourceActivity, 
groupthink.sugar_tools.GroupActivity):
 self._vte.grab_focus()
 self._vte.feed(\x1B[H\x1B[J\x1B[0;39m)
 
+def undobutton_cb(self, button):
+global text_buffer
+if text_buffer.can_undo():
+text_buffer.undo()
+
+def redobutton_cb(self, button):
+global text_buffer
+if text_buffer.can_redo():
+text_buffer.redo()
+
+def copybutton_cb(self, button):
+global text_buffer
+text_buffer.copy_clipboard(gtk.Clipboard())
+
+def pastebutton_cb(self, button):
+global text_buffer
+text_buffer.paste_clipboard(gtk.Clipboard(), None, True)
+
 def gobutton_cb(self, button):
 from shutil import copy2
 self.stopbutton_cb(button) # try stopping old code first.
@@ -501,7 +531,7 @@ PIPPY_DEFAULT_ICON = \
 
 def pippy_activity_version():
 Returns the version number of the generated activity bundle.
-return 34
+return 37
 def pippy_activity_extra_files():
 Returns a map of 'extra' files which should be included in the
 generated activity bundle.
-- 
1.7.0.4

___
Sugar-devel mailing list
Sugar-devel@lists.sugarlabs.org
http://lists.sugarlabs.org/listinfo/sugar-devel


[Sugar-devel] [PATCH] Fixes to the record UI

2010-06-08 Thread anishmangal2002
From: anishmangal2002 anishmangal2...@gmail.com

How the existing UI works:
The record UI consists of many windows/widgets. In a particular
mode or view, it displays and resizes the widgets appropriate for that
view and tries to hide the other windows by moving them off-screen.
Now, on sugar-0.88 (and probably on versions 0.86), while trying to
move the widgets off-screen, they actually get dumped at the
bottom-right corner. Hence, if a user runs the existing Record
activity on 0.88, he will observe that the bottom right quadrant of the
screen is 'corrupted'.

Fix description:
The patch works by hiding or resizing (to size 1px by 1px) the
widgets not required in a particular view/mode. The updateVideoComponents
method has been modified to hide the widgets not required in a
particular view. Widgets that can't be hidden are resized to
1 x 1 pixel.

Additionally, this patch also fixes the naming of some variables
(s/butt/button/g).

Tested successfully on sugar-emulator-0.88, soas-mirabelle and
xo1-f11-0.88.

Signed-off-by: anishmangal2002 anishmangal2...@gmail.com
---
 button.py|   10 ++--
 model.py |2 +
 p5_button.py |   30 +-
 ui.py|  199 +++---
 4 files changed, 129 insertions(+), 112 deletions(-)

diff --git a/button.py b/button.py
index 14b9700..2b0e85c 100644
--- a/button.py
+++ b/button.py
@@ -62,12 +62,12 @@ class RecdButton(TrayButton, gobject.GObject):
 return img
 
 
-def setButtClickedId( self, id ):
-self.BUTT_CLICKED_ID = id
+def setButtonClickedId( self, id ):
+self.BUTTON_CLICKED_ID = id
 
 
-def getButtClickedId( self ):
-return self.BUTT_CLICKED_ID
+def getButtonClickedId( self ):
+return self.BUTTON_CLICKED_ID
 
 
 def setup_rollover_options( self, info ):
@@ -105,4 +105,4 @@ class RecdButton(TrayButton, gobject.GObject):
 
 
 def _itemCopyToClipboardCb(self, widget):
-self.ui.copyToClipboard( self.recd )
\ No newline at end of file
+self.ui.copyToClipboard( self.recd )
diff --git a/model.py b/model.py
index b7f592b..e24752e 100644
--- a/model.py
+++ b/model.py
@@ -323,6 +323,8 @@ class Model:
 def startTakingPhoto( self ):
 self.setUpdating( True )
 self.ca.glive.takePhoto()
+self.ca.ui.FULLSCREEN = False
+self.ca.ui.updateVideoComponents()
 
 
 def savePhoto( self, pixbuf ):
diff --git a/p5_button.py b/p5_button.py
index cf76a34..a8e10c5 100644
--- a/p5_button.py
+++ b/p5_button.py
@@ -25,7 +25,7 @@ class P5Button(P5):
 def __init__(self):
 P5.__init__(self)
 self.noloop()
-self._butts = []
+self._buttons = []
 self._buttonPressed = False
 
 
@@ -34,10 +34,10 @@ class P5Button(P5):
 
 #iterate through the buttons to see if you've pressed any down
 bp = False
-for i in range ( 0, len(self._butts) ):
-if (self._butts[i]._enabled):
-contains = self._butts[i].contains(event.x, event.y)
-self._butts[i]._pressed = contains
+for i in range ( 0, len(self._buttons) ):
+if (self._buttons[i]._enabled):
+contains = self._buttons[i].contains(event.x, event.y)
+self._buttons[i]._pressed = contains
 if (contains):
 bp = True
 
@@ -51,16 +51,16 @@ class P5Button(P5):
 
 pressed = []
 #iterate through the buttons to see if you've released on any
-for i in range ( 0, len(self._butts) ):
-if (self._butts[i]._enabled):
-if (self._butts[i]._pressed):
-if (self._butts[i].contains(event.x, event.y)):
-pressed.append( self._butts[i] )
-
-if (self._butts[i]._toggle):
-self._butts[i]._pressed = not self._butts[i]._pressed
+for i in range ( 0, len(self._buttons) ):
+if (self._buttons[i]._enabled):
+if (self._buttons[i]._pressed):
+if (self._buttons[i].contains(event.x, event.y)):
+pressed.append( self._buttons[i] )
+
+if (self._buttons[i]._toggle):
+self._buttons[i]._pressed = not 
self._buttons[i]._pressed
 else:
-self._butts[i]._pressed = False
+self._buttons[i]._pressed = False
 
 for i in range( 0, len(pressed) ):
 pressed[i].doPressed()
@@ -170,4 +170,4 @@ class Button:
 
 
 def isImg( self ):
-return self._img != None
\ No newline at end of file
+return self._img != None
diff --git a/ui.py b/ui.py
index d89b819..e723f66 100644
--- a/ui.py
+++ b/ui.py
@@ -92,7 +92,7 @@ class UI:
 self.maxw = 49
 self.maxh = 49
 self.controlBarHt = 60
-self.recordButtWd = 55
+self.recordButtonWd = 55
 self.pipw = self

[Sugar-devel] [PATCH] Record - Fix for ticket #2011

2010-06-08 Thread anishmangal2002
From: anishmangal2002 anishmangal2...@gmail.com

Ctrl+w now exits the activity

Signed-off-by: anishmangal2002 anishmangal2...@gmail.com
---
 ui.py |3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/ui.py b/ui.py
index e723f66..c9ab664 100644
--- a/ui.py
+++ b/ui.py
@@ -741,6 +741,9 @@ class UI:
 elif (keyname == 'i' and event.state == gtk.gdk.CONTROL_MASK):
 if (not self.LIVEMODE):
 self.infoButtonClicked()
+elif (keyname == 'w' and event.state == gtk.gdk.CONTROL_MASK):
+self.ca.close()
+
 
 return False
 
-- 
1.7.0.4

___
Sugar-devel mailing list
Sugar-devel@lists.sugarlabs.org
http://lists.sugarlabs.org/listinfo/sugar-devel


[Sugar-devel] [record] Fixes to the UI

2010-06-06 Thread anishmangal2002
From: anishmangal2002 anishmangal2...@gmail.com

This patch fixes the Record ui which is broken since versions 0.86 and later.
---
 model.py  |7 ++
 record.py |3 +-
 ui.py |  206 +
 3 files changed, 174 insertions(+), 42 deletions(-)

diff --git a/model.py b/model.py
index b7f592b..6fc2c66 100644
--- a/model.py
+++ b/model.py
@@ -254,6 +254,10 @@ class Model:
 self.setUpdating( True )
 self.setRecording( False )
 self.ca.ui.FULLSCREEN = False
+pos = []
+pos.append({position:max, window:self.ca.ui.maxWindow} )
+pos.append({position:eye, window:self.ca.ui.recordWindow} )
+pos.append({position:prg, window:self.ca.ui.progressWindow} )
 self.ca.ui.updateVideoComponents()
 
 
@@ -321,8 +325,11 @@ class Model:
 
 
 def startTakingPhoto( self ):
+logging.debug('start taking photo')
 self.setUpdating( True )
 self.ca.glive.takePhoto()
+self.ca.ui.FULLSCREEN = False
+self.ca.ui.updateVideoComponents()
 
 
 def savePhoto( self, pixbuf ):
diff --git a/record.py b/record.py
index ccd4295..432ef60 100644
--- a/record.py
+++ b/record.py
@@ -184,7 +184,8 @@ class Record(activity.Activity):
 if (self.ui != None):
 self.ui.updateButtonSensitivities( )
 self.ui.doMouseListener( False )
-self.ui.hideAllWindows()
+self.ui.actuallyHideAllWindows()
+
 if (self.gplay != None):
 self.gplay.stop( )
 if (self.glive != None):
diff --git a/ui.py b/ui.py
index d89b819..6cad21a 100644
--- a/ui.py
+++ b/ui.py
@@ -369,7 +369,6 @@ class UI:
 self.centered = True
 self.setUp()
 
-
 def _mapEventCb( self, widget, event ):
 #when your parent window is ready, turn on the feed of live video
 self.liveVideoWindow.disconnect(self.MAP_EVENT_ID)
@@ -461,9 +460,11 @@ class UI:
 self.slowLiveVideoWindow.connect(visibility-notify-event, 
self._visibleNotifyCb)
 
 self.recordWindow = RecordWindow(self)
+self.recordWindow.set_geometry_hints(min_width=1, min_height=1)
 self.addToWindowStack( self.recordWindow, 
self.windowStack[len(self.windowStack)-1] )
 
 self.progressWindow = ProgressWindow(self)
+self.progressWindow.set_geometry_hints(min_width=1, min_height=1)
 self.addToWindowStack( self.progressWindow, 
self.windowStack[len(self.windowStack)-1] )
 
 self.maxWindow = gtk.Window()
@@ -474,6 +475,7 @@ class UI:
 self.addToWindowStack( self.maxWindow, 
self.windowStack[len(self.windowStack)-1] )
 
 self.scrubWindow = ScrubberWindow(self)
+self.scrubWindow.set_geometry_hints(min_width=1, min_height=1)
 self.addToWindowStack( self.scrubWindow, 
self.windowStack[len(self.windowStack)-1] )
 
 self.infWindow = gtk.Window()
@@ -525,6 +527,71 @@ class UI:
 else:
 self.ca.stopPipes()
 
+def resizeWindows( self ):
+if self.ca.m.MODE == Constants.MODE_PHOTO:
+if self.LIVEMODE:
+self.progressWindow.resize( 1, 1 )
+self.pipBgdWindow.resize( 1, 1 )
+self.playOggWindow.resize( 1, 1 )
+self.livePhotoWindow.resize( 1, 1 )
+self.slowLiveVideoWindow.resize( 1, 1 )
+self.infWindow.resize( 1, 1 )
+eyeDim = self.getEyeDim(self.FULLSCREEN)
+self.recordWindow.resize( eyeDim[0], eyeDim[1] )
+self.recordWindow.shutterBox.set_size_request(
+self.controlBarHt, self.controlBarHt )
+else :
+pgdDim = self.getPgdDim( self.FULLSCREEN )
+self.pipBgdWindow.resize( pgdDim[0], pgdDim[1] )
+self.progressWindow.progBar.set_size_request( 1, 1 )
+self.progressWindow.eb.set_visible_window( False )
+self.progressWindow.resize( 1, 1 )
+self.moveWinOffscreen(self.progressWindow)
+self.playOggWindow.resize( 1, 1 )
+self.recordWindow.resize( 1, 1 )
+self.scrubWindow.resize( 1, 1 )
+elif self.ca.m.MODE == Constants.MODE_VIDEO:
+if self.LIVEMODE:
+self.pipBgdWindow.resize( 1, 1 )
+self.playOggWindow.resize( 1, 1 )
+self.livePhotoWindow.resize( 1, 1 )
+self.slowLiveVideoWindow.resize( 1, 1 )
+self.infWindow.resize( 1, 1 )
+prgDim = self.getPrgDim( self.FULLSCREEN )
+prgLoc = self.getPrgLoc( self.FULLSCREEN )
+self.progressWindow.resize( prgDim[0], prgDim[1] )
+self.progressWindow.move( prgLoc[0], prgLoc[1] )
+self.progressWindow.eb.set_visible_window(True)
+else :
+pgdDim = self.getPgdDim( self.FULLSCREEN