Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorflavio <fdanesse@gmail.com>2012-10-17 00:31:28 (GMT)
committer flavio <fdanesse@gmail.com>2012-10-17 00:31:28 (GMT)
commit4cdd7605aa4da3f30e289d2f389ffdfbb8c3f95a (patch)
tree6a899c7d237b0a8ebf0a79696d435803ba05fca4
parent3870d9fbd4c46e70c5eff2f598871032d5cc583e (diff)
Gtk3 PortHEADmaster
-rw-r--r--.gitignore2
-rw-r--r--activity/activity.info2
-rw-r--r--backup.py318
-rwxr-xr-xsetup.py2
4 files changed, 90 insertions, 234 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4842d8c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+*.py[co]
+*.bak
diff --git a/activity/activity.info b/activity/activity.info
index d31aba4..c22f693 100644
--- a/activity/activity.info
+++ b/activity/activity.info
@@ -1,6 +1,6 @@
[Activity]
name = Backup
-activity_version = 5
+activity_version = 6
bundle_id = org.sugarlabs.Backup
exec = sugar-activity backup.BackupActivity
icon = Backup_icon
diff --git a/backup.py b/backup.py
index 3a56910..9ccf946 100644
--- a/backup.py
+++ b/backup.py
@@ -29,26 +29,21 @@ import traceback
import zipfile
import dbus
-import gobject
-import gtk
-
-#from sugar.activity.widgets import ActivityToolbarButton
-try:
- from sugar.activity.widgets import StopButton
- from sugar.graphics.icon import CellRendererIcon
- from sugar.graphics.toolbarbox import ToolbarBox
- pre_086_toolbars = False
-
-except ImportError:
- from sugar.graphics.toolbox import Toolbox
- pre_086_toolbars = True
-
-from sugar.activity import activity
-import sugar.env
-from sugar.graphics import style
-from sugar.graphics.toolbutton import ToolButton
-import sugar.logger
-from sugar import profile
+import gi
+from gi.repository import GObject
+from gi.repository import Gtk
+from gi.repository import Gio
+
+from sugar3.activity.widgets import StopButton
+from sugar3.graphics.icon import CellRendererIcon
+from sugar3.graphics.toolbarbox import ToolbarBox
+
+from sugar3.activity import activity
+import sugar3.env
+from sugar3.graphics import style
+from sugar3.graphics.toolbutton import ToolButton
+import sugar3.logger
+from sugar3 import profile
try:
import json
@@ -96,20 +91,7 @@ class BackupButton(ToolButton):
self.props.accelerator = '<Alt>b'
-if pre_086_toolbars:
- class StopButton(ToolButton):
-
- def __init__(self, activity, **kwargs):
- ToolButton.__init__(self, 'activity-stop', **kwargs)
- self.props.tooltip = _('Stop')
- self.props.accelerator = '<Ctrl>Q'
- self.connect('clicked', self.__stop_button_clicked_cb, activity)
-
- def __stop_button_clicked_cb(self, button, activity):
- activity.close()
-
-
-class AsyncBackup(gobject.GObject):
+class AsyncBackup(GObject.GObject):
"""
Run a data store backup asynchronously.
"""
@@ -117,14 +99,14 @@ class AsyncBackup(gobject.GObject):
_METADATA_JSON_NAME = '_metadata.json'
__gsignals__ = {
- 'progress': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ 'progress': (GObject.SIGNAL_RUN_FIRST, GObject.TYPE_NONE,
([int, int])),
- 'done': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
- 'error': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([str])),
+ 'done': (GObject.SIGNAL_RUN_FIRST, GObject.TYPE_NONE, ([])),
+ 'error': (GObject.SIGNAL_RUN_FIRST, GObject.TYPE_NONE, ([str])),
}
def __init__(self, mount_point):
- gobject.GObject.__init__(self)
+ GObject.GObject.__init__(self)
self._mount_point = mount_point
self._path = None
self._bundle = None
@@ -174,9 +156,9 @@ class AsyncBackup(gobject.GObject):
os.close(to_child_read_fd)
self._pipe_from_child = os.fdopen(from_child_read_fd, 'r')
self._pipe_to_child = os.fdopen(to_child_write_fd, 'w')
- self._pipe_from_child_watch_id = gobject.io_add_watch(
+ self._pipe_from_child_watch_id = GObject.io_add_watch(
self._pipe_from_child,
- gobject.IO_IN | gobject.IO_ERR | gobject.IO_HUP,
+ GObject.IO_IN | GObject.IO_ERR | GObject.IO_HUP,
self._child_io_cb)
def abort(self):
@@ -186,7 +168,7 @@ class AsyncBackup(gobject.GObject):
def _child_io_cb(self, source_, condition):
"""Receive and handle message from child."""
- if condition in [gobject.IO_ERR, gobject.IO_HUP]:
+ if condition in [GObject.IO_ERR, GObject.IO_HUP]:
logging.debug('error condition: %r', condition)
self.emit('error',
_('Lost connection to child process').encode('utf-8'))
@@ -240,7 +222,7 @@ class AsyncBackup(gobject.GObject):
def _parent_close(self):
"""Close connections to child and wait for it."""
- gobject.source_remove(self._pipe_from_child_watch_id)
+ GObject.source_remove(self._pipe_from_child_watch_id)
self._pipe_from_child.close()
self._pipe_to_child.close()
pid_, status = os.waitpid(self._child_pid, 0)
@@ -456,7 +438,9 @@ class BackupActivity(activity.Activity):
_MEDIA_COMBO_FREE_COLUMN = 3
def __init__(self, handle):
+
activity.Activity.__init__(self, handle, create_jobject=False)
+
self.max_participants = 1
self._progress_bar = None
self._message_box = None
@@ -464,9 +448,13 @@ class BackupActivity(activity.Activity):
self._media_combo = None
self._backup_button = None
self._backup = None
- self._hal_devices = {}
self._num_entries = None
self._color = profile.get_color()
+
+ self.volume_monitor = Gio.VolumeMonitor.get()
+ self.volume_monitor.connect('mount-added', self._gio_mount_added_cb)
+ self.volume_monitor.connect('mount-removed', self._gio_mount_removed_cb)
+
self._setup_widgets()
self._find_media()
@@ -490,80 +478,62 @@ class BackupActivity(activity.Activity):
def label_size_allocate(widget, rect):
widget.set_size_request(rect.width, -1)
- vbox = gtk.VBox()
+ vbox = Gtk.VBox()
instruction = _('Please plug in the storage device you want to back'
' up to, select it in the tool bar and press the'
' button to start the backup.')
- instruction_label = gtk.Label(instruction.encode('utf-8'))
+ instruction_label = Gtk.Label(instruction.encode('utf-8'))
instruction_label.set_line_wrap(True)
instruction_label.connect('size-allocate', label_size_allocate)
- vbox.pack_start(instruction_label, True)
+ vbox.pack_start(instruction_label, True, True, 0)
self.set_canvas(vbox)
vbox.show_all()
def _setup_toolbar(self):
- if pre_086_toolbars:
- self.toolbox = Toolbox()
- self.set_toolbox(self.toolbox)
-
- toolbar = gtk.Toolbar()
- self.toolbox.add_toolbar('Toolbar', toolbar)
- toolbar_box = self.toolbox
-
- else:
- toolbar_box = ToolbarBox()
- toolbar = toolbar_box.toolbar
- self.set_toolbar_box(toolbar_box)
-
- self._media_combo_model = gtk.ListStore(str, str, str, str)
- self._media_combo = gtk.ComboBox(self._media_combo_model)
- if not pre_086_toolbars:
- icon_renderer = CellRendererIcon(self._media_combo)
- icon_renderer.props.xo_color = self._color
- icon_renderer.props.width = style.STANDARD_ICON_SIZE + \
- style.DEFAULT_SPACING
- icon_renderer.props.height = style.STANDARD_ICON_SIZE
- icon_renderer.props.size = style.STANDARD_ICON_SIZE
- icon_renderer.props.xpad = style.DEFAULT_PADDING
- icon_renderer.props.ypad = style.DEFAULT_PADDING
- self._media_combo.pack_start(icon_renderer, False)
- self._media_combo.add_attribute(icon_renderer, 'icon_name',
- self._MEDIA_COMBO_ICON_COLUMN)
- # FIXME: icon_renderer for pre-0.86
-
- name_renderer = gtk.CellRendererText()
+
+ toolbar_box = ToolbarBox()
+ toolbar = toolbar_box.toolbar
+ self.set_toolbar_box(toolbar_box)
+
+ self._media_combo_model = Gtk.ListStore(str, str, str, str)
+ self._media_combo = Gtk.ComboBox()
+ self._media_combo.set_model(self._media_combo_model)
+
+ icon_renderer = CellRendererIcon(self._media_combo)
+ icon_renderer.props.xo_color = self._color
+ icon_renderer.props.width = style.STANDARD_ICON_SIZE + \
+ style.DEFAULT_SPACING
+ icon_renderer.props.height = style.STANDARD_ICON_SIZE
+ icon_renderer.props.size = style.STANDARD_ICON_SIZE
+ icon_renderer.props.xpad = style.DEFAULT_PADDING
+ icon_renderer.props.ypad = style.DEFAULT_PADDING
+ self._media_combo.pack_start(icon_renderer, False)
+ self._media_combo.add_attribute(icon_renderer, 'icon_name',
+ self._MEDIA_COMBO_ICON_COLUMN)
+
+ name_renderer = Gtk.CellRendererText()
self._media_combo.pack_start(name_renderer, False)
self._media_combo.add_attribute(name_renderer, 'text',
self._MEDIA_COMBO_NAME_COLUMN)
- free_renderer = gtk.CellRendererText()
+ free_renderer = Gtk.CellRendererText()
self._media_combo.pack_start(free_renderer, False)
self._media_combo.add_attribute(free_renderer, 'text',
self._MEDIA_COMBO_FREE_COLUMN)
- tool_item = gtk.ToolItem()
+ tool_item = Gtk.ToolItem()
tool_item.add(self._media_combo)
# FIXME: looks like plain GTK, not like Sugar
tooltip_text = _('Storage medium to store the backup on')
tool_item.set_tooltip_text(tooltip_text.encode('utf-8'))
toolbar.insert(tool_item, -1)
-
- if pre_086_toolbars:
- self._backup_button = gtk.ToolButton()
- self._backup_button.props.icon_name = 'journal-export'
- label_text = _('Backup Journal')
- try:
- self._backup_button.props.tooltip = label_text.encode('utf-8')
- except AttributeError:
- pass
-
- else:
- self._backup_button = BackupButton()
-
+
+ self._backup_button = BackupButton()
+
self._backup_button.connect('clicked', self._backup_cb)
self._backup_button.set_sensitive(False)
toolbar.insert(self._backup_button, -1)
-
- separator = gtk.SeparatorToolItem()
+
+ separator = Gtk.SeparatorToolItem()
separator.props.draw = False
separator.set_expand(True)
toolbar.insert(separator, -1)
@@ -595,28 +565,24 @@ class BackupActivity(activity.Activity):
def _setup_backup_view(self, mount_point):
"""Set up UI for showing feedback from worker process."""
- vbox = gtk.VBox(False)
+ vbox = Gtk.Box(orientation = Gtk.Orientation.VERTICAL)
label_text = _('Backing up Journal to %s') % (mount_point, )
- label = gtk.Label(label_text.encode('utf-8'))
+ label = Gtk.Label(label_text.encode('utf-8'))
label.set_line_wrap(True)
label.connect('size-allocate', label_size_allocate)
label.show()
- vbox.pack_start(label)
-
- alignment = gtk.Alignment(xalign=0.5, yalign=0.5, xscale=0.5)
- alignment.show()
-
- self._progress_bar = gtk.ProgressBar()
+ vbox.pack_start(label, False, False, 0)
+
+ self._progress_bar = Gtk.ProgressBar()
self._progress_bar.props.text = _('Scanning Journal').encode('utf-8')
self._progress_bar.show()
- alignment.add(self._progress_bar)
- vbox.add(alignment)
+ vbox.pack_start(self._progress_bar, False, False, 0)
- self._message_box = gtk.Label()
+ self._message_box = Gtk.Label()
label.set_line_wrap(True)
label.connect('size-allocate', label_size_allocate)
- vbox.pack_start(self._message_box)
+ vbox.pack_start(self._message_box, False, False, 0)
# FIXME
# self._close_button = gtk.Button(_('Abort'))
@@ -642,13 +608,13 @@ class BackupActivity(activity.Activity):
logging.debug('_done_cb')
self._backup_button.set_sensitive(True)
- vbox = gtk.VBox(False)
+ vbox = Gtk.VBox()
label_text = _('Successfully backed up %d Journal entries.') \
% (self._num_entries, )
- label = gtk.Label(label_text.encode('utf-8'))
+ label = Gtk.Label(label_text.encode('utf-8'))
label.set_line_wrap(True)
label.connect('size-allocate', label_size_allocate)
- vbox.pack_start(label)
+ vbox.pack_start(label, True, True, 0)
self.set_canvas(vbox)
self.show_all()
@@ -669,20 +635,10 @@ class BackupActivity(activity.Activity):
# self.emit('close')
def _find_media(self):
- """Fill the combo box with available storage media.
-
- Also sets up a callback to keep the list current.
- """
- try:
- import gio
- except ImportError:
- return self._find_media_hal()
-
- volume_monitor = gio.volume_monitor_get()
- volume_monitor.connect('mount-added', self._gio_mount_added_cb)
- volume_monitor.connect('mount-removed', self._gio_mount_removed_cb)
- for mount in volume_monitor.get_mounts():
- self._gio_mount_added_cb(volume_monitor, mount)
+ """Fill the combo box with available storage media."""
+
+ for mount in self.volume_monitor.get_mounts():
+ self._gio_mount_added_cb(self.volume_monitor, mount)
def _gio_mount_added_cb(self, volume_monitor, mount):
"""Handle notification from GIO that a medium was mounted."""
@@ -690,118 +646,17 @@ class BackupActivity(activity.Activity):
path = mount.get_root().get_path()
name = mount.get_name()
self._add_medium(path, name, icon_name)
-
+
def _gio_mount_removed_cb(self, volume_monitor, mount):
"""Handle notification from GIO that a medium was unmounted."""
path = mount.get_root().get_path()
self._remove_medium(path)
-
- def _find_media_hal(self):
- """Use HAL to fill in the available storage media."""
- bus = dbus.SystemBus()
- proxy = bus.get_object(HAL_SERVICE_NAME, HAL_MANAGER_PATH)
- hal_manager = dbus.Interface(proxy, HAL_MANAGER_IFACE)
- hal_manager.connect_to_signal('DeviceAdded',
- self._hal_device_added_cb)
-
- for udi in hal_manager.FindDeviceByCapability('volume'):
- self._hal_device_added_cb(udi)
-
- def _hal_device_added_cb(self, udi):
- """Handle notification from GIO that a device was added."""
- bus = dbus.SystemBus()
- device_object = bus.get_object(HAL_SERVICE_NAME, udi)
- device = dbus.Interface(device_object, HAL_DEVICE_IFACE)
-
- # A just-added device might lack one of the attributes we're
- # looking for, so we need to listen for changes on ALL devices.
- device.connect_to_signal('PropertyModified',
- lambda *args: self._hal_property_modified_cb(udi, *args))
-
- try:
- if device.GetProperty('volume.fsusage') != 'filesystem':
- logging.debug('Ignoring non-filesystem UDI %s', udi)
- return
- except dbus.DBusException:
- logging.debug('Ignoring UDI %s without volume.fsusage', udi)
- return
-
- self._hal_try_device(device, udi)
-
- def _hal_try_device(self, device, udi):
- """Possibly add device to UI."""
- if not device.GetProperty('volume.is_mounted'):
- return
-
- path = device.GetProperty('volume.mount_point')
- if path == '/':
- return
-
- name = device.GetProperty('volume.label')
- if not name:
- name = device.GetProperty('volume.uuid')
-
- self._hal_devices[udi] = path
- bus = dbus.SystemBus()
- bus.add_signal_receiver(self._hal_device_removed_cb,
- 'DeviceRemoved',
- HAL_MANAGER_IFACE, HAL_SERVICE_NAME,
- HAL_MANAGER_PATH, arg0=udi)
-
- self._add_medium(path, name,
- self._choose_icon_name(self._hal_get_icons_for_volume(device)))
-
- def _hal_device_removed_cb(self, udi):
- """Handle notification from GIO that a device was removed."""
- path = self._hal_devices.pop(udi, None)
- if not path:
- return
-
- self._remove_medium(path)
-
- def _hal_property_modified_cb(self, udi, count, changes):
- """Handle notification from HAL that a property has changed."""
- if 'volume.is_mounted' in [change[0] for change in changes]:
- logging.debug('volume.is_mounted changed for UDI %s', udi)
-
- bus = dbus.SystemBus()
- device_object = bus.get_object(HAL_SERVICE_NAME, udi)
- device = dbus.Interface(device_object, HAL_DEVICE_IFACE)
-
- # We can get multiple notifications, so need to figure out
- # the current state and ignore non-changes.
- if device.GetProperty('volume.is_mounted'):
- if udi not in self._hal_devices:
- self._hal_try_device(device, udi)
- else:
- logging.debug('Ignoring duplicate notification')
- else:
- if udi in self._hal_devices:
- self._hal_device_removed_cb(udi)
- else:
- logging.debug('Ignoring duplicate notification')
- else:
- logging.debug('Ignoring change for UDI %s', udi)
-
- def _hal_get_icons_for_volume(self, device):
- bus = dbus.SystemBus()
- storage_udi = device.GetProperty('block.storage_device')
- obj = bus.get_object(HAL_SERVICE_NAME, storage_udi)
- storage_device = dbus.Interface(obj, HAL_DEVICE_IFACE)
-
- storage_drive_type = storage_device.GetProperty('storage.drive_type')
- bus_type = storage_device.GetProperty('storage.bus')
- if storage_drive_type == 'sd_mmc':
- return ['media-flash-sd', 'media-flash-sd-mmc', 'media']
- elif bus_type == 'usb':
- return ['media-flash-usb', 'media', 'media-disk']
- else:
- return ['media', 'media-disk', 'media-flash-usb']
-
+
def _add_medium(self, path, medium_name, icon_name):
"""Make storage medium selectable in the UI."""
# FIXME: update space information periodically or at least after
# backup run
+
try:
stat = os.statvfs(path)
except EnvironmentError:
@@ -809,9 +664,9 @@ class BackupActivity(activity.Activity):
return
free_space = stat[statvfs.F_BSIZE] * stat[statvfs.F_BAVAIL]
-# total_space = stat[statvfs.F_BSIZE] * stat[statvfs.F_BLOCKS]
+ total_space = stat[statvfs.F_BSIZE] * stat[statvfs.F_BLOCKS]
self._media_combo_model.append([icon_name, medium_name, path,
- _('%s Free') % (format_size(free_space), )])
+ _('%s Free') % (format_size(free_space), )])
self._backup_button.set_sensitive(True)
if self._media_combo.get_active() == -1:
self._media_combo.set_active(0)
@@ -838,15 +693,14 @@ class BackupActivity(activity.Activity):
def _choose_icon_name(self, names):
"""Choose the first valid icon name or fall back to a default name."""
- theme = gtk.icon_theme_get_default()
+ theme = Gtk.IconTheme.get_default()
for name in names:
- if theme.lookup_icon(name, gtk.ICON_SIZE_LARGE_TOOLBAR, 0):
+ if theme.lookup_icon(name, style.GRID_CELL_SIZE, 0):
return name
-
return 'drive'
# pylint isn't smart enough for the gettext.install() magic
_ = lambda msg: msg
gettext.install('backup', 'po', unicode=True)
-sugar.logger.start()
+sugar3.logger.start()
diff --git a/setup.py b/setup.py
index 28be213..0d6da87 100755
--- a/setup.py
+++ b/setup.py
@@ -14,7 +14,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-from sugar.activity import bundlebuilder
+from sugar3.activity import bundlebuilder
bundlebuilder.start()