Example #1
0
    def _incompatible(self):
        ''' Display abbreviated activity user interface with alert '''
        toolbox = ToolbarBox()
        stop = StopButton(self)
        toolbox.toolbar.add(stop)
        self.set_toolbar_box(toolbox)

        title = _('Activity not compatible with this system.')
        msg = _('Please downgrade activity and try again.')
        alert = Alert(title=title, msg=msg)
        alert.add_button(0, 'Stop', Icon(icon_name='activity-stop'))
        self.add_alert(alert)

        label = Gtk.Label(_('Uh oh, WebKit2 is too old. '
                            'Browse-200 and later require WebKit2 API 4.0, '
                            'sorry!'))
        self.set_canvas(label)

        '''
        Workaround: start Terminal activity, then type

        sugar-erase-bundle org.laptop.WebActivity

        then in My Settings, choose Software Update, which will offer
        older Browse.
        '''

        alert.connect('response', self.__incompatible_response_cb)
        stop.connect('clicked', self.__incompatible_stop_clicked_cb,
                         alert)

        self.show_all()
    def __init__(self, timeout=5, **kwargs):
        Alert.__init__(self, **kwargs)

        self._pb = Gtk.ProgressBar()
        self._msg_box.pack_start(self._pb, False, False, 0)
        self._pb.set_size_request(int(Gdk.Screen.width() * 9. / 10.), -1)
        self._pb.set_fraction(0.0)
        self._pb.show()
Example #3
0
 def _show_alert(self, message, title=None):
     alert = Alert()
     if title is None:
         title = _('Atention')
     alert.props.title = title
     alert.props.msg = message
     alert.add_button(Gtk.ResponseType.OK, _('Ok'))
     self.add_alert(alert)
     alert.connect('response', self._alert_response_cb)
    def __init__(self, **kwargs):
        Alert.__init__(self, **kwargs)

        icon = Icon(icon_name='dialog-cancel')
        self.add_button(Gtk.ResponseType.CANCEL, _('Save As'), icon)
        icon.show()

        icon = Icon(icon_name='dialog-ok')
        self.add_button(Gtk.ResponseType.OK, _('Overwrite'), icon)
        icon.show()
Example #5
0
 def can_close(self):
     if self._force_close:
         return True
     elif downloadmanager.can_quit():
         return True
     else:
         alert = Alert()
         alert.props.title = ngettext('Download in progress',
                                      'Downloads in progress',
                                      downloadmanager.num_downloads())
         message = ngettext('Stopping now will erase your download',
                            'Stopping now will erase your downloads',
                            downloadmanager.num_downloads())
         alert.props.msg = message
         cancel_icon = Icon(icon_name='dialog-cancel')
         cancel_label = ngettext('Continue download', 'Continue downloads',
                                 downloadmanager.num_downloads())
         alert.add_button(Gtk.ResponseType.CANCEL, cancel_label,
                          cancel_icon)
         stop_icon = Icon(icon_name='dialog-ok')
         alert.add_button(Gtk.ResponseType.OK, _('Stop'), stop_icon)
         stop_icon.show()
         self.add_alert(alert)
         alert.connect('response', self.__inprogress_response_cb)
         alert.show()
         self.present()
         return False
    def _create_alert(self, title, msg):
        """Create and display an alert that cannot be dismissed by the user."""

        alert = Alert()
        alert.props.title = title
        alert.props.msg = msg
        alert.connect('response', self._alert_cancel_cb)

        self.add_alert(alert)

        return alert
Example #7
0
    def _search_clicked_cb(self, widget):
        title = self.searchentry.get_text()
        wiki = self.wikimenu.combo.props.value

        if not title:
            return

        if book.wiki.find('%s (from %s)' % (title, wiki))[0]:
            alert = Alert()
            alert.props.title = _('Exists')
            alert.props.msg = _('"%s" article already exists' % title)
            alert.show()
        else:
            Timer(0, self._download, [title, wiki]).start()
Example #8
0
 def _new_game_alert(self):
     alert = Alert()
     alert.props.title = _('New game')
     alert.props.msg = _('Do you want to play a new game?')
     icon = Icon(icon_name='dialog-cancel')
     alert.add_button(Gtk.ResponseType.CANCEL, _('Cancel'), icon)
     icon.show()
     ok_icon = Icon(icon_name='dialog-ok')
     alert.add_button(Gtk.ResponseType.OK, _('New game'), ok_icon)
     ok_icon.show()
     alert.connect('response', self.__game_alert_response_cb)
     self._parent.add_alert(alert)
     alert.show()
Example #9
0
    def __register_activate_cb(self, icon):
        alert = Alert()
        try:
            schoolserver.register_laptop()
        except RegisterError as e:
            alert.props.title = _('Registration Failed')
            alert.props.msg = '%s' % e
        else:
            alert.props.title = _('Registration Successful')
            alert.props.msg = _('You are now registered '
                                'with your school server.')

        ok_icon = Icon(icon_name='dialog-ok')
        alert.add_button(Gtk.ResponseType.OK, _('Ok'), ok_icon)

        self._box.add_alert(alert)
        alert.connect('response', self.__register_alert_response_cb)
 def _show_error_alert(self, title, msg=None):
     self._alert = ErrorAlert()
     self._alert.props.title = title
     if msg is not None:
         self._alert.props.msg = msg
     self.add_alert(self._alert)
     self._alert.connect('response', self._alert_cancel_cb)
     self._alert.show()
Example #11
0
    def _object_chooser(self, mime_type, type_name):
        chooser = ObjectChooser()
        matches_mime_type = False

        response = chooser.run()
        if response == Gtk.ResponseType.ACCEPT:
            jobject = chooser.get_selected_object()
            metadata = jobject.metadata
            file_path = jobject.file_path

            if metadata['mime_type'] == mime_type:
                matches_mime_type = True

            else:
                alert = Alert()

                alert.props.title = _('Invalid object')
                alert.props.msg = \
                       _('The selected object must be a %s file' % (type_name))

                ok_icon = Icon(icon_name='dialog-ok')
                alert.add_button(Gtk.ResponseType.OK, _('Ok'), ok_icon)
                ok_icon.show()

                alert.connect('response', lambda a, r: self.remove_alert(a))

                self.add_alert(alert)

                alert.show()

        return matches_mime_type, file_path, metadata['title']
Example #12
0
    def _value_changed(self, cell, path, new_text, model, activity):
        _logger.info("Change '%s' to '%s'" % (model[path][1], new_text))
        is_number = True
        number = new_text.replace(",", ".")
        try:
            float(number)
        except ValueError:
            is_number = False

        if is_number:
            decimals = utils.get_decimals(str(float(number)))
            new_text = locale.format('%.' + decimals + 'f', float(number))
            model[path][1] = str(new_text)

            self.emit("value-changed", str(path), number)

        elif not is_number:
            alert = Alert()

            alert.props.title = _('Invalid Value')
            alert.props.msg = \
                           _('The value must be a number (integer or decimal)')

            ok_icon = Icon(icon_name='dialog-ok')
            alert.add_button(Gtk.ResponseType.OK, _('Ok'), ok_icon)
            ok_icon.show()

            alert.connect('response', lambda a, r: activity.remove_alert(a))

            activity.add_alert(alert)

            alert.show()
Example #13
0
 def __erase_activate_cb(self, menu_item):
     alert = Alert()
     erase_string = _("Erase")
     alert.props.title = erase_string
     alert.props.msg = _('Do you want to permanently erase "%s"?') % self._metadata["title"]
     icon = Icon(icon_name="dialog-cancel")
     alert.add_button(Gtk.ResponseType.CANCEL, _("Cancel"), icon)
     icon.show()
     ok_icon = Icon(icon_name="dialog-ok")
     alert.add_button(Gtk.ResponseType.OK, erase_string, ok_icon)
     ok_icon.show()
     alert.connect("response", self.__erase_alert_response_cb)
     journalwindow.get_journal_window().add_alert(alert)
     alert.show()
Example #14
0
 def _erase_button_clicked_cb(self, button):
     alert = Alert()
     erase_string = _('Erase')
     alert.props.title = erase_string
     alert.props.msg = _('Do you want to permanently erase \"%s\"?') \
         % self._metadata['title']
     icon = Icon(icon_name='dialog-cancel')
     alert.add_button(Gtk.ResponseType.CANCEL, _('Cancel'), icon)
     icon.show()
     ok_icon = Icon(icon_name='dialog-ok')
     alert.add_button(Gtk.ResponseType.OK, erase_string, ok_icon)
     ok_icon.show()
     alert.connect('response', self.__erase_alert_response_cb)
     journalwindow.get_journal_window().add_alert(alert)
     alert.show()
Example #15
0
    def __pdf_alert(self, object_id):
        alert = Alert()
        alert.props.title = _("Page saved")
        alert.props.msg = _("The page has been saved as PDF to journal")

        alert.add_button(Gtk.ResponseType.APPLY, _("Show in Journal"), Icon(icon_name="zoom-activity"))
        alert.add_button(Gtk.ResponseType.OK, _("Ok"), Icon(icon_name="dialog-ok"))

        # Remove other alerts
        for alert in self._activity._alerts:
            self._activity.remove_alert(alert)

        self._activity.add_alert(alert)
        alert.connect("response", self.__pdf_response_alert, object_id)
        alert.show_all()
    def _show_journal_alert(self, title, msg):
        _stop_alert = Alert()
        _stop_alert.props.title = title
        _stop_alert.props.msg = msg
        _stop_alert.add_button(Gtk.ResponseType.APPLY,
                               _('Show in Journal'),
                               Icon(icon_name='zoom-activity'))
        _stop_alert.add_button(Gtk.ResponseType.OK, _('Ok'),
                               Icon(icon_name='dialog-ok'))
        # Remove other alerts
        for alert in self._alerts:
            self.remove_alert(alert)

        self.add_alert(_stop_alert)
        _stop_alert.connect('response', self.__stop_response_cb)
        _stop_alert.show_all()
Example #17
0
    def _alert(self, title, text=None):
        try:
            self.remove_alert(self.alert)

        finally:
            self.alert = Alert()
            self.alert.props.title = title
            self.alert.props.msg = text
            self.add_alert(self.alert)
            self.alert.connect('response', self._alert_cancel_cb)
            self.alert.show()
    def _save_epub(self):
        epub_file_name = create_ebub_from_book_model(
            self.metadata['title'], self._book_model)

        # create a new journal item
        fileObject = datastore.create()
        fileObject.metadata['title'] = \
            _('"%s" as book') % self.metadata['title']
        fileObject.metadata['mime_type'] = 'application/epub+zip'

        full_text = ''
        for page in self._book_model.get_pages():
            full_text += page.text + '\n'
        fileObject.metadata['fulltext'] = full_text
        fileObject.metadata['icon-color'] = self.metadata['icon-color']
        fileObject.metadata['keep'] = self.metadata.get('keep', '0')

        fileObject.metadata['preview'] = self.metadata['preview']
        fileObject.file_path = epub_file_name

        # store the journal item
        datastore.write(fileObject, transfer_ownership=True)
        book_object_id = fileObject.object_id

        fileObject.destroy()
        del fileObject
        shutil.rmtree(os.path.dirname(epub_file_name))

        finish_alert = Alert()
        finish_alert.props.title = _('Book created')
        finish_alert.props.msg = _('You can read the book in your Journal')
        open_icon = Icon(icon_name='zoom-activity')
        finish_alert.add_button(Gtk.ResponseType.APPLY,
                                _('Show in Journal'), open_icon)
        open_icon.show()
        ok_icon = Icon(icon_name='dialog-ok')
        finish_alert.add_button(Gtk.ResponseType.OK, _('Ok'), ok_icon)
        ok_icon.show()
        # Remove other alerts
        for alert in self._alerts:
            self.remove_alert(alert)

        self.add_alert(finish_alert)
        finish_alert.connect('response', self.__book_saved_alert_response_cb,
                             book_object_id)
        finish_alert.show()
Example #19
0
    def _shared_cb(self, activity):        
        self._logger.debug('My activity was shared')
        self.alert = Alert()
        self.alert.props.title = 'Shared Activity'
        self.alert.props.msg = 'Shared messages to be displayed here'
        self.add_alert(self.alert)
        self.initiating = True
        self._sharing_setup()

        self._logger.debug('This is my activity: making a tube...')
        id = self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube(
            SERVICE, {})
Example #20
0
    def _incompatible(self):
        ''' Display abbreviated activity user interface with alert '''
        toolbox = ToolbarBox()
        stop = StopButton(self)
        toolbox.toolbar.add(stop)
        self.set_toolbar_box(toolbox)

        title = _('Activity not compatible with this system.')
        msg = _('Please downgrade activity and try again.')
        alert = Alert(title=title, msg=msg)
        alert.add_button(0, 'Stop', Icon(icon_name='activity-stop'))
        self.add_alert(alert)

        label = Gtk.Label(_('Uh oh, GStreamer is too old.'))
        self.set_canvas(label)

        alert.connect('response', self.__incompatible_response_cb)
        stop.connect('clicked', self.__incompatible_stop_clicked_cb,
                     alert)

        self.show_all()
Example #21
0
    def _show_journal_alert(self, title, msg, object_id):
        open_alert = Alert()
        open_alert.props.title = title
        open_alert.props.msg = msg
        open_icon = Icon(icon_name='zoom-activity')
        open_alert.add_button(Gtk.ResponseType.APPLY,
                              _('Show in Journal'), open_icon)
        open_icon.show()
        ok_icon = Icon(icon_name='dialog-ok')
        open_alert.add_button(Gtk.ResponseType.OK, _('Ok'), ok_icon)
        ok_icon.show()
        # Remove other alerts
        for alert in self._alerts:
            self.remove_alert(alert)

        self.add_alert(open_alert)
        open_alert.connect('response', self.__open_response_cb, object_id)
        open_alert.show()
Example #22
0
    def __pdf_alert(self, object_id):
        alert = Alert()
        alert.props.title = _('Page saved')
        alert.props.msg = _('The page has been saved as PDF to journal')

        alert.add_button(Gtk.ResponseType.APPLY,
                         _('Show in Journal'),
                         Icon(icon_name='zoom-activity'))
        alert.add_button(Gtk.ResponseType.OK, _('Ok'),
                         Icon(icon_name='dialog-ok'))

        # Remove other alerts
        for alert in self._activity._alerts:
            self._activity.remove_alert(alert)

        self._activity.add_alert(alert)
        alert.connect('response', self.__pdf_response_alert, object_id)
        alert.show_all()
    def __crashed_cb(self, browser):
        self.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.LEFT_PTR))
        uri = browser.cached_uri
        logging.error('WebKit2 WebView at uri %r has crashed', uri)
        self.close_tab(browser.get_parent())

        alert = Alert(title=_('This tab has crashed Browse: %s') % uri,
                      msg=_('If you reopen the tab, it may just crash again'))
        alert.add_button(Gtk.ResponseType.OK, _('Reopen'))
        alert.add_button(Gtk.ResponseType.CANCEL, _('Disregard'))
        alert.connect('response', self.__crashed_alert_cb, uri)
        self._activity.add_alert(alert)
    def _show_missing_tracks_alert(self, tracks):
        self._alert = Alert()
        title = _('%s tracks not found.') % len(tracks)
        self._alert.props.title = title
        icon = Icon(icon_name='dialog-cancel')
        self._alert.add_button(Gtk.ResponseType.CANCEL, _('Dismiss'), icon)
        icon.show()

        icon = Icon(icon_name='dialog-ok')
        self._alert.add_button(Gtk.ResponseType.APPLY, _('Details'), icon)
        icon.show()
        self.add_alert(self._alert)
        self._alert.connect(
            'response', self.__missing_tracks_alert_response_cb, tracks)
 def _clear_game_bt(self, button):
     if self.activity.game.model.is_demo or \
             len(self.activity.cardlist.pairs) == 0:
         self.clear_game()
     else:
         alert = Alert()
         alert.props.title = _('Clear all the tiles from the game?')
         icon = Icon(icon_name='dialog-ok')
         alert.add_button(1, _('Clear'), icon)
         icon = Icon(icon_name='dialog-cancel')
         alert.add_button(0, _('Do not clear'), icon)
         alert.connect('response', self._clear_game_alert_cb)
         self.activity.add_alert(alert)
 def __activate_game_cb(self, menu, i):
     self._game_selected_index = i
     if self.activity.game.model.is_demo:
         self._change_game()
     else:
         alert = Alert()
         alert.props.title = _('Discard your modified game?')
         icon = Icon(icon_name='dialog-ok')
         alert.add_button(1, _('Discard'), icon)
         icon = Icon(icon_name='dialog-cancel')
         alert.add_button(0, _('Do not discard'), icon)
         alert.connect('response', self._change_game_alert_cb)
         self.activity.add_alert(alert)
 def __activate_art4apps_game_cb(self, menu, category, language):
     self._art4apps_data = (category, language)
     if self.activity.game.model.is_demo:
         self._change_art4apps_game(category, language)
     else:
         alert = Alert()
         alert.props.title = _('Discard your modified game?')
         icon = Icon(icon_name='dialog-ok')
         alert.add_button(1, _('Discard'), icon)
         icon = Icon(icon_name='dialog-cancel')
         alert.add_button(0, _('Do not discard'), icon)
         alert.connect('response', self._change_art4apps_game_alert_cb)
         self.activity.add_alert(alert)
 def __save_ebook_clicked_cb(self, button):
     alert = Alert()
     alert.props.title = _('Book creation')
     alert.props.msg = _('Do you want to add an image for the cover?')
     icon = Icon(icon_name='dialog-ok')
     alert.add_button(Gtk.ResponseType.YES, _('Yes'), icon)
     icon.show()
     icon = Icon(icon_name='dialog-cancel')
     alert.add_button(Gtk.ResponseType.NO, _('No'), icon)
     icon.show()
     alert.connect('response', self.__add_cover_response_cb,
                   self._set_cover_and_create_book)
     self.add_alert(alert)
    def __init__(self, **kwargs):
        Alert.__init__(self, **kwargs)
        # Name entry box
        self._name_view = Gtk.EventBox()
        self._name_view.show()

        # Entry box
        self._name_entry = Gtk.Entry()
        halign = Gtk.Alignment.new(0, 0, 0, 0)
        self._hbox.pack_start(halign, False, False, 0)
        halign.add(self._name_view)
        halign.show()

        self._name_view.add(self._name_entry)
        self._name_entry.show()

        halign = Gtk.Alignment.new(0, 0, 0, 0)
        self._buttons_box = Gtk.HButtonBox()
        self._buttons_box.set_layout(Gtk.ButtonBoxStyle.END)
        self._buttons_box.set_spacing(style.DEFAULT_SPACING)
        halign.add(self._buttons_box)
        self._hbox.pack_start(halign, False, False, 0)
        halign.show()
        self.show_all()
Example #30
0
    def _erase_comment_cb(self, widget, event):
        alert = Alert()

        entry = self.get_selection().get_selected()[1]
        erase_string = _('Erase')
        alert.props.title = erase_string
        alert.props.msg = _('Do you want to permanently erase \"%s\"?') \
            % self._store[entry][self.COMMENT_MESSAGE]

        icon = Icon(icon_name='dialog-cancel')
        alert.add_button(Gtk.ResponseType.CANCEL, _('Cancel'), icon)
        icon.show()

        ok_icon = Icon(icon_name='dialog-ok')
        alert.add_button(Gtk.ResponseType.OK, erase_string, ok_icon)
        ok_icon.show()

        alert.connect('response', self._erase_alert_response_cb, entry)

        journalwindow.get_journal_window().add_alert(alert)
        alert.show()
Example #31
0
    def __erase_activated_cb(self, tree_view, bundle_id):
        registry = bundleregistry.get_registry()
        activity_info = registry.get_bundle(bundle_id)

        alert = Alert()
        alert.props.title = _('Confirm erase')
        alert.props.msg = \
            _('Confirm erase: Do you want to permanently erase %s?') \
            % activity_info.get_name()

        cancel_icon = Icon(icon_name='dialog-cancel')
        alert.add_button(Gtk.ResponseType.CANCEL, _('Keep'), cancel_icon)

        erase_icon = Icon(icon_name='dialog-ok')
        alert.add_button(Gtk.ResponseType.OK, _('Erase'), erase_icon)

        alert.connect('response', self.__erase_confirmation_dialog_response_cb,
                      bundle_id)

        self.add_alert(alert)
Example #32
0
    def __init__(self, handle):
        ''' Initialize the Sugar activity '''
        super(Dimensions, self).__init__(handle)
        self.ready_to_play = False
        self._prompt = ''
        self._read_journal_data()
        self._sep = []
        self._setup_toolbars()
        self._setup_canvas()

        if self.shared_activity:
            # We're joining
            if not self.get_shared():
                xocolors = XoColor(profile.get_color().to_string())
                share_icon = Icon(icon_name='zoom-neighborhood',
                                  xo_color=xocolors)
                self._joined_alert = Alert()
                self._joined_alert.props.icon = share_icon
                self._joined_alert.props.title = _('Please wait')
                self._joined_alert.props.msg = _('Starting connection...')
                self.add_alert(self._joined_alert)

                # Wait for joined signal
                self.connect("joined", self._joined_cb)

        self._setup_presence_service()

        if not hasattr(self, '_saved_state'):
            self._saved_state = None
            self.vmw.new_game(show_selector=True)
        else:
            self.vmw.new_game(saved_state=self._saved_state,
                              deck_index=self._deck_index)
        self.ready_to_play = True

        if self._editing_word_list:
            self.vmw.editing_word_list = True
            self.vmw.edit_word_list()
        elif self._editing_custom_cards:
            self.vmw.editing_custom_cards = True
            self.vmw.edit_custom_card()

        Gdk.Screen.get_default().connect('size-changed', self._configure_cb)
        self._configure_cb(None)
Example #33
0
    def _new_tube_cb(self, id, initiator, type, service, params, state):
        ''' Create a new tube. '''
        _logger.debug(
            'New tube: ID=%d initator=%d type=%d service=%s '
            'params=%r state=%d', id, initiator, type, service, params, state)

        if (type == telepathy.TUBE_TYPE_DBUS and service == SERVICE):
            if state == telepathy.TUBE_STATE_LOCAL_PENDING:
                self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].AcceptDBusTube(
                    id)

            self.collab = CollabWrapper(self)
            self.collab.message.connect(self.event_received_cb)
            self.collab.setup()

            if self._waiting_for_reflections:
                self.send_event(JOIN_CMD, {})
                self._joined_alert = Alert()
                self._joined_alert.props.title = _('Please wait')
                self._joined_alert.props.msg = _('Requesting reflections...')
                self.add_alert(self._joined_alert)
Example #34
0
    def _incompatible(self):
        ''' Display abbreviated activity user interface with alert '''
        toolbox = ToolbarBox()
        stop = StopButton(self)
        toolbox.toolbar.add(stop)
        self.set_toolbar_box(toolbox)

        title = _('Activity not compatible with this system.')
        msg = _('Please erase the activity.')
        alert = Alert(title=title, msg=msg)
        alert.add_button(0, 'Stop', Icon(icon_name='activity-stop'))
        self.add_alert(alert)

        label = Gtk.Label(_('You do not have an accelerometer.'))
        self.set_canvas(label)

        alert.connect('response', self.__incompatible_response_cb)
        stop.connect('clicked', self.__incompatible_stop_clicked_cb, alert)

        self.show_all()
Example #35
0
        def _create_alert(name, scrolled):
            title = G.TEXT_SAVE_CHANGES_QUESTION.replace("****", name)
            msg = G.TEXT_IF_NOT_SAVE

            no = Gtk.Image.new_from_icon_name("activity-stop",
                                              Gtk.IconSize.MENU)

            save = Gtk.Image.new_from_icon_name("filesave", Gtk.IconSize.MENU)

            alert = Alert()
            alert.props.title = title
            alert.props.msg = msg

            alert.add_button(Gtk.ResponseType.NO, _("No save"), icon=no)
            alert.add_button(Gtk.ResponseType.YES, _("Save"), icon=save)

            alert.connect("response", _alert_response, scrolled)

            self.vbox.pack_start(alert, False, False, 0)
            self.vbox.reorder_child(alert, 0)
            self.vbox.show_all()
Example #36
0
    def __create_new_folder(self, entry):
        if entry.get_text():
            try:
                path = os.path.join(self.folder, entry.get_text())
                os.mkdir(path)
                self.folder = path

            except OSError as msg:
                alert = Alert()
                alert.props.title = _('Error creating the folder.')
                alert.props.msg = msg
                image = Gtk.Image.new_from_stock(Gtk.STOCK_OK,
                                                 Gtk.IconSize.MENU)
                alert.add_button(Gtk.ResponseType.NO, _('Ok'), icon=image)

                alert.connect('response', self.__alert_response)

                self.vbox.pack_start(alert, False, False, 0)
                self.vbox.reorder_child(alert, 1)

        item = entry.get_parent()
        self.toolbar.remove(item)
        self.button_new_folder.set_sensitive(True)
Example #37
0
        def _create_alert(name, scrolled):
            title = _('Save changes to document "%s" before closing?' % name)
            msg = _('If you do not save, changes will be lost forever.')

            no = Gtk.Image.new_from_icon_name('activity-stop',
                                              Gtk.IconSize.MENU)
            save = Gtk.Image.new_from_icon_name('filesave', Gtk.IconSize.MENU)

            alert = Alert()
            alert.props.title = title
            alert.props.msg = msg

            button1 = alert.add_button(Gtk.ResponseType.NO,
                                       _('No save'),
                                       icon=no)
            button2 = alert.add_button(Gtk.ResponseType.YES,
                                       _('Save'),
                                       icon=save)

            alert.connect('response', _alert_response, scrolled)

            self.vbox.pack_start(alert, False, False, 0)
            self.vbox.reorder_child(alert, 0)
            self.vbox.show_all()
class FileChooserSave(FileChooser):

    __gsignals__ = {
        "save-file": (GObject.SIGNAL_RUN_FIRST, None, [str])
    }

    def __init__(self, folder=None):
        FileChooser.__init__(self, folder)

        self.alert = None
        self.view.set_selection_mode(Gtk.SelectionMode.SINGLE)
        self.view.connect("selection-changed", self.__selection_changed)
        self.view.connect("button-press-event", self.__button_press_event_cb)
        self.entry.connect("activate", self._save_path_from_entry)

        self.connect("key-release-event", self.__key_release_event_cb)

        self.__make_toolbar()
        self.show_folder()

        self.show_all()

    def __make_toolbar(self):
        self.toolbar = Gtk.Toolbar()
        self.toolbar.modify_bg(
            Gtk.StateType.NORMAL, style.COLOR_TOOLBAR_GREY.get_gdk_color())

        self.toolbar.insert(self.go_up_button, -1)

        self.toolbar.insert(Gtk.SeparatorToolItem(), -1)

        self.button_new_folder = ToolButton(icon_name="new-folder")
        self.button_new_folder.set_tooltip(_("Create a folder"))
        self.button_new_folder.connect("clicked", self.create_folder)
        self.toolbar.insert(self.button_new_folder, -1)

        item = Gtk.ToolItem()
        item.add(self.entry)
        self.toolbar.insert(item, -1)

        separator = Gtk.SeparatorToolItem()
        separator.props.draw = False
        separator.set_expand(True)
        self.toolbar.insert(separator, -1)

        item = Gtk.ToolItem()
        self.entry_name = Gtk.Entry()
        self.entry_name.set_size_request(200, -1)
        self.entry_name.set_placeholder_text("Select a name for this file.")
        self.entry_name.connect("activate", self.__name_selected)
        item.add(self.entry_name)
        self.toolbar.insert(item, -1)
        self.entries.append(self.entry_name)

        self.button_save = ToolButton(icon_name="save-as")
        self.button_save.connect("clicked", self.__save_path_from_button)
        self.toolbar.insert(self.button_save, -1)

        self.close_button = ToolButton(icon_name="dialog-cancel")
        self.close_button.connect("clicked", self.close)
        self.toolbar.insert(self.close_button, -1)

        self.vbox.pack_start(self.toolbar, False, False, 0)

    def __key_release_event_cb(self, widget, event):
        if event.keyval == Gdk.KEY_Return:
            if self.area.get_selected_items():
                self.__name_selected()

        elif event.keyval == Gdk.KEY_BackSpace:
            if not self.entry.has_focus() and not self.entry_name.has_focus():
                self.go_up()

        elif event.keyval == Gdk.KEY_Escape:
            self.close()

    def create_folder(self, widget):
        self.button_new_folder.set_sensitive(False)

        entry = Gtk.Entry()
        entry.set_placeholder_text("Select a name")
        entry.connect("activate", self.__create_new_folder)

        item = Gtk.ToolItem()
        item.add(entry)
        self.toolbar.insert(item, 4)
        self.toolbar.show_all()

    def __create_new_folder(self, entry):
        if entry.get_text():
            try:
                path = os.path.join(self.folder, entry.get_text())
                os.mkdir(path)
                self.folder = path

            except OSError as msg:
                if self.alert:
                    self.vbox.remove(self.alert)
                    self.alert = None
                self.alert = Alert()
                self.alert.props.title = G.TEXT_ERROR_CREATING_FOLDER
                self.alert.props.msg = msg
                image = Gtk.Image.new_from_stock(
                    Gtk.STOCK_OK, Gtk.IconSize.MENU)
                self.alert.add_button(Gtk.ResponseType.NO, _("Ok"), icon=image)

                self.alert.connect("response", self.__alert_response)

                self.vbox.pack_start(self.alert, False, False, 0)
                self.vbox.reorder_child(self.alert, 1)

        item = entry.get_parent()
        self.toolbar.remove(item)
        self.button_new_folder.set_sensitive(True)

    def __save_path_from_button(self, button):
        self.__name_selected()

    def __name_selected(self, entry=None):
        path = os.path.join(self.folder, self.entry_name.get_text())
        self._save_path_from_entry(path=path)

    def _save_path_from_entry(self, entry=None, path=None):
        if not path:
            path = self.entry.get_text()

        if os.path.exists(path):
            if os.path.isdir(path):
                self.folder = path

            elif os.path.isfile(path):
                self.create_alert(path)

        elif not os.path.exists(path):
            if os.path.isdir(self.go_up(path, _return=True)):
                self.emit("save-file", path)
                self.destroy()

    def create_alert(self, path):
        if self.alert:
            self.vbox.remove(self.alert)
            self.alert = None

        self.alert = Alert()
        self.alert.props.title = G.TEXT_FILE_ALREADY_EXISTS
        self.alert.props.msg = G.TEXT_OVERWRITE_QUESTION.replace("****", path)
        cancel = Gtk.Image.new_from_icon_name(
                "dialog-cancel", Gtk.IconSize.MENU)
        save = Gtk.Image.new_from_icon_name("filesave", Gtk.IconSize.MENU)
        self.alert.add_button(Gtk.ResponseType.NO, _("Cancel"), icon=cancel)
        self.alert.add_button(Gtk.ResponseType.YES, _("Save"), icon=save)

        self.alert.connect("response", self.__alert_response, path)

        self.vbox.pack_start(self.alert, False, False, 0)
        self.vbox.reorder_child(self.alert, 2)

    def __alert_response(self, alert, response, path):
        if response == Gtk.ResponseType.NO:
            self.vbox.remove(alert)

        elif response == Gtk.ResponseType.YES:
            self.emit("save-file", path)
            self.destroy()
        self.alert_status = 0
        self.alert = None

    def __selection_changed(self, view):
        if self.view.get_selected_items():
            path = self.view.get_selected_items()[0]
            iter = self.model.get_iter(path)
            name = self.model.get_value(iter, 0)
            if os.path.isfile(os.path.join(self.folder, name)):
                self.entry_name.set_text(name)

            else:
                self.entry_name.set_text("")

        else:
            self.entry_name.set_text("")

    def __button_press_event_cb(self, view, event):
        if event.button != 1:
            return

        try:
            path = view.get_path_at_pos(int(event.x), int(event.y))
            iter = self.model.get_iter(path)
            directory = os.path.join(
                    self.folder, self.model.get_value(iter, 0))

            if event.type.value_name == "GDK_2BUTTON_PRESS":
                if os.path.isdir(directory):
                    self.folder = directory
                    self.selected_path = None

                elif os.path.isfile(directory):
                    self.selected_path = directory
                    self.create_alert(directory)

            elif event.type.value_name == "GDK_1BUTTON_PRESS":
                self.selected_path = directory

        except TypeError:
            self.selected_path = None
class JukeboxActivity(activity.Activity):

    __gsignals__ = {
        'playlist-finished': (GObject.SignalFlags.RUN_FIRST, None, []),
    }

    def __init__(self, handle):
        activity.Activity.__init__(self, handle)

        self.player = None

        self._alert = None
        self._playlist_jobject = None

        self.set_title(_('Jukebox Activity'))
        self.max_participants = 1

        toolbar_box = ToolbarBox()
        activity_button = ActivityToolbarButton(self)
        activity_toolbar = activity_button.page
        toolbar_box.toolbar.insert(activity_button, 0)
        self.title_entry = activity_toolbar.title

        self._view_toolbar = ViewToolbar()
        self._view_toolbar.connect('go-fullscreen', self.__go_fullscreen_cb)
        self._view_toolbar.connect('toggle-playlist',
                                   self.__toggle_playlist_cb)
        view_toolbar_button = ToolbarButton(page=self._view_toolbar,
                                            icon_name='toolbar-view')
        self._view_toolbar.show()
        toolbar_box.toolbar.insert(view_toolbar_button, -1)
        view_toolbar_button.show()

        self._control_toolbar = Gtk.Toolbar()
        self._control_toolbar_button = ToolbarButton(
            page=self._control_toolbar, icon_name='media-playback-start')
        self._control_toolbar.show()
        toolbar_box.toolbar.insert(self._control_toolbar_button, -1)
        self._control_toolbar_button.hide()

        self.set_toolbar_box(toolbar_box)
        toolbar_box.show_all()

        self.connect('key_press_event', self.__key_press_event_cb)
        self.connect('playlist-finished', self.__playlist_finished_cb)

        # We want to be notified when the activity gets the focus or
        # loses it. When it is not active, we don't need to keep
        # reproducing the video
        self.connect('notify::active', self.__notify_active_cb)

        self._video_canvas = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)

        self._playlist_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)

        self.playlist_widget = PlayList()
        self.playlist_widget.connect('play-index', self.__play_index_cb)
        self.playlist_widget.connect('missing-tracks',
                                     self.__missing_tracks_cb)
        self.playlist_widget.set_size_request(
            Gdk.Screen.width() * PLAYLIST_WIDTH_PROP, 0)
        self.playlist_widget.show()

        self._playlist_box.pack_start(self.playlist_widget,
                                      expand=True,
                                      fill=True,
                                      padding=0)

        self._playlist_toolbar = Gtk.Toolbar()

        move_up = ToolButton("go-up")
        move_up.set_tooltip(_("Move up"))
        move_up.connect("clicked", self._move_up_cb)
        self._playlist_toolbar.insert(move_up, 0)

        move_down = ToolButton("go-down")
        move_down.set_tooltip(_("Move down"))
        move_down.connect("clicked", self._move_down_cb)
        self._playlist_toolbar.insert(move_down, 1)

        self._playlist_box.pack_end(self._playlist_toolbar, False, False, 0)
        self._video_canvas.pack_start(self._playlist_box, False, False, 0)

        # Create the player just once
        logging.debug('Instantiating GstPlayer')
        self.player = GstPlayer()
        self.player.connect('eos', self.__player_eos_cb)
        self.player.connect('error', self.__player_error_cb)
        self.player.connect('play', self.__player_play_cb)

        self.control = Controls(self, toolbar_box.toolbar,
                                self._control_toolbar)

        self._separator = Gtk.SeparatorToolItem()
        self._separator.props.draw = False
        self._separator.set_expand(True)
        self._separator.show()
        toolbar_box.toolbar.insert(self._separator, -1)

        self._stop = StopButton(self)
        toolbar_box.toolbar.insert(self._stop, -1)

        self._empty_widget = Gtk.Label(label="")
        self._empty_widget.show()
        self.videowidget = VideoWidget()
        self.set_canvas(self._video_canvas)
        self._init_view_area()
        self.show_all()
        # need hide the playlist by default
        self._playlist_box.hide()

        self._configure_cb()

        self.player.init_view_area(self.videowidget)

        self._volume_monitor = Gio.VolumeMonitor.get()
        self._volume_monitor.connect('mount-added', self.__mount_added_cb)
        self._volume_monitor.connect('mount-removed', self.__mount_removed_cb)

        if handle.object_id is None:
            # The activity was launched from scratch. We need to show
            # the Empty Widget
            self.playlist_widget.hide()
            emptypanel.show(self, 'activity-jukebox', _('No media'),
                            _('Choose media files'),
                            self.control.show_picker_cb)

        self.control.check_if_next_prev()

        Gdk.Screen.get_default().connect('size-changed', self._configure_cb)

    def _move_up_cb(self, button):
        self.playlist_widget.move_up()

    def _move_down_cb(self, button):
        self.playlist_widget.move_down()

    def _configure_cb(self, event=None):
        toolbar = self.get_toolbar_box().toolbar
        toolbar.remove(self._stop)
        toolbar.remove(self._separator)
        if Gdk.Screen.width() < Gdk.Screen.height():
            self._control_toolbar_button.show()
            self._control_toolbar_button.set_expanded(True)
            self.control.update_layout(landscape=False)
            toolbar.insert(self._separator, -1)
        else:
            self._control_toolbar_button.set_expanded(False)
            self._control_toolbar_button.hide()
            self.control.update_layout(landscape=True)
        toolbar.insert(self._stop, -1)

    def __notify_active_cb(self, widget, event):
        """Sugar notify us that the activity is becoming active or inactive.
        When we are inactive, we stop the player if it is reproducing
        a video.
        """

        logging.debug('JukeboxActivity notify::active signal received')

        if self.player.player.props.current_uri is not None and \
                self.player.playing_video():
            if not self.player.is_playing() and self.props.active:
                self.player.play()
            if self.player.is_playing() and not self.props.active:
                self.player.pause()

    def _init_view_area(self):
        """
        Use a notebook with two pages, one empty an another
        with the videowidget
        """
        self.view_area = Gtk.Notebook()
        self.view_area.set_show_tabs(False)
        self.view_area.append_page(self._empty_widget, None)
        self.view_area.append_page(self.videowidget, None)
        self._video_canvas.pack_end(self.view_area,
                                    expand=True,
                                    fill=True,
                                    padding=0)

    def _switch_canvas(self, show_video):
        """Show or hide the video visualization in the canvas.

        When hidden, the canvas is filled with an empty widget to
        ensure redrawing.

        """
        if show_video:
            self.view_area.set_current_page(1)
        else:
            self.view_area.set_current_page(0)
        self._video_canvas.queue_draw()

    def __key_press_event_cb(self, widget, event):
        keyname = Gdk.keyval_name(event.keyval)
        logging.info("Keyname Press: %s, time: %s", keyname, event.time)
        if self.title_entry.has_focus():
            return False

        if keyname == "space":
            self.control._button_clicked_cb(None)
            return True

    def __playlist_finished_cb(self, widget):
        self._switch_canvas(show_video=False)
        self._view_toolbar._show_playlist.set_active(True)
        self.unfullscreen()

        # Select the first stream to be played when Play button will
        # be pressed
        self.playlist_widget.set_current_playing(0)
        self.control.check_if_next_prev()

    def songchange(self, direction):
        current_playing = self.playlist_widget.get_current_playing()
        if direction == 'prev' and current_playing > 0:
            self.play_index(current_playing - 1)
        elif direction == 'next' and \
                current_playing < len(self.playlist_widget._items) - 1:
            self.play_index(current_playing + 1)
        else:
            self.emit('playlist-finished')

    def play_index(self, index):
        # README: this line is no more necessary because of the
        # .playing_video() method
        # self._switch_canvas(show_video=True)
        self.playlist_widget.set_current_playing(index)

        path = self.playlist_widget._items[index]['path']
        if self.playlist_widget.check_available_media(path):
            if self.playlist_widget.is_from_journal(path):
                path = self.playlist_widget.get_path_from_journal(path)
            self.control.check_if_next_prev()

            self.player.set_uri(path)
            self.player.play()
        else:
            self.songchange('next')

    def __play_index_cb(self, widget, index, path):
        # README: this line is no more necessary because of the
        # .playing_video() method
        # self._switch_canvas(show_video=True)
        self.playlist_widget.set_current_playing(index)

        if self.playlist_widget.is_from_journal(path):
            path = self.playlist_widget.get_path_from_journal(path)

        self.control.check_if_next_prev()

        self.player.set_uri(path)
        self.player.play()

    def __player_eos_cb(self, widget):
        self.songchange('next')

    def _show_error_alert(self, title, msg=None):
        self._alert = ErrorAlert()
        self._alert.props.title = title
        if msg is not None:
            self._alert.props.msg = msg
        self.add_alert(self._alert)
        self._alert.connect('response', self._alert_cancel_cb)
        self._alert.show()

    def __mount_added_cb(self, volume_monitor, device):
        logging.debug('Mountpoint added. Checking...')
        self.remove_alert(self._alert)
        self.playlist_widget.update()

    def __mount_removed_cb(self, volume_monitor, device):
        logging.debug('Mountpoint removed. Checking...')
        self.remove_alert(self._alert)
        self.playlist_widget.update()

    def __missing_tracks_cb(self, widget, tracks):
        self._show_missing_tracks_alert(tracks)

    def _show_missing_tracks_alert(self, tracks):
        self._alert = Alert()
        title = _('%s tracks not found.') % len(tracks)
        self._alert.props.title = title
        icon = Icon(icon_name='dialog-cancel')
        self._alert.add_button(Gtk.ResponseType.CANCEL, _('Dismiss'), icon)
        icon.show()

        icon = Icon(icon_name='dialog-ok')
        self._alert.add_button(Gtk.ResponseType.APPLY, _('Details'), icon)
        icon.show()
        self.add_alert(self._alert)
        self._alert.connect('response',
                            self.__missing_tracks_alert_response_cb, tracks)

    def __missing_tracks_alert_response_cb(self, alert, response_id, tracks):
        if response_id == Gtk.ResponseType.APPLY:
            vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
            vbox.props.valign = Gtk.Align.CENTER
            label = Gtk.Label(label='')
            label.set_markup(_('<b>Missing tracks</b>'))
            vbox.pack_start(label, False, False, 15)

            for track in tracks:
                label = Gtk.Label(label=track['path'])
                vbox.add(label)

            _missing_tracks = Gtk.ScrolledWindow()
            _missing_tracks.add_with_viewport(vbox)
            _missing_tracks.show_all()

            self.view_area.append_page(_missing_tracks, None)

            self.view_area.set_current_page(2)

        self.remove_alert(alert)

    def _alert_cancel_cb(self, alert, response_id):
        self.remove_alert(alert)

    def __player_play_cb(self, widget):
        # Do not show the visualization widget if we are playing just
        # an audio stream

        def callback():
            if self.player.playing_video():
                self._switch_canvas(True)
            else:
                self._switch_canvas(False)
            return False

        # HACK: we need a timeout here because gstreamer returns
        # n-video = 0 if we call it immediately
        GObject.timeout_add(1000, callback)

    def __player_error_cb(self, widget, message, detail):
        self.player.stop()
        self.control.set_disabled()

        logging.error('ERROR MESSAGE: %s', message)
        logging.error('ERROR DETAIL: %s', detail)

        file_path = self.playlist_widget._items[
            self.playlist_widget.get_current_playing()]['path']
        mimetype = mime.get_for_file(file_path)

        title = _('Error')
        msg = _('This "%s" file can\'t be played') % mimetype
        self._switch_canvas(False)
        self._show_error_alert(title, msg)

    def can_close(self):
        # We need to put the Gst.State in NULL so gstreamer can
        # cleanup the pipeline
        self.player.stop()
        return True

    def read_file(self, file_path):
        """Load a file from the datastore on activity start."""
        logging.debug('JukeBoxAtivity.read_file: %s', file_path)

        title = self.metadata['title']
        self.playlist_widget.load_file(file_path, title)
        self._view_toolbar._show_playlist.set_active(True)

    def write_file(self, file_path):
        def write_playlist_to_file(file_path):
            """Open the file at file_path and write the playlist.

            It is saved in audio/x-mpegurl format.

            """

            list_file = open(file_path, 'w')
            for uri in self.playlist_widget._items:
                list_file.write('#EXTINF:%s\n' % uri['title'])
                list_file.write('%s\n' % uri['path'])
            list_file.close()

        if not self.metadata['mime_type']:
            self.metadata['mime_type'] = 'audio/x-mpegurl'

        if self.metadata['mime_type'] == 'audio/x-mpegurl':
            write_playlist_to_file(file_path)

        else:
            if self._playlist_jobject is None:
                self._playlist_jobject = \
                    self.playlist_widget.create_playlist_jobject()

            # Add the playlist to the playlist jobject description.
            # This is only done if the activity was not started from a
            # playlist or from scratch:
            description = ''
            for uri in self.playlist_widget._items:
                description += '%s\n' % uri['title']
            self._playlist_jobject.metadata['description'] = description

            write_playlist_to_file(self._playlist_jobject.file_path)
            datastore.write(self._playlist_jobject)

    def __go_fullscreen_cb(self, toolbar):
        self.fullscreen()

    def __toggle_playlist_cb(self, toolbar):
        if self._view_toolbar._show_playlist.get_active():
            self._playlist_box.show_all()
        else:
            self._playlist_box.hide()
        self._video_canvas.queue_draw()
Example #40
0
class CEdit(activity.Activity):
    def __init__(self, handle):
        activity.Activity.__init__(self, handle)

        self.get_conf()

        self.reopen = True
        self.vbox = Gtk.VBox()
        self.infobar = InfoBar()

        self.make_toolbar()
        self.make_notebook()

        self.infobar.connect('language-changed', self.set_language)

        self.vbox.pack_end(self.infobar, False, False, 0)
        self.set_canvas(self.vbox)
        self.show_all()

    def get_conf(self):
        if 'saved' in self.metadata:
            self.conf = {}
            self.conf['font'] = str(self.metadata['font'])
            self.conf['font-size'] = int(self.metadata['font-size'])
            self.conf['show-line-numbers'] = bool(
                int(self.metadata['show-line-numbers']))
            self.conf['tab-width'] = int(self.metadata['tab-width'])
            self.conf['use-spaces'] = bool(int(self.metadata['use-spaces']))
            self.conf['theme'] = str(self.metadata['theme'])
            self.conf['right-line-pos'] = int(self.metadata['right-line-pos'])
            self.conf['show-right-line'] = bool(
                int(self.metadata['show-right-line']))
            self.conf['wrap-mode'] = str(self.metadata['wrap-mode'])

        else:
            self.conf = {
                'font': 'Monospace',
                'font-size': 14,
                'show-line-numbers': True,
                'tab-width': 4,
                'use-spaces': True,
                'theme': 'classic',
                'right-line-pos': 80,
                'show-right-line': False,
                'wrap-mode': 'none'
            }

    def make_toolbar(self):
        def make_separator(toolbar, expand=True):
            separator = Gtk.SeparatorToolItem()
            separator.props.draw = not expand
            separator.set_expand(expand)
            toolbar.insert(separator, -1)

        toolbar_box = ToolbarBox()
        toolbar = toolbar_box.toolbar

        activity_button = ToolButton()
        activity_button.set_icon_widget(ActivityIcon(None))
        toolbar.insert(activity_button, -1)

        toolbar.insert(Gtk.SeparatorToolItem(), -1)

        toolbar_file = Gtk.Toolbar()
        boton_toolbar_file = ToolbarButton(page=toolbar_file, icon_name='txt')
        toolbar.add(boton_toolbar_file)

        toolbar_edit = EditToolbar()
        button_toolbar_edit = ToolbarButton(page=toolbar_edit,
                                            icon_name='toolbar-edit')
        toolbar.insert(button_toolbar_edit, -1)

        toolbar_view = Gtk.Toolbar()
        boton_toolbar_view = ToolbarButton(page=toolbar_view,
                                           icon_name='toolbar-view')
        toolbar.insert(boton_toolbar_view, -1)

        self.button_undo = toolbar_edit.undo
        self.button_undo.props.accelerator = '<Ctrl>Z'
        self.button_undo.set_sensitive(False)
        toolbar_edit.undo.connect('clicked', self.undo)

        self.button_redo = toolbar_edit.redo
        self.button_redo.props.accelerator = '<Ctrl><Mayus>Z'
        self.button_redo.set_sensitive(False)
        self.button_redo.connect('clicked', self.redo)

        self.entry_search = IconEntry()
        item_entry = Gtk.ToolItem()
        self.entry_search.set_size_request(250, -1)
        self.entry_search.set_placeholder_text('Search...')
        self.entry_search.set_icon_from_name(Gtk.EntryIconPosition.SECONDARY,
                                             'search')
        self.entry_search.connect('changed', self.search_text)
        self.entry_search.connect('activate', self.search_text, True)
        item_entry.add(self.entry_search)
        toolbar_edit.insert(item_entry, -1)

        self.entry_replace = IconEntry()
        item_entry = Gtk.ToolItem()
        self.entry_replace.set_size_request(250, -1)
        self.entry_replace.set_placeholder_text('Replace...')
        self.entry_replace.connect('activate', self.replace_text)
        item_entry.add(self.entry_replace)
        toolbar_edit.insert(item_entry, -1)

        button_new = ToolButton('new-file')
        button_new.props.accelerator = '<Ctrl>N'
        button_new.connect('clicked', lambda w: self.new_page())
        button_new.set_tooltip(_('New file'))
        toolbar_file.insert(button_new, -1)

        button_open = ToolButton('fileopen')
        button_open.props.accelerator = '<Ctrl>O'
        button_open.set_tooltip(_('Open file from file system'))
        button_open.connect('clicked', self.file_chooser_open)
        toolbar_file.insert(button_open, -1)

        self.button_save = ToolButton('filesave')
        self.button_save.props.accelerator = '<Ctrl>S'
        self.button_save.set_tooltip(_('Save file to the file system'))
        self.button_save.connect('clicked', self.file_chooser_save)
        toolbar_file.insert(self.button_save, -1)

        button_save_as = ToolButton('save-as')
        button_save_as.props.accelerator = '<Ctrl><Mayus>S'
        button_save_as.set_tooltip(_('Save as file to the file system'))
        button_save_as.connect('clicked', self.file_chooser_save, True)
        toolbar_file.insert(button_save_as, -1)

        make_separator(toolbar_file, False)

        button_print = ToolButton('printer')
        button_print.props.accelerator = '<Ctrl>I'
        button_print.set_tooltip(_('Print file'))
        button_print.connect('clicked', self.print_file)
        toolbar_file.insert(button_print, -1)

        make_separator(toolbar_edit, False)

        button_clock = ToolButton('clock')
        button_clock.props.accelerator = '<Ctrl>T'
        button_clock.set_tooltip(_('Insert date and time'))
        button_clock.connect('clicked', self.insert_date_and_time)
        toolbar_edit.insert(button_clock, -1)

        button_wrap_none = Gtk.RadioToolButton()
        button_wrap_none.set_icon_name('wrap-none')
        button_wrap_none.connect("toggled", self.wrap_mode_changed, 'none')
        toolbar_view.insert(button_wrap_none, -1)

        button_wrap_char = Gtk.RadioToolButton.new_from_widget(
            button_wrap_none)
        button_wrap_char.set_icon_name('format-justify-fill')
        button_wrap_char.connect("toggled", self.wrap_mode_changed, 'char')
        toolbar_view.insert(button_wrap_char, -1)

        button_wrap_word = Gtk.RadioToolButton.new_from_widget(
            button_wrap_none)
        button_wrap_word.set_icon_name('format-justify-left')
        button_wrap_word.connect("toggled", self.wrap_mode_changed, 'word')
        toolbar_view.insert(button_wrap_word, -1)

        if self.conf['wrap-mode'] == 'none':
            button_wrap_none.set_active(True)

        elif self.conf['wrap-mode'] == 'char':
            button_wrap_none.set_active(True)

        elif self.conf['wrap-mode'] == 'word':
            button_wrap_none.set_active(True)

        make_separator(toolbar_view, False)

        item_font_size = FontSize()
        item_font_size.set_font_size(self.conf['font-size'])
        item_font_size.connect('changed', self.font_size_changed)
        toolbar_view.insert(item_font_size, -1)

        combo_font = FontComboBox(self.conf['font'])
        combo_font.connect('changed', self.font_changed)
        toolbar_view.insert(combo_font, -1)

        make_separator(toolbar_view, False)

        button_numbers = ToggleToolButton('show-numbers')
        button_numbers.props.accelerator = '<Ctrl><Mayus>N'
        button_numbers.set_tooltip(_('Show line numbers'))
        button_numbers.set_active(self.conf['show-line-numbers'])
        button_numbers.connect('toggled', self.show_numbers_changed)
        toolbar_view.insert(button_numbers, -1)

        button_right_line = ToggleToolButton('show-right-line')
        button_right_line.props.accelerator = '<Ctrl>L'
        button_right_line.set_tooltip(_('Show a line in a specific position'))
        button_right_line.set_active(self.conf['show-right-line'])
        button_right_line.connect('toggled', self.show_right_line_changed)
        toolbar_view.insert(button_right_line, -1)

        self.spinner_right_line = Spinner(self.conf['right-line-pos'], 1, 150)
        self.spinner_right_line.set_sensitive(self.conf['show-right-line'])
        self.spinner_right_line.connect('value-changed',
                                        self.right_line_pos_changed)
        toolbar_view.insert(self.spinner_right_line, -1)

        make_separator(toolbar_view, False)

        combo_styles = ComboStyles(self.conf['theme'])
        combo_styles.connect('theme-changed', self.theme_changed)
        toolbar_view.insert(combo_styles, -1)

        make_separator(toolbar, True)

        button_stop = ToolButton('activity-stop')
        button_stop.props.accelerator = '<Ctrl>Q'
        button_stop.connect('clicked', self._exit)
        toolbar.insert(button_stop, -1)

        toolbar_file.show_all()
        toolbar_edit.show_all()
        toolbar_view.show_all()

        toolbar_edit.copy.hide()
        toolbar_edit.paste.hide()

        self.set_toolbar_box(toolbar_box)

    def make_notebook(self):
        self.notebook = Gtk.Notebook()
        button_add = Gtk.ToolButton.new_from_stock(Gtk.STOCK_ADD)
        button_add.connect('clicked', lambda w: self.new_page())

        self.notebook.set_scrollable(True)
        self.notebook.set_show_tabs(True)
        self.notebook.set_action_widget(button_add, Gtk.PackType.END)

        self.notebook.add_events(Gdk.EventMask.SCROLL_MASK
                                 | Gdk.EventMask.SMOOTH_SCROLL_MASK)

        self.notebook.connect('switch-page', self.update_buttons)
        self.notebook.connect('scroll-event', self.notebook_scrolled)
        self.notebook.connect('page-removed', self.page_removed)

        self.vbox.pack_start(self.notebook, True, True, 2)
        self.new_page()
        button_add.show()
        self.show_all()

    def page_removed(self, notebook, scroll, page):
        if not self.reopen:
            return

        if len(self.notebook.get_children()) == 0:
            self.new_page()

    def set_language(self, infobar, language):
        buffer = self.get_view().buffer
        buffer.set_language_from_string(language)

    def set_language_from_buffer(self, buffer, language):
        self.infobar.set_language(language)

    def notebook_scrolled(self, widget, event):
        if event.get_scroll_direction()[1] == Gdk.ScrollDirection.UP:
            self.notebook.prev_page()
        elif event.get_scroll_direction()[1] == Gdk.ScrollDirection.DOWN:
            self.notebook.next_page()

    def update_buttons(self, notebook=None, scrolled=None, *args):
        if not isinstance(scrolled, Gtk.ScrolledWindow):
            view = self.get_view()

        else:
            view = scrolled.get_children()[0]

        buffer = view.get_buffer()

        self.button_undo.set_sensitive(buffer.can_undo())
        self.button_redo.set_sensitive(buffer.can_redo())
        self.button_save.set_sensitive(buffer.get_modified())
        self.entry_search.set_sensitive(bool(buffer.get_all_text()))
        self.entry_replace.set_sensitive(bool(buffer.get_all_text()))
        self.spinner_right_line.set_sensitive(self.conf['show-right-line'])
        self.infobar.set_language(buffer.get_language_str())
        self.update_cursor_position(buffer)

    def new_page(self, view=None, label=None):
        if not view:
            view = View(self.conf)
            view.buffer.connect('changed', self.update_buttons)
            view.buffer.connect('mark-set', self.update_cursor_position)
            view.buffer.connect('language-changed',
                                self.set_language_from_buffer)

        if not label:
            label = view.get_file_name()

        if type(label) == str:
            label = Gtk.Label(label)
            label.modify_font(Pango.FontDescription('15 bold'))

        view.connect('title-changed', self.change_title_from_view)

        scrolled = Gtk.ScrolledWindow()
        scrolled.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        scrolled.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
        scrolled.add(view)

        hbox = Gtk.HBox()
        hbox.set_size_request(-1, 20)

        hbox.pack_start(label, False, False, 0)

        button = Gtk.Button()
        button.set_relief(Gtk.ReliefStyle.NONE)
        button.set_size_request(12, 12)
        button.set_image(
            Gtk.Image.new_from_stock(Gtk.STOCK_CLOSE, Gtk.IconSize.MENU))
        button.connect('clicked', self.remove_page_from_widget, scrolled)
        hbox.pack_start(button, False, False, 0)

        self.notebook.append_page(scrolled, hbox)
        self.notebook.set_tab_reorderable(scrolled, True)

        view.grab_focus()
        hbox.show_all()
        self.show_all()

        self.notebook.set_current_page(self.notebook.get_n_pages() - 1)
        return view

    def update_cursor_position(self, buffer, *args):
        iter = buffer.get_iter_at_mark(buffer.get_insert())
        line = iter.get_line() + 1
        column = iter.get_line_offset() + 1
        self.infobar.set_pos(line, column)

    def file_chooser_open(self, widget):
        path = self.get_view().get_file()
        file_chooser = FileChooserOpen(self, path)
        file_chooser.connect('open-file', self._open_file_from_chooser)
        file_chooser.show_all()

    def file_chooser_save(self, widget, force=False, close=False):
        # Force is for "save as"

        idx = self.notebook.get_current_page()
        view = self.get_view()

        if view.get_file() and not force:
            self.save_file(idx=idx, path=view.get_file())
            return

        file_chooser = FileChooserSave()
        file_chooser.connect('save-file', self._save_file_from_chooser, close)
        file_chooser.show_all()

    def begin_print(self, operation, context, compositor):
        while not compositor.paginate(context):
            pass

        n_pages = compositor.get_n_pages()
        operation.set_n_pages(n_pages)

    def draw_page(self, operation, context, page_nr, compositor):
        compositor.draw_page(context, page_nr)

    def print_file(self, widget):
        def _alert_response(alert, response):
            self.vbox.remove(alert)

        view = self.get_view()
        buffer = view.get_buffer()
        path = view.get_file()

        if not path:
            alert = TimeoutAlert(10)
            alert.props.title = _('This file has not saved.')
            alert.props.msg = _('You must save this file to print.')
            hbox = alert.get_children()[0]
            buttonbox = hbox.get_children()[1]
            button = buttonbox.get_children()[0]
            buttonbox.remove(button)

            alert.connect('response', _alert_response)

            self.vbox.pack_start(alert, False, False, 0)
            self.vbox.reorder_child(alert, 0)

            return

        compositor = GtkSource.PrintCompositor.new_from_view(view)
        compositor.set_wrap_mode(view.get_wrap_mode())
        compositor.set_highlight_syntax(buffer.get_highlight_syntax())
        compositor.set_print_line_numbers(self.conf['show-line-numbers'])

        if view.buffer.language:
            compositor.set_header_format(
                False,
                '%s - %s' % (view.buffer.get_language_str(), view.get_file()),
                None, None)

        compositor.set_footer_format(True, '%T', path, 'Page %N/%Q')
        compositor.set_print_header(True)
        compositor.set_print_footer(True)

        operation = Gtk.PrintOperation()
        operation.set_job_name(path)

        operation.connect('begin-print', self.begin_print, compositor)
        operation.connect('draw-page', self.draw_page, compositor)

        res = operation.run(Gtk.PrintOperationAction.PRINT_DIALOG, None)
        if res == Gtk.PrintOperationResult.ERROR:
            dialog = Gtk.MessageDialog(self,
                                       Gtk.DialogFlags.DESTROY_WITH_PARENT,
                                       Gtk.MessageType.ERROR,
                                       Gtk.ButtonsType.OK,
                                       'Error to print the file: %s' % path)

            dialog.run()
            dialog.destroy()

    def _open_file_from_chooser(self, widget, path):
        children = self.notebook.get_children()
        for scrolled in children:
            view = scrolled.get_children()[0]
            if view.get_file() == path:
                idx = children.index(scrolled)
                self.notebook.set_current_page(idx)
                return

        view = self.get_view()

        if view.get_file():
            self.new_page(label=view.get_file_name())
            view = self.get_view(idx=-1)

        view.set_file(path)

    def _save_file_from_chooser(self, widget, path, close=False):
        view = self.get_view()
        view.save_file(path)

        if close:
            view = self.get_view()
            scrolled = view.get_parent()
            idx = self.notebook.get_children().index(scrolled)
            self.notebook.remove_page(idx)

    def save_file(self, widget=None, idx=None, path=None):
        if idx is not None:
            idx = self.notebook.get_current_page()

        scrolled = self.notebook.get_children()[idx]
        view = scrolled.get_children()[0]
        view.save_file(view.get_file())

    def remove_page_from_widget(self, widget, scrolled, force=False):
        view = scrolled.get_children()[0]
        buffer = view.get_buffer()
        idx = self.notebook.get_children().index(scrolled)

        if not buffer.get_modified() or force:
            self.notebook.remove_page(idx)

        else:
            name = view.get_file_name()
            title = _('Save changes to document "%s" before closing?' % name)
            msg = _('If you do not save, changes will be lost forever.')
            cancel = Gtk.Image.new_from_icon_name('dialog-cancel',
                                                  Gtk.IconSize.MENU)
            no = Gtk.Image.new_from_icon_name('activity-stop',
                                              Gtk.IconSize.MENU)
            save = Gtk.Image.new_from_icon_name('filesave', Gtk.IconSize.MENU)

            self.alert = Alert()
            self.alert.props.title = title
            self.alert.props.msg = msg

            button1 = self.alert.add_button(Gtk.ResponseType.CANCEL,
                                            _('Cancel'),
                                            icon=cancel)
            button2 = self.alert.add_button(Gtk.ResponseType.NO,
                                            _('No save'),
                                            icon=no)
            button3 = self.alert.add_button(Gtk.ResponseType.YES,
                                            _('Save'),
                                            icon=save)

            self.alert.connect('response', self._alert_response, scrolled)

            self.vbox.pack_start(self.alert, False, False, 0)
            self.vbox.reorder_child(self.alert, 0)
            self.vbox.show_all()

    def change_title_from_view(self, view=None, label=None):
        if not view:
            view = self.get_view()
        if not label:
            label = view.get_file_name()

        scrolled = view.get_parent()
        hbox = self.notebook.get_tab_label(scrolled)
        widget = hbox.get_children()[0]
        changed = view.get_buffer().get_modified()

        widget.set_label(label)

        color = '#FF0000' if changed else '#FFFFFF'
        widget.modify_fg(Gtk.StateType.NORMAL, Gdk.color_parse(color))
        self.update_buttons()

    def get_view(self, idx=None):
        if idx is None:
            idx = self.notebook.get_current_page()

        scrolled = self.notebook.get_children()[idx]
        return scrolled.get_children()[0]

    def undo(self, widget):
        self.get_view().undo()
        self.change_title_from_view()

    def redo(self, widget):
        self.get_view().redo()
        self.change_title_from_view()

    def search_text(self, entry, enter=False):
        text = entry.get_text()
        self.get_view().search(text, enter)

    def replace_text(self, entry):
        text_search = self.entry_search.get_text()
        text_replace = entry.get_text()
        self.get_view().replace(text_search, text_replace)

    def wrap_mode_changed(self, widget, mode):
        self.conf['wrap-mode'] = mode
        self.set_conf_to_views()

    def font_size_changed(self, widget, font_size):
        self.conf['font-size'] = font_size
        self.set_conf_to_views()

    def font_changed(self, widget, font):
        self.conf['font'] = font
        self.set_conf_to_views()

    def show_numbers_changed(self, widget):
        self.conf['show-line-numbers'] = widget.get_active()
        self.set_conf_to_views()

    def show_right_line_changed(self, widget):
        self.conf['show-right-line'] = widget.get_active()
        self.update_buttons()
        self.set_conf_to_views()

    def right_line_pos_changed(self, widget, value):
        self.conf['right-line-pos'] = value
        self.set_conf_to_views()

    def theme_changed(self, widget, theme):
        self.conf['theme'] = theme
        self.set_conf_to_views()

    def tab_width_changed(self, widget, tab_width):
        self.conf['tab-width'] = tab_width
        self.set_conf_to_views()

    def set_conf_to_views(self):
        for scrolled in self.notebook.get_children():
            view = scrolled.get_children()[0]
            view.set_conf(self.conf)

    def insert_date_and_time(self, widget):
        view = self.get_view()
        day = datetime.date.today()
        date = day.strftime('%d/%m/%y')
        hour = time.strftime('%H:%M:%S')
        text = date + ' ' + hour

        view.buffer.insert_interactive_at_cursor(text, -1, True)

    def _alert_response(self, widget, response, scrolled):
        if response == Gtk.ResponseType.NO:
            self.remove_page_from_widget(None, scrolled, force=True)
        elif response == Gtk.ResponseType.YES:
            self.file_chooser_save(None, False, True)

        self.vbox.remove(self.alert)

    def write_file(self, file_path):
        files = []

        for scrolled in self.notebook.get_children():
            view = scrolled.get_children()[0]
            if view.get_file():
                files.append(view.get_file)

        self.metadata['saved'] = True
        self.metadata['font'] = self.conf['font']
        self.metadata['font-size'] = self.conf['font-size']
        self.metadata['show-line-numbers'] = self.conf['show-line-numbers']
        self.metadata['tab-width'] = self.conf['tab-width']
        self.metadata['use-spaces'] = self.conf['use-spaces']
        self.metadata['theme'] = self.conf['theme']
        self.metadata['right-line-pos'] = self.conf['right-line-pos']
        self.metadata['show-right-line'] = self.conf['show-right-line']
        self.metadata['wrap-mode'] = self.conf['wrap-mode']

    def _exit(self, *args):
        def _remove_page(widget, scrolled):
            if scrolled in self.notebook.get_children():
                idx = self.notebook.get_children().index(scrolled)
                self.notebook.remove_page(idx)

            check_modified()

        def _alert_response(alert, response, scrolled):
            self.vbox.remove(alert)

            if response == Gtk.ResponseType.YES:
                view = scrolled.get_children()[0]

                if view.get_file():
                    idx = self.notebook.get_children()
                    self.save_file(idx=idx, path=view.get_file())
                    self.remove_page_from_widget(None, scrolled, force=True)
                    return

                file_chooser = FileChooserSave()
                file_chooser.connect('save-file', self._save_file_from_chooser,
                                     True)
                file_chooser.connect('destroy', _remove_page, scrolled)
                file_chooser.show_all()

            else:
                self.remove_page_from_widget(None, scrolled, force=True)
                check_modified()

        def _create_alert(name, scrolled):
            title = _('Save changes to document "%s" before closing?' % name)
            msg = _('If you do not save, changes will be lost forever.')

            no = Gtk.Image.new_from_icon_name('activity-stop',
                                              Gtk.IconSize.MENU)
            save = Gtk.Image.new_from_icon_name('filesave', Gtk.IconSize.MENU)

            alert = Alert()
            alert.props.title = title
            alert.props.msg = msg

            button1 = alert.add_button(Gtk.ResponseType.NO,
                                       _('No save'),
                                       icon=no)
            button2 = alert.add_button(Gtk.ResponseType.YES,
                                       _('Save'),
                                       icon=save)

            alert.connect('response', _alert_response, scrolled)

            self.vbox.pack_start(alert, False, False, 0)
            self.vbox.reorder_child(alert, 0)
            self.vbox.show_all()

        def check_modified():
            if not self.notebook.get_children():
                _close()
                return

            self.notebook.set_current_page(self.notebook.get_n_pages() - 1)
            scrolled = self.notebook.get_children()[-1]
            view = scrolled.get_children()[0]
            buffer = view.get_buffer()

            if buffer.get_modified():
                name = view.get_file_name()
                _create_alert(name, scrolled)

            else:
                self.remove_page_from_widget(None, scrolled, force=True)
                check_modified()

        def _close():
            self.close()

        self.reopen = False
        check_modified()
Example #41
0
    def __init__(self, handle):
        ''' Initialize the toolbar '''
        try:
            super(ReflectActivity, self).__init__(handle)
        except dbus.exceptions.DBusException as e:
            _logger.error(str(e))

        logging.error('setting reflection data to []')
        self.reflection_data = []

        self.connect('realize', self.__realize_cb)

        self.font_size = 8

        self.max_participants = 4
        self._setup_toolbars()

        color = profile.get_color()
        color_stroke = color.get_stroke_color()
        color_fill = color.get_fill_color()

        lighter = utils.lighter_color([color_stroke, color_fill])
        darker = 1 - lighter

        if lighter == 0:
            self.bg_color = style.Color(color_stroke)
            self.fg_color = style.Color(color_fill)
        else:
            self.bg_color = style.Color(color_fill)
            self.fg_color = style.Color(color_stroke)

        self.modify_bg(Gtk.StateType.NORMAL, self.bg_color.get_gdk_color())

        self.bundle_path = activity.get_bundle_path()
        self.tmp_path = os.path.join(activity.get_activity_root(), 'instance')

        self.sharing = False
        self._copy_entry = None
        self._paste_entry = None
        self._webkit = None
        self._clipboard_text = ''
        self._fixed = None

        self.initiating = True
        if self.shared_activity:
            # We're joining
            if not self.get_shared():
                self.initiating = False

                self.busy_cursor()
                share_icon = Icon(icon_name='zoom-neighborhood')
                self._joined_alert = Alert()
                self._joined_alert.props.icon = share_icon
                self._joined_alert.props.title = _('Please wait')
                self._joined_alert.props.msg = _('Starting connection...')
                self.add_alert(self._joined_alert)

                # Wait for joined signal
                self.connect("joined", self._joined_cb)

        self._open_reflect_windows()

        self._setup_presence_service()

        # Joiners wait to receive data from sharer
        # Otherwise, load reflections from local store
        if not self.shared_activity:
            self.busy_cursor()
            GObject.idle_add(self._load_reflections)
Example #42
0
    def __accept_clicked_cb(self, widget):
        if hasattr(self._section_view, "apply"):
            self._section_view.apply()

        if self._section_view.needs_restart:
            self._section_toolbar.accept_button.set_sensitive(False)
            self._section_toolbar.cancel_button.set_sensitive(False)
            alert = Alert()
            alert.props.title = _('Warning')
            alert.props.msg = _('Changes require restart')

            if self._section_view.props.is_cancellable:
                icon = Icon(icon_name='dialog-cancel')
                alert.add_button(Gtk.ResponseType.CANCEL, _('Cancel changes'),
                                 icon)
                icon.show()

            if self._current_option not in ('aboutme', 'backup'):
                icon = Icon(icon_name='dialog-ok')
                alert.add_button(Gtk.ResponseType.ACCEPT, _('Later'), icon)
                icon.show()

            icon = Icon(icon_name='system-restart')
            alert.add_button(Gtk.ResponseType.APPLY, _('Restart now'), icon)
            icon.show()

            self._vbox.pack_start(alert, False, False, 0)
            self._vbox.reorder_child(alert, 2)
            alert.connect('response', self.__response_cb)
            alert.show()
        else:
            self._show_main_view()
Example #43
0
class Network(SectionView):
    def __init__(self, model, alerts):
        SectionView.__init__(self)

        self._model = model
        self.restart_alerts = alerts
        self._jabber_sid = 0
        self._radio_valid = True
        self._jabber_change_handler = None
        self._radio_change_handler = None
        self._wireless_configuration_reset_handler = None
        self._start_jabber = self._model.get_jabber()
        self._proxy_settings = {}
        self._proxy_inline_alerts = {}

        self.set_border_width(style.DEFAULT_SPACING * 2)
        self.set_spacing(style.DEFAULT_SPACING)
        group = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL)

        self._radio_alert_box = Gtk.HBox(spacing=style.DEFAULT_SPACING)

        scrolled = Gtk.ScrolledWindow()
        scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        self.add(scrolled)
        scrolled.show()

        workspace = Gtk.VBox()
        scrolled.add_with_viewport(workspace)
        workspace.show()

        separator_wireless = Gtk.HSeparator()
        workspace.pack_start(separator_wireless, False, True, 0)
        separator_wireless.show()

        label_wireless = Gtk.Label(label=_('Wireless'))
        label_wireless.set_alignment(0, 0)
        workspace.pack_start(label_wireless, False, True, 0)
        label_wireless.show()
        box_wireless = Gtk.VBox()
        box_wireless.set_border_width(style.DEFAULT_SPACING * 2)
        box_wireless.set_spacing(style.DEFAULT_SPACING)

        radio_info = Gtk.Label(label=_('The wireless radio may be turned'
                                       ' off to save battery life.'))
        radio_info.set_alignment(0, 0)
        radio_info.set_line_wrap(True)
        radio_info.show()
        box_wireless.pack_start(radio_info, False, True, 0)

        box_radio = Gtk.HBox(spacing=style.DEFAULT_SPACING)
        self._button = Gtk.CheckButton()
        self._button.set_alignment(0, 0)
        box_radio.pack_start(self._button, False, True, 0)
        self._button.show()

        label_radio = Gtk.Label(label=_('Radio'))
        label_radio.set_alignment(0, 0.5)
        box_radio.pack_start(label_radio, False, True, 0)
        label_radio.show()

        box_wireless.pack_start(box_radio, False, True, 0)
        box_radio.show()

        self._radio_alert = InlineAlert()
        self._radio_alert_box.pack_start(self._radio_alert, False, True, 0)
        box_radio.pack_end(self._radio_alert_box, False, True, 0)
        self._radio_alert_box.show()
        if 'radio' in self.restart_alerts:
            self._radio_alert.props.msg = self.restart_msg
            self._radio_alert.show()

        wireless_info = Gtk.Label(
            label=_('Discard wireless connections if'
                    ' you have trouble connecting to the network'))
        wireless_info.set_alignment(0, 0)
        wireless_info.set_line_wrap(True)
        wireless_info.show()
        box_wireless.pack_start(wireless_info, False, True, 0)

        box_clear_wireless = Gtk.HBox(spacing=style.DEFAULT_SPACING)
        self._clear_wireless_button = Gtk.Button()
        self._clear_wireless_button.set_label(
            _('Discard wireless connections'))
        box_clear_wireless.pack_start(self._clear_wireless_button, False, True,
                                      0)
        if not self._model.have_wireless_networks():
            self._clear_wireless_button.set_sensitive(False)
        self._clear_wireless_button.show()
        box_wireless.pack_start(box_clear_wireless, False, True, 0)
        box_clear_wireless.show()

        workspace.pack_start(box_wireless, False, True, 0)
        box_wireless.show()

        separator_mesh = Gtk.HSeparator()
        workspace.pack_start(separator_mesh, False, False, 0)
        separator_mesh.show()

        label_mesh = Gtk.Label(label=_('Collaboration'))
        label_mesh.set_alignment(0, 0)
        workspace.pack_start(label_mesh, False, True, 0)
        label_mesh.show()
        box_mesh = Gtk.VBox()
        box_mesh.set_border_width(style.DEFAULT_SPACING * 2)
        box_mesh.set_spacing(style.DEFAULT_SPACING)

        server_info = Gtk.Label(
            _("The server is the equivalent of what"
              " room you are in; people on the same server"
              " will be able to see each other, even when"
              " they aren't on the same network."))
        server_info.set_alignment(0, 0)
        server_info.set_line_wrap(True)
        box_mesh.pack_start(server_info, False, True, 0)
        server_info.show()

        box_server = Gtk.HBox(spacing=style.DEFAULT_SPACING)
        label_server = Gtk.Label(label=_('Server:'))
        label_server.set_alignment(1, 0.5)
        label_server.modify_fg(Gtk.StateType.NORMAL,
                               style.COLOR_SELECTION_GREY.get_gdk_color())
        box_server.pack_start(label_server, False, True, 0)
        group.add_widget(label_server)
        label_server.show()
        self._entry = Gtk.Entry()
        self._entry.set_alignment(0)
        self._entry.set_size_request(int(Gdk.Screen.width() / 3), -1)
        box_server.pack_start(self._entry, False, True, 0)
        self._entry.show()
        box_mesh.pack_start(box_server, False, True, 0)
        box_server.show()

        social_help_info = Gtk.Label(
            _('Social Help is a forum that lets you connect with developers'
              ' and discuss Sugar Activities.  Changing servers means'
              ' discussions will happen in a different place with'
              ' different people.'))
        social_help_info.set_alignment(0, 0)
        social_help_info.set_line_wrap(True)
        box_mesh.pack_start(social_help_info, False, True, 0)
        social_help_info.show()

        social_help_box = Gtk.HBox(spacing=style.DEFAULT_SPACING)
        social_help_label = Gtk.Label(label=_('Social Help Server:'))
        social_help_label.set_alignment(1, 0.5)
        social_help_label.modify_fg(Gtk.StateType.NORMAL,
                                    style.COLOR_SELECTION_GREY.get_gdk_color())
        social_help_box.pack_start(social_help_label, False, True, 0)
        group.add_widget(social_help_label)
        social_help_label.show()

        self._social_help_entry = Gtk.Entry()
        self._social_help_entry.set_alignment(0)
        self._social_help_entry.set_size_request(int(Gdk.Screen.width() / 3),
                                                 -1)
        social_help_box.pack_start(self._social_help_entry, False, True, 0)
        self._social_help_entry.show()
        box_mesh.pack_start(social_help_box, False, True, 0)
        social_help_box.show()

        workspace.pack_start(box_mesh, False, True, 0)
        box_mesh.show()

        separator_proxy = Gtk.HSeparator()
        workspace.pack_start(separator_proxy, False, False, 0)
        separator_proxy.show()

        self._add_proxy_section(workspace)

        self.setup()

    def _add_proxy_section(self, workspace):
        label_proxy = Gtk.Label(_('Proxy'))
        label_proxy.set_alignment(0, 0)
        workspace.pack_start(label_proxy, False, True, 0)
        label_proxy.show()

        box_proxy = Gtk.VBox()
        box_proxy.set_border_width(style.DEFAULT_SPACING * 2)
        box_proxy.set_spacing(style.DEFAULT_SPACING)
        workspace.pack_start(box_proxy, False, True, 0)
        box_proxy.show()

        self._proxy_alert = Alert()
        self._proxy_alert.props.title = _('Error')
        self._proxy_alert.props.msg = _('Proxy settings cannot be verified')
        box_proxy.pack_start(self._proxy_alert, False, False, 0)
        self._proxy_alert.connect('response', self._response_cb)
        self._proxy_alert.hide()

        # GSettings schemas for proxy:
        schemas = [
            'org.sugarlabs.system.proxy', 'org.sugarlabs.system.proxy.http',
            'org.sugarlabs.system.proxy.https',
            'org.sugarlabs.system.proxy.ftp',
            'org.sugarlabs.system.proxy.socks'
        ]

        for schema in schemas:
            proxy_setting = Gio.Settings.new(schema)

            # We are not going to apply the settings immediatly.
            # We'll apply them if the user presses the "accept"
            # button, or we'll revert them if the user presses the
            # "cancel" button.
            proxy_setting.delay()
            alert = InlineAlert()

            self._proxy_settings[schema] = proxy_setting
            self._proxy_inline_alerts[schema] = alert

        size_group = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL)

        automatic_proxy_box = Gtk.VBox(spacing=style.DEFAULT_SPACING)
        manual_proxy_box = Gtk.VBox(spacing=style.DEFAULT_SPACING)

        option_sets = [('None', 'none', Gtk.VBox()),
                       ('Use system proxy', 'system', Gtk.VBox()),
                       ('Manual', 'manual', manual_proxy_box),
                       ('Automatic', 'auto', automatic_proxy_box)]

        box_mode = ComboSettingBox(
            _('Method:'), self._proxy_settings['org.sugarlabs.system.proxy'],
            'mode', option_sets, size_group)

        box_proxy.pack_start(box_mode, False, False, 0)
        box_mode.show()

        url_box = StringSettingBox(
            _('Configuration URL:'),
            self._proxy_settings['org.sugarlabs.system.proxy'],
            'autoconfig-url', size_group)

        automatic_proxy_box.pack_start(url_box, True, True, 0)
        url_box.show()

        wpad_help_text = _('Web Proxy Autodiscovery is used when a'
                           ' Configuration URL is not provided. This is not'
                           ' recommended for untrusted public networks.')
        automatic_proxy_help = Gtk.Label(wpad_help_text)
        automatic_proxy_help.set_alignment(0, 0)
        automatic_proxy_help.set_line_wrap(True)
        automatic_proxy_help.show()
        automatic_proxy_box.pack_start(automatic_proxy_help, True, True, 0)

        # HTTP Section
        schema = 'org.sugarlabs.system.proxy.http'
        box_http = HostPortSettingBox(_('HTTP Proxy:'),
                                      self._proxy_inline_alerts[schema],
                                      self._proxy_settings[schema], size_group)
        manual_proxy_box.pack_start(box_http, False, False, 0)
        box_http.show()
        auth_contents_box = Gtk.VBox(spacing=style.DEFAULT_SPACING)
        auth_box = OptionalSettingsBox(_('Use authentication'),
                                       self._proxy_settings[schema],
                                       'use-authentication', auth_contents_box)
        manual_proxy_box.pack_start(auth_box, False, False, 0)
        auth_box.show()
        proxy_http_setting = Gio.Settings.new(schema)
        proxy_http_setting.delay()
        box_username = StringSettingBox(_('Username:'******'authentication-user', size_group)
        auth_contents_box.pack_start(box_username, False, False, 0)
        box_username.show()
        box_password = StringSettingBox(_('Password:'******'authentication-password',
                                        size_group,
                                        password_field=True)
        auth_contents_box.pack_start(box_password, False, False, 0)
        box_password.show()

        # HTTPS Section
        schema = 'org.sugarlabs.system.proxy.https'
        box_https = HostPortSettingBox(_('HTTPS Proxy:'),
                                       self._proxy_inline_alerts[schema],
                                       self._proxy_settings[schema],
                                       size_group)
        manual_proxy_box.pack_start(box_https, False, False, 0)
        box_https.show()

        # FTP Section
        schema = 'org.sugarlabs.system.proxy.ftp'
        box_ftp = HostPortSettingBox(_('FTP Proxy:'),
                                     self._proxy_inline_alerts[schema],
                                     self._proxy_settings[schema], size_group)
        manual_proxy_box.pack_start(box_ftp, False, False, 0)
        box_ftp.show()

        # SOCKS Section
        schema = 'org.sugarlabs.system.proxy.socks'
        box_socks = HostPortSettingBox(_('SOCKS Proxy:'),
                                       self._proxy_inline_alerts[schema],
                                       self._proxy_settings[schema],
                                       size_group)
        manual_proxy_box.pack_start(box_socks, False, False, 0)
        box_socks.show()

        box_ignore = StringSettingBox_with_convert(
            _('Ignore Hosts:'),
            self._proxy_settings['org.sugarlabs.system.proxy'], 'ignore-hosts',
            type_as_to_string, string_to_type_as, size_group)
        manual_proxy_box.pack_start(box_ignore, False, False, 0)
        box_ignore.show()

    def setup(self):
        self._entry.set_text(self._start_jabber)
        self._social_help_entry.set_text(self._model.get_social_help())

        try:
            radio_state = self._model.get_radio()
        except self._model.ReadError as detail:
            self._radio_alert.props.msg = detail
            self._radio_alert.show()
        else:
            self._button.set_active(radio_state)

        self._radio_valid = True
        self.needs_restart = False
        self._radio_change_handler = self._button.connect(
            'toggled', self.__radio_toggled_cb)
        self._wireless_configuration_reset_handler =  \
            self._clear_wireless_button.connect(
                'clicked', self.__wireless_configuration_reset_cb)

    def _response_cb(self, alert, response_id):
        if response_id is Gtk.ResponseType.APPLY:
            self._proxy_alert.hide()
            self._apply_proxy_settings()
            self.show_restart_alert = True
            self.emit('add-alert')
        elif response_id is Gtk.ResponseType.CANCEL:
            self.undo()
            self._proxy_alert.remove_button(Gtk.ResponseType.APPLY)
            self._proxy_alert.remove_button(Gtk.ResponseType.CANCEL)
            self._proxy_alert.hide()
            self.emit('set-toolbar-sensitivity', True)

    def _ping_servers(self):
        response_to_return = True
        non_blank_host_name_counter = 0  # To check accidental blank hostnames
        for schema in list(self._proxy_settings.keys()):
            if (schema != 'org.sugarlabs.system.proxy'):
                hostname = Gio.Settings.get_string(
                    self._proxy_settings[schema], 'host')
                if hostname != '':
                    non_blank_host_name_counter += 1
                    response = os.system("ping -c 1 -W 1 " + hostname)
                    if (response):
                        self._proxy_inline_alerts[schema].show()
                        response_to_return = False
        if non_blank_host_name_counter == 0:
            response_to_return = False
        return response_to_return

    def _verify_settings(self):
        self._proxy_alert.props.title = _('Please Wait!')
        self._proxy_alert.props.msg = _('Proxy settings are being verified.')
        self._proxy_alert.show()
        flag_all_true = True
        g_proxy_schema = self._proxy_settings['org.sugarlabs.system.proxy']
        g_mode = Gio.Settings.get_string(g_proxy_schema, 'mode')
        self.show_restart_alert = False

        if g_mode == 'auto':
            flag_all_true = os.path.isfile(
                Gio.Settings.get_string(g_proxy_schema, 'autoconfig-url'))
        elif g_mode == 'manual':
            flag_all_true = self._ping_servers()
        if flag_all_true:
            self.show_restart_alert = True
            self._proxy_alert.hide()
            self._apply_proxy_settings()
        else:
            self._proxy_alert.props.title = _('Error!')
            self._proxy_alert.props.msg = _('The following setting(s) seems '
                                            'to be incorrect and may break '
                                            'your internet connection')

            icon = Icon(icon_name='dialog-cancel')
            self._proxy_alert.add_button(Gtk.ResponseType.APPLY,
                                         _('Break my internet'), icon)
            icon.show()
            icon = Icon(icon_name='dialog-ok')
            self._proxy_alert.add_button(Gtk.ResponseType.CANCEL, _('Reset'),
                                         icon)
            icon.show()

    def _apply_proxy_settings(self):
        for setting in list(self._proxy_settings.values()):
            if (Gio.Settings.get_has_unapplied(setting)):
                setting.apply()

    def apply(self):
        self._apply_jabber(self._entry.get_text())
        self._model.set_social_help(self._social_help_entry.get_text())
        settings_changed = False
        for setting in list(self._proxy_settings.values()):
            if (Gio.Settings.get_has_unapplied(setting)):
                settings_changed = True
        if settings_changed:
            self.needs_restart = True
            self._is_cancellable = False
            self.restart_msg = _('Proxy changes require restart')
            self._verify_settings()
        else:
            self.show_restart_alert = True

    def undo(self):
        self._button.disconnect(self._radio_change_handler)
        self._radio_alert.hide()
        for setting in list(self._proxy_settings.values()):
            setting.revert()
        for alert in list(self._proxy_inline_alerts.values()):
            alert.hide()

    def _validate(self):
        if self._radio_valid:
            self.props.is_valid = True
        else:
            self.props.is_valid = False

    def __radio_toggled_cb(self, widget, data=None):
        radio_state = widget.get_active()
        try:
            self._model.set_radio(radio_state)
        except self._model.ReadError as detail:
            self._radio_alert.props.msg = detail
            self._radio_valid = False
        else:
            self._radio_valid = True
            if self._model.have_wireless_networks():
                self._clear_wireless_button.set_sensitive(True)

        self._validate()
        return False

    def _apply_jabber(self, jabber):
        if jabber == self._model.get_jabber():
            return
        self._model.set_jabber(jabber)

    def __wireless_configuration_reset_cb(self, widget):
        # FIXME: takes effect immediately, not after CP is closed with
        # confirmation button
        self._model.clear_wireless_networks()
        self._clear_wireless_button.set_sensitive(False)
class Download(object):
    def __init__(self, download, browser):
        self._download = download
        self._activity = browser.get_toplevel()
        self._source = download.get_uri()

        self._download.connect('notify::status', self.__state_change_cb)
        self._download.connect('error', self.__error_cb)

        self.datastore_deleted_handler = None

        self.dl_jobject = None
        self._object_id = None
        self._last_update_time = 0
        self._last_update_percent = 0
        self._stop_alert = None

        # figure out download URI
        self.temp_path = os.path.join(activity.get_activity_root(), 'instance')
        if not os.path.exists(self.temp_path):
            os.makedirs(self.temp_path)

        fd, self._dest_path = tempfile.mkstemp(
            dir=self.temp_path,
            suffix=download.get_suggested_filename(),
            prefix='tmp')
        os.close(fd)
        logging.debug('Download destination path: %s' % self._dest_path)

        # We have to start the download to get 'total-size'
        # property. It not, 0 is returned
        self._download.set_destination_uri('file://' + self._dest_path)
        self._download.start()

    def __progress_change_cb(self, download, something):
        progress = self._download.get_progress()
        self.dl_jobject.metadata['progress'] = str(int(progress * 100))
        datastore.write(self.dl_jobject)

    def __state_change_cb(self, download, gparamspec):
        state = self._download.get_status()
        if state == WebKit.DownloadStatus.STARTED:
            # Check free space and cancel the download if there is not enough.
            total_size = self._download.get_total_size()
            logging.debug('Total size of the file: %s', total_size)
            enough_space = self.enough_space(total_size, path=self.temp_path)
            if not enough_space:
                logging.debug('Download canceled because of Disk Space')
                self.cancel()

                self._canceled_alert = Alert()
                self._canceled_alert.props.title = _('Not enough space '
                                                     'to download')

                total_size_mb = total_size / 1024.0**2
                free_space_mb = self._free_available_space(
                    path=self.temp_path) - SPACE_THRESHOLD / 1024.0**2
                filename = self._download.get_suggested_filename()
                self._canceled_alert.props.msg = \
                    _('Download "%{filename}" requires %{total_size_in_mb}'
                      ' MB of free space, only %{free_space_in_mb} MB'
                      ' is available' %
                      {'filename': filename,
                       'total_size_in_mb': format_float(total_size_mb),
                       'free_space_in_mb': format_float(free_space_mb)})
                ok_icon = Icon(icon_name='dialog-ok')
                self._canceled_alert.add_button(Gtk.ResponseType.OK, _('Ok'),
                                                ok_icon)
                ok_icon.show()
                self._canceled_alert.connect('response',
                                             self.__stop_response_cb)
                self._activity.add_alert(self._canceled_alert)
            else:
                self._download.connect('notify::progress',
                                       self.__progress_change_cb)
                self._create_journal_object()
                self._object_id = self.dl_jobject.object_id

                alert = TimeoutAlert(9)
                alert.props.title = _('Download started')
                alert.props.msg = _('%s' %
                                    self._download.get_suggested_filename())
                self._activity.add_alert(alert)
                alert.connect('response', self.__start_response_cb)
                alert.show()
                global _active_downloads
                _active_downloads.append(self)

        elif state == WebKit.DownloadStatus.FINISHED:
            self._stop_alert = Alert()
            self._stop_alert.props.title = _('Download completed')
            self._stop_alert.props.msg = \
                _('%s' % self._download.get_suggested_filename())
            open_icon = Icon(icon_name='zoom-activity')
            self._stop_alert.add_button(Gtk.ResponseType.APPLY,
                                        _('Show in Journal'), open_icon)
            open_icon.show()
            ok_icon = Icon(icon_name='dialog-ok')
            self._stop_alert.add_button(Gtk.ResponseType.OK, _('Ok'), ok_icon)
            ok_icon.show()
            self._activity.add_alert(self._stop_alert)
            self._stop_alert.connect('response', self.__stop_response_cb)
            self._stop_alert.show()

            if self._dest_path.endswith('.journal'):

                metadata, preview_data, file_path = \
                    utils.unpackage_ds_object(self._dest_path)
                original_object_id = metadata['original_object_id']
                for key in metadata.keys():
                    self.dl_jobject.metadata[key] = metadata[key]

                self.dl_jobject.metadata['preview'] = dbus.ByteArray(
                    preview_data)

                self.dl_jobject.file_path = file_path

                datastore.write(self.dl_jobject,
                                transfer_ownership=True,
                                reply_handler=self.__internal_save_cb,
                                error_handler=self.__internal_error_cb,
                                timeout=360)

                # notify to the server, the object was successfully downloaded
                url = 'ws://%s:%d/websocket' % (self._activity.ip,
                                                self._activity.port)
                messanger = utils.Messanger(url)
                data = utils.get_user_data()
                data['object_id'] = original_object_id
                messanger.send_message('DOWNLOADED', data)

            else:
                self.dl_jobject.metadata['title'] = \
                    self._download.get_suggested_filename()
                self.dl_jobject.metadata['description'] = _('From: %s') \
                    % self._source
                self.dl_jobject.metadata['progress'] = '100'
                self.dl_jobject.file_path = self._dest_path

                # sniff for a mime type, no way to get headers from WebKit
                sniffed_mime_type = mime.get_for_file(self._dest_path)
                self.dl_jobject.metadata['mime_type'] = sniffed_mime_type

                datastore.write(self.dl_jobject,
                                transfer_ownership=True,
                                reply_handler=self.__internal_save_cb,
                                error_handler=self.__internal_error_cb,
                                timeout=360)

        elif state == WebKit.DownloadStatus.CANCELLED:
            self.cleanup()

    def __error_cb(self, download, err_code, err_detail, reason):
        logging.debug('Error downloading URI code %s, detail %s: %s' %
                      (err_code, err_detail, reason))

    def __internal_save_cb(self):
        logging.debug('Object saved succesfully to the datastore.')
        self.cleanup()

    def __internal_error_cb(self, err):
        logging.debug('Error saving activity object to datastore: %s' % err)
        self.cleanup()

    def __start_response_cb(self, alert, response_id):
        global _active_downloads
        if response_id is Gtk.ResponseType.CANCEL:
            logging.debug('Download Canceled')
            self.cancel()
            try:
                datastore.delete(self._object_id)
            except Exception, e:
                logging.warning('Object has been deleted already %s' % e)

            self.cleanup()
            if self._stop_alert is not None:
                self._activity.remove_alert(self._stop_alert)

        self._activity.remove_alert(alert)
Example #45
0
    def __download_finished_cb(self, download):
        if hasattr(self._activity, 'busy'):
            self._activity.unbusy()

        if self._progress_sid is not None:
            GObject.source_remove(self._progress_sid)

        if self.dl_jobject is None:
            return  # the "failed" signal was observed

        self.dl_jobject.metadata['title'] = self._suggested_filename
        self.dl_jobject.metadata['description'] = _('From: %s') \
            % self._source
        self.dl_jobject.metadata['progress'] = '100'
        self.dl_jobject.file_path = self._dest_path

        mime_type = Gio.content_type_guess(self._dest_path)[0]
        if mime_type != 'application/vnd.olpc-sugar':
            mime_type = download.get_response().get_mime_type()

        self.dl_jobject.metadata['mime_type'] = mime_type

        if mime_type in ('image/bmp', 'image/gif', 'image/jpeg', 'image/png',
                         'image/tiff'):
            preview = self._get_preview()
            if preview is not None:
                self.dl_jobject.metadata['preview'] = \
                    dbus.ByteArray(preview)

        datastore.write(self.dl_jobject,
                        transfer_ownership=True,
                        reply_handler=self.__internal_save_cb,
                        error_handler=self.__internal_error_cb,
                        timeout=360)

        if self._start_alert is not None:
            self._activity.remove_alert(self._start_alert)
        self._stop_alert = Alert()
        self._stop_alert.props.title = _('Downloaded')
        self._stop_alert.props.msg = self._suggested_filename

        bundle = None
        if _HAS_BUNDLE_LAUNCHER:
            bundle = get_bundle(object_id=self._object_id)

        if bundle is not None:
            icon = Icon(file=bundle.get_icon())
            label = _('Open with %s') % bundle.get_name()
            response_id = Gtk.ResponseType.APPLY
        else:
            icon = Icon(icon_name='zoom-activity')
            label = _('Show in Journal')
            response_id = Gtk.ResponseType.ACCEPT

        self._stop_alert.add_button(response_id, label, icon)
        icon.show()

        ok_icon = Icon(icon_name='dialog-ok')
        self._stop_alert.add_button(Gtk.ResponseType.OK, _('Ok'), ok_icon)
        ok_icon.show()

        self._activity.add_alert(self._stop_alert)
        self._stop_alert.connect('response', self.__stop_response_cb)
        self._stop_alert.show()
Example #46
0
class Network(SectionView):
    def __init__(self, model, alerts):
        SectionView.__init__(self)

        self._model = model
        self.restart_alerts = alerts
        self._jabber_sid = 0
        self._radio_valid = True
        self._jabber_change_handler = None
        self._radio_change_handler = None
        self._wireless_configuration_reset_handler = None
        self._start_jabber = self._model.get_jabber()
        self._proxy_settings = {}
        self._proxy_inline_alerts = {}

        self.set_border_width(style.DEFAULT_SPACING * 2)
        self.set_spacing(style.DEFAULT_SPACING)
        group = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL)

        self._radio_alert_box = Gtk.HBox(spacing=style.DEFAULT_SPACING)

        scrolled = Gtk.ScrolledWindow()
        scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        self.add(scrolled)
        scrolled.show()

        workspace = Gtk.VBox()
        scrolled.add_with_viewport(workspace)
        workspace.show()

        separator_wireless = Gtk.HSeparator()
        workspace.pack_start(separator_wireless, False, True, 0)
        separator_wireless.show()

        label_wireless = Gtk.Label(label=_('Wireless'))
        label_wireless.set_alignment(0, 0)
        workspace.pack_start(label_wireless, False, True, 0)
        label_wireless.show()
        box_wireless = Gtk.VBox()
        box_wireless.set_border_width(style.DEFAULT_SPACING * 2)
        box_wireless.set_spacing(style.DEFAULT_SPACING)

        radio_info = Gtk.Label(label=_('The wireless radio may be turned'
                                       ' off to save battery life.'))
        radio_info.set_alignment(0, 0)
        radio_info.set_line_wrap(True)
        radio_info.show()
        box_wireless.pack_start(radio_info, False, True, 0)

        box_radio = Gtk.HBox(spacing=style.DEFAULT_SPACING)
        self._button = Gtk.CheckButton()
        self._button.set_alignment(0, 0)
        box_radio.pack_start(self._button, False, True, 0)
        self._button.show()

        label_radio = Gtk.Label(label=_('Radio'))
        label_radio.set_alignment(0, 0.5)
        box_radio.pack_start(label_radio, False, True, 0)
        label_radio.show()

        box_wireless.pack_start(box_radio, False, True, 0)
        box_radio.show()

        self._radio_alert = InlineAlert()
        self._radio_alert_box.pack_start(self._radio_alert, False, True, 0)
        box_radio.pack_end(self._radio_alert_box, False, True, 0)
        self._radio_alert_box.show()
        if 'radio' in self.restart_alerts:
            self._radio_alert.props.msg = self.restart_msg
            self._radio_alert.show()

        wireless_info = Gtk.Label(
            label=_('Discard wireless connections if'
                    ' you have trouble connecting to the network'))
        wireless_info.set_alignment(0, 0)
        wireless_info.set_line_wrap(True)
        wireless_info.show()
        box_wireless.pack_start(wireless_info, False, True, 0)

        box_clear_wireless = Gtk.HBox(spacing=style.DEFAULT_SPACING)
        self._clear_wireless_button = Gtk.Button()
        self._clear_wireless_button.set_label(
            _('Discard wireless connections'))
        box_clear_wireless.pack_start(
            self._clear_wireless_button, False, True, 0)
        if not self._model.have_wireless_networks():
            self._clear_wireless_button.set_sensitive(False)
        self._clear_wireless_button.show()
        box_wireless.pack_start(box_clear_wireless, False, True, 0)
        box_clear_wireless.show()

        workspace.pack_start(box_wireless, False, True, 0)
        box_wireless.show()

        separator_mesh = Gtk.HSeparator()
        workspace.pack_start(separator_mesh, False, False, 0)
        separator_mesh.show()

        label_mesh = Gtk.Label(label=_('Collaboration'))
        label_mesh.set_alignment(0, 0)
        workspace.pack_start(label_mesh, False, True, 0)
        label_mesh.show()
        box_mesh = Gtk.VBox()
        box_mesh.set_border_width(style.DEFAULT_SPACING * 2)
        box_mesh.set_spacing(style.DEFAULT_SPACING)

        server_info = Gtk.Label(_("The server is the equivalent of what"
                                  " room you are in; people on the same server"
                                  " will be able to see each other, even when"
                                  " they aren't on the same network."))
        server_info.set_alignment(0, 0)
        server_info.set_line_wrap(True)
        box_mesh.pack_start(server_info, False, True, 0)
        server_info.show()

        box_server = Gtk.HBox(spacing=style.DEFAULT_SPACING)
        label_server = Gtk.Label(label=_('Server:'))
        label_server.set_alignment(1, 0.5)
        label_server.modify_fg(Gtk.StateType.NORMAL,
                               style.COLOR_SELECTION_GREY.get_gdk_color())
        box_server.pack_start(label_server, False, True, 0)
        group.add_widget(label_server)
        label_server.show()
        self._entry = Gtk.Entry()
        self._entry.set_alignment(0)
        self._entry.set_size_request(int(Gdk.Screen.width() / 3), -1)
        box_server.pack_start(self._entry, False, True, 0)
        self._entry.show()
        box_mesh.pack_start(box_server, False, True, 0)
        box_server.show()

        social_help_info = Gtk.Label(
            _('Social Help is a forum that lets you connect with developers'
              ' and discuss Sugar Activities.  Changing servers means'
              ' discussions will happen in a different place with'
              ' different people.'))
        social_help_info.set_alignment(0, 0)
        social_help_info.set_line_wrap(True)
        box_mesh.pack_start(social_help_info, False, True, 0)
        social_help_info.show()

        social_help_box = Gtk.HBox(spacing=style.DEFAULT_SPACING)
        social_help_label = Gtk.Label(label=_('Social Help Server:'))
        social_help_label.set_alignment(1, 0.5)
        social_help_label.modify_fg(Gtk.StateType.NORMAL,
                                    style.COLOR_SELECTION_GREY.get_gdk_color())
        social_help_box.pack_start(social_help_label, False, True, 0)
        group.add_widget(social_help_label)
        social_help_label.show()

        self._social_help_entry = Gtk.Entry()
        self._social_help_entry.set_alignment(0)
        self._social_help_entry.set_size_request(
            int(Gdk.Screen.width() / 3), -1)
        social_help_box.pack_start(self._social_help_entry, False, True, 0)
        self._social_help_entry.show()
        box_mesh.pack_start(social_help_box, False, True, 0)
        social_help_box.show()

        workspace.pack_start(box_mesh, False, True, 0)
        box_mesh.show()

        separator_proxy = Gtk.HSeparator()
        workspace.pack_start(separator_proxy, False, False, 0)
        separator_proxy.show()

        self._add_proxy_section(workspace)

        self.setup()

    def _add_proxy_section(self, workspace):
        label_proxy = Gtk.Label(_('Proxy'))
        label_proxy.set_alignment(0, 0)
        workspace.pack_start(label_proxy, False, True, 0)
        label_proxy.show()

        box_proxy = Gtk.VBox()
        box_proxy.set_border_width(style.DEFAULT_SPACING * 2)
        box_proxy.set_spacing(style.DEFAULT_SPACING)
        workspace.pack_start(box_proxy, False, True, 0)
        box_proxy.show()

        self._proxy_alert = Alert()
        self._proxy_alert.props.title = _('Error')
        self._proxy_alert.props.msg = _('Proxy settings cannot be verified')
        box_proxy.pack_start(self._proxy_alert, False, False, 0)
        self._proxy_alert.connect('response', self._response_cb)
        self._proxy_alert.hide()

        # GSettings schemas for proxy:
        schemas = ['org.sugarlabs.system.proxy',
                   'org.sugarlabs.system.proxy.http',
                   'org.sugarlabs.system.proxy.https',
                   'org.sugarlabs.system.proxy.ftp',
                   'org.sugarlabs.system.proxy.socks']

        for schema in schemas:
            proxy_setting = Gio.Settings.new(schema)

            # We are not going to apply the settings immediatly.
            # We'll apply them if the user presses the "accept"
            # button, or we'll revert them if the user presses the
            # "cancel" button.
            proxy_setting.delay()
            alert = InlineAlert()

            self._proxy_settings[schema] = proxy_setting
            self._proxy_inline_alerts[schema] = alert

        size_group = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL)

        automatic_proxy_box = Gtk.VBox(spacing=style.DEFAULT_SPACING)
        manual_proxy_box = Gtk.VBox(spacing=style.DEFAULT_SPACING)

        option_sets = [('None', 'none', Gtk.VBox()),
                       ('Use system proxy', 'system', Gtk.VBox()),
                       ('Manual', 'manual', manual_proxy_box),
                       ('Automatic', 'auto', automatic_proxy_box)]

        box_mode = ComboSettingBox(
            _('Method:'), self._proxy_settings['org.sugarlabs.system.proxy'],
            'mode', option_sets, size_group)

        box_proxy.pack_start(box_mode, False, False, 0)
        box_mode.show()

        url_box = StringSettingBox(
            _('Configuration URL:'),
            self._proxy_settings['org.sugarlabs.system.proxy'],
            'autoconfig-url',
            size_group)

        automatic_proxy_box.pack_start(url_box, True, True, 0)
        url_box.show()

        wpad_help_text = _('Web Proxy Autodiscovery is used when a'
                           ' Configuration URL is not provided. This is not'
                           ' recommended for untrusted public networks.')
        automatic_proxy_help = Gtk.Label(wpad_help_text)
        automatic_proxy_help.set_alignment(0, 0)
        automatic_proxy_help.set_line_wrap(True)
        automatic_proxy_help.show()
        automatic_proxy_box.pack_start(automatic_proxy_help, True, True, 0)

        # HTTP Section
        schema = 'org.sugarlabs.system.proxy.http'
        box_http = HostPortSettingBox(
            _('HTTP Proxy:'), self._proxy_inline_alerts[schema],
            self._proxy_settings[schema], size_group)
        manual_proxy_box.pack_start(box_http, False, False, 0)
        box_http.show()
        auth_contents_box = Gtk.VBox(spacing=style.DEFAULT_SPACING)
        auth_box = OptionalSettingsBox(
            _('Use authentication'),
            self._proxy_settings[schema],
            'use-authentication', auth_contents_box)
        manual_proxy_box.pack_start(auth_box, False, False, 0)
        auth_box.show()
        proxy_http_setting = Gio.Settings.new(schema)
        proxy_http_setting.delay()
        box_username = StringSettingBox(
            _('Username:'******'authentication-user', size_group)
        auth_contents_box.pack_start(box_username, False, False, 0)
        box_username.show()
        box_password = StringSettingBox(
            _('Password:'******'authentication-password', size_group, password_field=True)
        auth_contents_box.pack_start(box_password, False, False, 0)
        box_password.show()

        # HTTPS Section
        schema = 'org.sugarlabs.system.proxy.https'
        box_https = HostPortSettingBox(
            _('HTTPS Proxy:'), self._proxy_inline_alerts[schema],
            self._proxy_settings[schema],
            size_group)
        manual_proxy_box.pack_start(box_https, False, False, 0)
        box_https.show()

        # FTP Section
        schema = 'org.sugarlabs.system.proxy.ftp'
        box_ftp = HostPortSettingBox(
            _('FTP Proxy:'), self._proxy_inline_alerts[schema],
            self._proxy_settings[schema],
            size_group)
        manual_proxy_box.pack_start(box_ftp, False, False, 0)
        box_ftp.show()

        # SOCKS Section
        schema = 'org.sugarlabs.system.proxy.socks'
        box_socks = HostPortSettingBox(
            _('SOCKS Proxy:'), self._proxy_inline_alerts[schema],
            self._proxy_settings[schema],
            size_group)
        manual_proxy_box.pack_start(box_socks, False, False, 0)
        box_socks.show()

        box_ignore = StringSettingBox_with_convert(
            _('Ignore Hosts:'),
            self._proxy_settings['org.sugarlabs.system.proxy'], 'ignore-hosts',
            type_as_to_string, string_to_type_as, size_group)
        manual_proxy_box.pack_start(box_ignore, False, False, 0)
        box_ignore.show()

    def setup(self):
        self._entry.set_text(self._start_jabber)
        self._social_help_entry.set_text(self._model.get_social_help())

        try:
            radio_state = self._model.get_radio()
        except self._model.ReadError, detail:
            self._radio_alert.props.msg = detail
            self._radio_alert.show()
        else:
    def __state_change_cb(self, download, gparamspec):
        state = self._download.get_status()
        if state == WebKit.DownloadStatus.STARTED:
            # Check free space and cancel the download if there is not enough.
            total_size = self._download.get_total_size()
            logging.debug('Total size of the file: %s', total_size)
            enough_space = self.enough_space(total_size, path=self.temp_path)
            if not enough_space:
                logging.debug('Download canceled because of Disk Space')
                self.cancel()

                self._canceled_alert = Alert()
                self._canceled_alert.props.title = _('Not enough space '
                                                     'to download')

                total_size_mb = total_size / 1024.0**2
                free_space_mb = self._free_available_space(
                    path=self.temp_path) - SPACE_THRESHOLD / 1024.0**2
                filename = self._download.get_suggested_filename()
                self._canceled_alert.props.msg = \
                    _('Download "%{filename}" requires %{total_size_in_mb}'
                      ' MB of free space, only %{free_space_in_mb} MB'
                      ' is available' %
                      {'filename': filename,
                       'total_size_in_mb': format_float(total_size_mb),
                       'free_space_in_mb': format_float(free_space_mb)})
                ok_icon = Icon(icon_name='dialog-ok')
                self._canceled_alert.add_button(Gtk.ResponseType.OK, _('Ok'),
                                                ok_icon)
                ok_icon.show()
                self._canceled_alert.connect('response',
                                             self.__stop_response_cb)
                self._activity.add_alert(self._canceled_alert)
            else:
                self._download.connect('notify::progress',
                                       self.__progress_change_cb)
                self._create_journal_object()
                self._object_id = self.dl_jobject.object_id

                alert = TimeoutAlert(9)
                alert.props.title = _('Download started')
                alert.props.msg = _('%s' %
                                    self._download.get_suggested_filename())
                self._activity.add_alert(alert)
                alert.connect('response', self.__start_response_cb)
                alert.show()
                global _active_downloads
                _active_downloads.append(self)

        elif state == WebKit.DownloadStatus.FINISHED:
            self._stop_alert = Alert()
            self._stop_alert.props.title = _('Download completed')
            self._stop_alert.props.msg = \
                _('%s' % self._download.get_suggested_filename())
            open_icon = Icon(icon_name='zoom-activity')
            self._stop_alert.add_button(Gtk.ResponseType.APPLY,
                                        _('Show in Journal'), open_icon)
            open_icon.show()
            ok_icon = Icon(icon_name='dialog-ok')
            self._stop_alert.add_button(Gtk.ResponseType.OK, _('Ok'), ok_icon)
            ok_icon.show()
            self._activity.add_alert(self._stop_alert)
            self._stop_alert.connect('response', self.__stop_response_cb)
            self._stop_alert.show()

            if self._dest_path.endswith('.journal'):

                metadata, preview_data, file_path = \
                    utils.unpackage_ds_object(self._dest_path)
                original_object_id = metadata['original_object_id']
                for key in metadata.keys():
                    self.dl_jobject.metadata[key] = metadata[key]

                self.dl_jobject.metadata['preview'] = dbus.ByteArray(
                    preview_data)

                self.dl_jobject.file_path = file_path

                datastore.write(self.dl_jobject,
                                transfer_ownership=True,
                                reply_handler=self.__internal_save_cb,
                                error_handler=self.__internal_error_cb,
                                timeout=360)

                # notify to the server, the object was successfully downloaded
                url = 'ws://%s:%d/websocket' % (self._activity.ip,
                                                self._activity.port)
                messanger = utils.Messanger(url)
                data = utils.get_user_data()
                data['object_id'] = original_object_id
                messanger.send_message('DOWNLOADED', data)

            else:
                self.dl_jobject.metadata['title'] = \
                    self._download.get_suggested_filename()
                self.dl_jobject.metadata['description'] = _('From: %s') \
                    % self._source
                self.dl_jobject.metadata['progress'] = '100'
                self.dl_jobject.file_path = self._dest_path

                # sniff for a mime type, no way to get headers from WebKit
                sniffed_mime_type = mime.get_for_file(self._dest_path)
                self.dl_jobject.metadata['mime_type'] = sniffed_mime_type

                datastore.write(self.dl_jobject,
                                transfer_ownership=True,
                                reply_handler=self.__internal_save_cb,
                                error_handler=self.__internal_error_cb,
                                timeout=360)

        elif state == WebKit.DownloadStatus.CANCELLED:
            self.cleanup()
Example #48
0
    def __create_restart_alert_cb(self, widget=None, event=None):
        alert = Alert()
        alert.props.title = _('Warning')
        alert.props.msg = self._section_view.restart_msg

        if self._section_view.props.is_cancellable:
            icon = Icon(icon_name='dialog-cancel')
            alert.add_button(Gtk.ResponseType.CANCEL, _('Cancel changes'),
                             icon)
            icon.show()

        if self._section_view.props.is_deferrable:
            icon = Icon(icon_name='dialog-ok')
            alert.add_button(Gtk.ResponseType.ACCEPT, _('Later'), icon)
            icon.show()

        icon = Icon(icon_name='system-restart')
        alert.add_button(Gtk.ResponseType.APPLY, _('Restart now'), icon)
        icon.show()

        self.add_alert(alert)
        alert.connect('response', self.__response_cb)
        alert.show()
Example #49
0
    def __create_empty_file_cb(self, button):
        alert = Alert()
        alert.props.title = _('Create new file')
        alert.props.msg = _('Select the name of the file')

        # HACK
        alert._hbox.remove(alert._buttons_box)
        alert.entry = Gtk.Entry()
        alert._hbox.pack_start(alert.entry, True, True, 0)

        alert._buttons_box = Gtk.HButtonBox()
        alert._buttons_box.set_layout(Gtk.ButtonBoxStyle.END)
        alert._buttons_box.set_spacing(style.DEFAULT_SPACING)
        alert._hbox.pack_start(alert._buttons_box, True, True, 0)

        icon = Icon(icon_name='dialog-cancel')
        alert.add_button(Gtk.ResponseType.CANCEL, _('Cancel'), icon)

        icon = Icon(icon_name='dialog-ok')
        alert.add_button(Gtk.ResponseType.OK, _('Ok'), icon)
        alert.show_all()
        #

        self.add_alert(alert)
        alert.connect('response', self.__create_file_alert_cb)
Example #50
0
 def __register_activate_cb(self, icon):
     alert = Alert()
     alert.props.title = _('Registration')
     alert.props.msg = _('Please wait, searching for your school server.')
     self._box.add_alert(alert)
     GObject.idle_add(self.__register)
    def _restart_alert(self):
        alert = Alert()
        alert.props.title = _('Warning')
        alert.props.msg = _('Changes require restart')

        icon = Icon(icon_name='dialog-cancel')
        alert.add_button(Gtk.ResponseType.CANCEL, _('Cancel changes'), icon)
        icon.show()

        icon = Icon(icon_name='dialog-ok')
        alert.add_button(Gtk.ResponseType.ACCEPT, _('Later'), icon)
        icon.show()

        icon = Icon(icon_name='system-restart')
        alert.add_button(Gtk.ResponseType.APPLY, _('Restart now'), icon)
        icon.show()

        alert.connect('response', self.__response_cb)
        self.add_alert(alert)
        alert.show()
    def _show_journal_alert(self, title, msg):
        _stop_alert = Alert()
        _stop_alert.props.title = title
        _stop_alert.props.msg = msg

        if _HAS_BUNDLE_LAUNCHER:
            bundle = get_bundle(object_id=self._object_id)

        if bundle is not None:
            icon = Icon(file=bundle.get_icon())
            label = _('Open with %s') % bundle.get_name()
            _stop_alert.add_button(Gtk.ResponseType.ACCEPT, label, icon)
        else:
            icon = Icon(icon_name='zoom-activity')
            label = _('Show in Journal')
            _stop_alert.add_button(Gtk.ResponseType.APPLY, label, icon)
        icon.show()

        ok_icon = Icon(icon_name='dialog-ok')
        _stop_alert.add_button(Gtk.ResponseType.OK, _('Ok'), ok_icon)
        ok_icon.show()
        # Remove other alerts
        for alert in self._alerts:
            self.remove_alert(alert)

        self.add_alert(_stop_alert)
        _stop_alert.connect('response', self.__stop_response_cb)
        _stop_alert.show()
class Download(object):
    def __init__(self, download, browser):
        self._download = download
        self._activity = browser.get_toplevel()
        self._source = download.get_uri()

        self._download.connect('notify::status', self.__state_change_cb)
        self._download.connect('error', self.__error_cb)

        self.datastore_deleted_handler = None

        self.dl_jobject = None
        self._object_id = None
        self._stop_alert = None

        self._progress = 0
        self._last_update_progress = 0
        self._progress_sid = None

        # figure out download URI
        self.temp_path = os.path.join(activity.get_activity_root(), 'instance')
        if not os.path.exists(self.temp_path):
            os.makedirs(self.temp_path)

        fd, self._dest_path = tempfile.mkstemp(
            dir=self.temp_path,
            suffix=download.get_suggested_filename(),
            prefix='tmp')
        os.close(fd)
        logging.debug('Download destination path: %s' % self._dest_path)

        # We have to start the download to get 'total-size'
        # property. It not, 0 is returned
        self._download.set_destination_uri('file://' + self._dest_path)
        self._download.start()

    def _update_progress(self):
        if self._progress > self._last_update_progress:
            self._last_update_progress = self._progress
            self.dl_jobject.metadata['progress'] = str(self._progress)
            datastore.write(self.dl_jobject)

        self._progress_sid = None
        return False

    def __progress_change_cb(self, download, something):
        self._progress = int(self._download.get_progress() * 100)

        if self._progress_sid is None:
            self._progress_sid = GObject.timeout_add(PROGRESS_TIMEOUT,
                                                     self._update_progress)

    def __current_size_changed_cb(self, download, something):
        current_size = self._download.get_current_size()
        total_size = self._download.get_total_size()
        self._progress = int(current_size * 100 / total_size)

        if self._progress_sid is None:
            self._progress_sid = GObject.timeout_add(PROGRESS_TIMEOUT,
                                                     self._update_progress)

    def __state_change_cb(self, download, gparamspec):
        state = self._download.get_status()
        if state == WebKit.DownloadStatus.STARTED:
            # Check free space and cancel the download if there is not enough.
            total_size = self._download.get_total_size()
            logging.debug('Total size of the file: %s', total_size)
            enough_space = self.enough_space(total_size, path=self.temp_path)
            if not enough_space:
                logging.debug('Download canceled because of Disk Space')
                self.cancel()

                self._canceled_alert = Alert()
                self._canceled_alert.props.title = _('Not enough space '
                                                     'to download')

                total_size_mb = total_size / 1024.0**2
                free_space_mb = (self._free_available_space(
                    path=self.temp_path) - SPACE_THRESHOLD) \
                    / 1024.0 ** 2
                filename = self._download.get_suggested_filename()
                self._canceled_alert.props.msg = \
                    _('Download "%{filename}" requires %{total_size_in_mb}'
                      ' MB of free space, only %{free_space_in_mb} MB'
                      ' is available' %
                      {'filename': filename,
                       'total_size_in_mb': format_float(total_size_mb),
                       'free_space_in_mb': format_float(free_space_mb)})
                ok_icon = Icon(icon_name='dialog-ok')
                self._canceled_alert.add_button(Gtk.ResponseType.OK, _('Ok'),
                                                ok_icon)
                ok_icon.show()
                self._canceled_alert.connect('response',
                                             self.__stop_response_cb)
                self._activity.add_alert(self._canceled_alert)
            else:
                # FIXME: workaround for SL #4385
                # self._download.connect('notify::progress',
                #                        self.__progress_change_cb)
                self._download.connect('notify::current-size',
                                       self.__current_size_changed_cb)

                self._create_journal_object()
                self._object_id = self.dl_jobject.object_id

                alert = TimeoutAlert(9)
                alert.props.title = _('Download started')
                alert.props.msg = _('%s' %
                                    self._download.get_suggested_filename())
                self._activity.add_alert(alert)
                alert.connect('response', self.__start_response_cb)
                alert.show()
                global _active_downloads
                _active_downloads.append(self)

        elif state == WebKit.DownloadStatus.FINISHED:
            self._stop_alert = Alert()
            self._stop_alert.props.title = _('Download completed')
            self._stop_alert.props.msg = \
                _('%s' % self._download.get_suggested_filename())

            if self._progress_sid is not None:
                GObject.source_remove(self._progress_sid)

            self.dl_jobject.metadata['title'] = \
                self._download.get_suggested_filename()
            self.dl_jobject.metadata['description'] = _('From: %s') \
                % self._source
            self.dl_jobject.metadata['progress'] = '100'
            self.dl_jobject.file_path = self._dest_path

            # sniff for a mime type, no way to get headers from WebKit
            sniffed_mime_type = mime.get_for_file(self._dest_path)
            self.dl_jobject.metadata['mime_type'] = sniffed_mime_type

            if sniffed_mime_type in ('image/bmp', 'image/gif', 'image/jpeg',
                                     'image/png', 'image/tiff'):
                preview = self._get_preview()
                if preview is not None:
                    self.dl_jobject.metadata['preview'] = \
                        dbus.ByteArray(preview)

            datastore.write(self.dl_jobject,
                            transfer_ownership=True,
                            reply_handler=self.__internal_save_cb,
                            error_handler=self.__internal_error_cb,
                            timeout=360)

            bundle = None
            if _HAS_BUNDLE_LAUNCHER:
                bundle = get_bundle(object_id=self._object_id)

            if bundle is not None:
                icon = Icon(file=bundle.get_icon())
                label = _('Open with %s') % bundle.get_name()
                response_type = Gtk.ResponseType.APPLY
            else:
                icon = Icon(icon_name='zoom-activity')
                label = _('Show in Journal')
                response_type = Gtk.ResponseType.ACCEPT

            self._stop_alert.add_button(response_type, label, icon)
            icon.show()

            ok_icon = Icon(icon_name='dialog-ok')
            self._stop_alert.add_button(Gtk.ResponseType.OK, _('Ok'), ok_icon)
            ok_icon.show()

            self._activity.add_alert(self._stop_alert)
            self._stop_alert.connect('response', self.__stop_response_cb)
            self._stop_alert.show()

        elif state == WebKit.DownloadStatus.CANCELLED:
            self.cleanup()

    def __error_cb(self, download, err_code, err_detail, reason):
        logging.debug('Error downloading URI code %s, detail %s: %s' %
                      (err_code, err_detail, reason))

    def __internal_save_cb(self):
        logging.debug('Object saved succesfully to the datastore.')
        self.cleanup()

    def __internal_error_cb(self, err):
        logging.debug('Error saving activity object to datastore: %s' % err)
        self.cleanup()

    def __start_response_cb(self, alert, response_id):
        global _active_downloads
        if response_id is Gtk.ResponseType.CANCEL:
            logging.debug('Download Canceled')
            self.cancel()
            try:
                datastore.delete(self._object_id)
            except Exception, e:
                logging.warning('Object has been deleted already %s' % e)

            self.cleanup()
            if self._stop_alert is not None:
                self._activity.remove_alert(self._stop_alert)

        self._activity.remove_alert(alert)
Example #54
0
class DevTutorActivity(activity.Activity):
    """DevTutorActivity class as specified in activity.info"""
    def __init__(self, handle):
        activity.Activity.__init__(self, handle)

        self.max_participants = 10

        # toolbar with the new toolbar redesign
        toolbar_box = ToolbarBox()

        activity_button = ActivityToolbarButton(self)
        toolbar_box.toolbar.insert(activity_button, 0)
        activity_button.show()

        self.back_button = BackButton()
        self.back_button.connect('clicked', self.show_options1)
        toolbar_box.toolbar.insert(self.back_button, -1)
        self.back_button.show()

        separator = Gtk.SeparatorToolItem()
        separator.props.draw = False
        separator.set_expand(True)
        toolbar_box.toolbar.insert(separator, -1)
        separator.show()

        stop_button = StopButton(self)
        toolbar_box.toolbar.insert(stop_button, -1)
        stop_button.show()

        self.set_toolbar_box(toolbar_box)
        toolbar_box.show()

        self.show_options()

        self._logger = logging.getLogger('hellomesh-activity')

        self.hellotube = None  # Shared session
        self.initiating = False

        # get the Presence Service
        self.pservice = presenceservice.get_instance()
        # Buddy object for you
        owner = self.pservice.get_owner()
        self.owner = owner

        self.connect('shared', self._shared_cb)
        self.connect('joined', self._joined_cb)

    def show_options1(self, data=None):
        self.show_options()

    def show_options(self):
        self.main_container = Gtk.VBox()

        self.add_padding()
        self.line1 = Gtk.HBox()

        button1 = Gtk.Button("Show modules")
        #button1.set_size_request(200,80)
        #self.line1.pack_start(button1, False, False, 0)
        self.line1.add(button1)
        button1.connect('clicked', self.show_modules, None)
        button1.get_child().modify_font(Pango.FontDescription("Sans 14"))
        button1.show()

        self.main_container.add(self.line1)
        self.line1.show()

        self.add_padding()

        self.line2 = Gtk.HBox()
        button2 = Gtk.Button("Show activities")
        #button2.set_size_request(200,80)
        #self.line2.pack_start(button2, False, False, 0)
        self.line2.add(button2)
        button2.connect('clicked', self.show_activity_list, None)
        button2.get_child().modify_font(Pango.FontDescription("Sans 14"))
        button2.show()

        self.main_container.add(self.line2)
        self.line2.show()
        self.add_padding()

        self.line3 = Gtk.HBox()
        text = Gtk.TextView()
        self.entry = Gtk.Entry()
        self.entry.set_sensitive(True)
        self.entry.connect('activate', self.entry_activate_cb)

        self.entry.show()
        self.line3.add(self.entry)
        self.main_container.add(self.line3)
        self.line3.show()

        self.set_canvas(self.main_container)

        self.main_container.show()

    def add_padding(self):
        self.line_space1 = Gtk.HBox()
        self.main_container.add(self.line_space1)
        self.line_space1.show()

        self.line_space2 = Gtk.HBox()
        self.main_container.add(self.line_space2)
        self.line_space2.show()

    def show_modules(self, sender, data=None):
        self.mod = ShowModules(self.set_canvas)
        self.mod.show_modules()

    def show_activity_list(self, sender, data=None):
        self.back_button.connect('clicked', self.show_options1)
        self.main_container = Gtk.VBox()

        self.add_padding()
        self.line1 = Gtk.HBox()

        button1 = Gtk.Button("Hello World activity")
        #button1.set_size_request(200,80)
        #self.line1.pack_start(button1, False, False, 0)
        self.line1.add(button1)
        button1.connect('clicked', self.show_labels_hello, None)
        button1.get_child().modify_font(Pango.FontDescription("Sans 14"))
        button1.show()

        self.main_container.add(self.line1)
        self.line1.show()

        self.add_padding()
        self.line2 = Gtk.HBox()

        button2 = Gtk.Button("Write activity")
        #button2.set_size_request(200,80)
        #self.line2.pack_start(button2, False, False, 0)
        self.line2.add(button2)
        button2.connect('clicked', self.show_labels_write, None)
        button2.get_child().modify_font(Pango.FontDescription("Sans 14"))
        button2.show()

        self.main_container.add(self.line2)
        self.line2.show()
        self.add_padding()

        self.set_canvas(self.main_container)
        self.main_container.show()

    def show_labels_hello(self, sender, data=None):
        self.back_button.connect('clicked', self.show_activity_list)
        self.main_container = Gtk.VBox()

        self.add_padding()
        self.line1 = Gtk.HBox()

        self.label1 = Gtk.Label(
            _("Hello World activity step 1 - call activity.__init__"))
        self.label1.set_line_wrap(True)
        self.label1.modify_font(Pango.FontDescription("Sans 12"))
        self.line1.add(self.label1)
        self.label1.show()

        button1 = Gtk.Button("Show result")
        button1.set_size_request(200, 80)
        self.line1.pack_start(button1, False, False, 0)
        button1.connect('clicked', self.hello_launch1, None)
        button1.get_child().modify_font(Pango.FontDescription("Sans 14"))
        button1.show()

        self.main_container.add(self.line1)
        self.line1.show()

        self.add_padding()
        self.line2 = Gtk.HBox()

        self.label2 = Gtk.Label(_("Hello Word activity step 2 - add toolbox"))
        self.label2.set_line_wrap(True)
        self.label2.modify_font(Pango.FontDescription("Sans 12"))
        self.line2.add(self.label2)
        self.label2.show()

        button2 = Gtk.Button("Show result")
        button2.set_size_request(200, 80)
        self.line2.pack_start(button2, False, False, 0)
        button2.connect('clicked', self.hello_launch2, None)
        button2.get_child().modify_font(Pango.FontDescription("Sans 14"))
        button2.show()

        self.main_container.add(self.line2)
        self.line2.show()

        self.add_padding()
        self.line3 = Gtk.HBox()

        self.label3 = Gtk.Label(
            _("Hello World activity step 3 - add hello world label"))
        self.label3.set_line_wrap(True)
        self.label3.modify_font(Pango.FontDescription("Sans 12"))
        self.line3.add(self.label3)
        self.label3.show()

        button3 = Gtk.Button("Show result")
        button3.set_size_request(200, 80)
        self.line3.pack_start(button3, False, False, 0)
        button3.connect('clicked', self.hello_launch3, None)
        button3.get_child().modify_font(Pango.FontDescription("Sans 14"))
        button3.show()

        self.main_container.add(self.line3)
        self.line3.show()

        self.add_padding()
        self.line4 = Gtk.HBox()

        self.label4 = Gtk.Label(
            _("Hello World activity step 4 - add rotate button"))
        self.label4.set_line_wrap(True)
        self.label4.modify_font(Pango.FontDescription("Sans 12"))
        self.line4.add(self.label4)
        self.label4.show()

        button4 = Gtk.Button("Show result")
        button4.set_size_request(200, 80)
        self.line4.pack_start(button4, False, False, 0)
        button4.connect('clicked', self.hello_launch4, None)
        button4.get_child().modify_font(Pango.FontDescription("Sans 14"))
        button4.show()

        self.main_container.add(self.line4)
        self.line4.show()

        self.add_padding()
        self.set_canvas(self.main_container)
        self.main_container.show()

    def show_labels_write(self, sender, data=None):
        self.back_button.connect('clicked', self.show_activity_list)
        self.main_container = Gtk.VBox()
        self.add_padding()
        self.line1 = Gtk.HBox()

        self.label1 = Gtk.Label(_("Write activity step 1 "))
        self.label1.set_line_wrap(True)
        self.label1.modify_font(Pango.FontDescription("Sans 12"))
        self.line1.add(self.label1)
        self.label1.show()

        button1 = Gtk.Button("Show result")
        button1.set_size_request(200, 80)
        self.line1.pack_start(button1, False, False, 0)
        button1.connect('clicked', self.write_launch1, None)
        button1.get_child().modify_font(Pango.FontDescription("Sans 14"))
        button1.show()

        self.main_container.add(self.line1)
        self.line1.show()
        self.add_padding()
        self.line2 = Gtk.HBox()

        self.label2 = Gtk.Label(_("Write activity step 2"))
        self.label2.set_line_wrap(True)
        self.label2.modify_font(Pango.FontDescription("Sans 12"))
        self.line2.add(self.label2)
        self.label2.show()

        button2 = Gtk.Button("Show result")
        button2.set_size_request(200, 80)
        self.line2.pack_start(button2, False, False, 0)
        button2.connect('clicked', self.write_launch2, None)
        button2.get_child().modify_font(Pango.FontDescription("Sans 14"))
        button2.show()

        self.main_container.add(self.line2)
        self.line2.show()

        self.set_canvas(self.main_container)
        self.add_padding()
        self.line3 = Gtk.HBox()

        self.label3 = Gtk.Label(_("Write activity step 3"))
        self.label3.set_line_wrap(True)
        self.label3.modify_font(Pango.FontDescription("Sans 12"))
        self.line3.add(self.label3)
        self.label3.show()

        button3 = Gtk.Button("Show result")
        button3.set_size_request(200, 80)
        self.line3.pack_start(button3, False, False, 0)
        button3.connect('clicked', self.write_launch3, None)
        button3.get_child().modify_font(Pango.FontDescription("Sans 14"))
        button3.show()

        self.main_container.add(self.line3)
        self.line3.show()
        self.add_padding()
        self.set_canvas(self.main_container)
        self.main_container.show()

    def hello_launch1(self, sender, data=None):
        f = open('/tmp/1', 'w')
        os.putenv('TUTOR_CLASS', 'HelloWorldActivity')
        self.launch()

    def hello_launch2(self, sender, data=None):
        f = open('/tmp/2', 'w')
        self.hello_launch1(sender, data)

    def hello_launch3(self, sender, data=None):
        f = open('/tmp/3', 'w')
        self.hello_launch2(sender, data)

    def hello_launch4(self, sender, data=None):
        f = open('/tmp/4', 'w')
        self.hello_launch3(sender, data)

    def write_launch1(self, sender, data=None):
        f = open('/tmp/1', 'w')
        os.putenv('TUTOR_CLASS', 'AbiWordActivity')
        self.launch()

    def write_launch2(self, sender, data=None):
        f = open('/tmp/2', 'w')
        self.write_launch1(sender, data)

    def write_launch3(self, sender, data=None):
        f = open('/tmp/3', 'w')
        self.write_launch2(sender, data)

    def launch(self):
        subprocess.Popen(['sugar-launch', 'org.sugarlabs.DevTutor'])

    def entry_activate_cb(self, entry):
        """Handle the event when Enter is pressed in the Entry."""
        text = entry.props.text
        if self.hellotube is not None:
            self.hellotube.SendText(text)

    def entry_text_update_cb(self, text):
        """Update Entry text when text received from others."""
        self.entry.props.text = text

    def _alert(self, title, text=None):
        try:
            self.remove_alert(self.alert)

        finally:
            self.alert = Alert()
            self.alert.props.title = title
            self.alert.props.msg = text
            self.add_alert(self.alert)
            self.alert.connect('response', self._alert_cancel_cb)
            self.alert.show()

    def _alert_cancel_cb(self, alert, response_id):
        #self.remove_alert(alert)
        pass

    def _shared_cb(self, activity):
        self._logger.debug('My activity was shared')
        self.alert = Alert()
        self.alert.props.title = 'Shared Activity'
        self.alert.props.msg = 'Shared messages to be displayed here'
        self.add_alert(self.alert)
        self.initiating = True
        self._sharing_setup()

        self._logger.debug('This is my activity: making a tube...')
        id = self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube(
            SERVICE, {})

    def _sharing_setup(self):
        if self.shared_activity is None:
            self._logger.error('Failed to share or join activity')
            return

        self.conn = self.shared_activity.telepathy_conn
        self.tubes_chan = self.shared_activity.telepathy_tubes_chan
        self.text_chan = self.shared_activity.telepathy_text_chan

        self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal(
            'NewTube', self._new_tube_cb)

        self.shared_activity.connect('buddy-joined', self._buddy_joined_cb)
        self.shared_activity.connect('buddy-left', self._buddy_left_cb)

        self.entry.set_sensitive(True)
        self.entry.grab_focus()

        # Optional - included for example:
        # Find out who's already in the shared activity:
        for buddy in self.shared_activity.get_joined_buddies():
            self._logger.debug('Buddy %s is already in the activity',
                               buddy.props.nick)

    def _list_tubes_reply_cb(self, tubes):
        for tube_info in tubes:
            self._new_tube_cb(*tube_info)

    def _list_tubes_error_cb(self, e):
        self._logger.error('ListTubes() failed: %s', e)

    def _joined_cb(self, activity):
        if not self.shared_activity:
            return

        self._logger.debug('Joined an existing shared activity')
        self._alert('Joined', 'Joined a shared activity')
        self.initiating = False
        self._sharing_setup()

        self._logger.debug('This is not my activity: waiting for a tube...')
        self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes(
            reply_handler=self._list_tubes_reply_cb,
            error_handler=self._list_tubes_error_cb)

    def _new_tube_cb(self, id, initiator, type, service, params, state):
        self._logger.debug(
            'New tube: ID=%d initator=%d type=%d service=%s '
            'params=%r state=%d', id, initiator, type, service, params, state)
        if (type == telepathy.TUBE_TYPE_DBUS and service == SERVICE):
            if state == telepathy.TUBE_STATE_LOCAL_PENDING:
                self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].AcceptDBusTube(
                    id)
            tube_conn = TubeConnection(
                self.conn,
                self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES],
                id,
                group_iface=self.text_chan[telepathy.CHANNEL_INTERFACE_GROUP])
            self.hellotube = TextSync(tube_conn, self.initiating,
                                      self.entry_text_update_cb, self._alert,
                                      self._get_buddy)

    def _buddy_joined_cb(self, activity, buddy):
        """Called when a buddy joins the shared activity.

        This doesn't do much here as HelloMesh doesn't have much 
        functionality. It's up to you do do interesting things
        with the Buddy...
        """
        self._logger.debug('Buddy %s joined', buddy.props.nick)
        self._alert('Buddy joined', '%s joined' % buddy.props.nick)

    def _buddy_left_cb(self, activity, buddy):
        """Called when a buddy leaves the shared activity.

        This doesn't do much here as HelloMesh doesn't have much 
        functionality. It's up to you do do interesting things
        with the Buddy...
        """
        self._logger.debug('Buddy %s left', buddy.props.nick)
        self._alert('Buddy left', '%s left' % buddy.props.nick)

    def _get_buddy(self, cs_handle):
        """Get a Buddy from a channel specific handle."""
        self._logger.debug('Trying to find owner of handle %u...', cs_handle)
        group = self.text_chan[telepathy.CHANNEL_INTERFACE_GROUP]
        my_csh = group.GetSelfHandle()
        self._logger.debug('My handle in that group is %u', my_csh)
        if my_csh == cs_handle:
            handle = self.conn.GetSelfHandle()
            self._logger.debug('CS handle %u belongs to me, %u', cs_handle,
                               handle)

        elif group.GetGroupFlags(
        ) & telepathy.CHANNEL_GROUP_FLAG_CHANNEL_SPECIFIC_HANDLES:
            handle = group.GetHandleOwners([cs_handle])[0]
            self._logger.debug('CS handle %u belongs to %u', cs_handle, handle)

        else:
            handle = cs_handle
            self._logger.debug('non-CS handle %u belongs to itself', handle)
            # XXX: deal with failure to get the handle owner
            assert handle != 0

        return self.pservice.get_buddy_by_telepathy_handle(
            self.conn.service_name, self.conn.object_path, handle)
Example #55
0
class Download(object):
    def __init__(self, webkit_download, activity):
        self._download = webkit_download
        self._activity = activity

        self._source = self._download.get_request().get_uri()
        logging.debug('START Download %s', self._source)

        self.datastore_deleted_handler = None

        self.dl_jobject = None
        self._object_id = None
        self._start_alert = None
        self._stop_alert = None

        self._dest_path = ''
        self._progress = 0
        self._last_update_progress = 0
        self._progress_sid = None

        self.temp_path = os.path.join(self._activity.get_activity_root(),
                                      'instance')
        if not os.path.exists(self.temp_path):
            os.makedirs(self.temp_path)

        self._download.connect('failed', self.__download_failed_cb)
        self._download.connect('finished', self.__download_finished_cb)
        self._download.connect('received-data',
                               self.__download_received_data_cb)

        # Notify response is called before decide destination
        self._download.connect('notify::response', self.__notify_response_cb)
        self._download.connect('decide-destination',
                               self.__decide_destination_cb)
        self._download.connect('created-destination',
                               self.__created_destination_cb)

    def __notify_response_cb(self, download, pspec):
        logging.debug('__notify_response_cb')
        response = download.get_response()

        # Check free space and cancel the download if there is not enough.
        total_size = response.get_content_length()
        logging.debug('Total size of the file: %s', total_size)
        enough_space = self.enough_space(total_size, path=self.temp_path)
        if not enough_space:
            logging.debug('Download canceled because of Disk Space')
            self.cancel()

            self._canceled_alert = Alert()
            self._canceled_alert.props.title = _('Not enough space '
                                                 'to download')

            total_size_mb = total_size / 1024.0**2
            free_space_mb = (self._free_available_space(
                path=self.temp_path) - SPACE_THRESHOLD) \
                / 1024.0 ** 2
            filename = response.get_suggested_filename()
            self._canceled_alert.props.msg = \
                _('Download "%{filename}" requires %{total_size_in_mb}'
                  ' MB of free space, only %{free_space_in_mb} MB'
                  ' is available' %
                  {'filename': filename,
                   'total_size_in_mb': format_float(total_size_mb),
                   'free_space_in_mb': format_float(free_space_mb)})
            ok_icon = Icon(icon_name='dialog-ok')
            self._canceled_alert.add_button(Gtk.ResponseType.OK, _('Ok'),
                                            ok_icon)
            ok_icon.show()
            self._canceled_alert.connect('response',
                                         self.__canceled_response_cb)
            self._activity.add_alert(self._canceled_alert)

    def __canceled_response_cb(self, alert, response_id):
        self._activity.remove_alert(alert)

    def __decide_destination_cb(self, download, suggested_filename):
        logging.debug('__decide_desintation_cb suggests %s',
                      suggested_filename)
        self._start_alert = TimeoutAlert(9)
        self._start_alert.props.title = _('Downloading')
        self._start_alert.props.msg = suggested_filename
        self._activity.add_alert(self._start_alert)
        self._start_alert.connect('response', self.__start_response_cb)
        self._start_alert.show()

        self._suggested_filename = suggested_filename
        # figure out download URI
        self._dest_path = tempfile.mktemp(dir=self.temp_path,
                                          suffix=suggested_filename,
                                          prefix='tmp')
        logging.debug('Download destination path: %s' % self._dest_path)
        self._download.set_destination('file://' + self._dest_path)
        logging.error(self._download.get_destination)
        return True

    def __created_destination_cb(self, download, dest):
        logging.debug('__created_destination_cb at %s', dest)
        self._create_journal_object()
        self._object_id = self.dl_jobject.object_id

    def _update_progress(self):
        if self._progress > self._last_update_progress:
            self._last_update_progress = self._progress
            self.dl_jobject.metadata['progress'] = str(self._progress)
            datastore.write(self.dl_jobject)

        self._progress_sid = None
        return False

    def __download_received_data_cb(self, download, data_size):
        self._progress = int(self._download.get_estimated_progress() * 100)

        if self._progress_sid is None:
            self._progress_sid = GObject.timeout_add(PROGRESS_TIMEOUT,
                                                     self._update_progress)

    def __download_finished_cb(self, download):
        if hasattr(self._activity, 'busy'):
            self._activity.unbusy()

        if self._progress_sid is not None:
            GObject.source_remove(self._progress_sid)

        if self.dl_jobject is None:
            return  # the "failed" signal was observed

        self.dl_jobject.metadata['title'] = self._suggested_filename
        self.dl_jobject.metadata['description'] = _('From: %s') \
            % self._source
        self.dl_jobject.metadata['progress'] = '100'
        self.dl_jobject.file_path = self._dest_path

        mime_type = Gio.content_type_guess(self._dest_path)[0]
        if mime_type != 'application/vnd.olpc-sugar':
            mime_type = download.get_response().get_mime_type()

        self.dl_jobject.metadata['mime_type'] = mime_type

        if mime_type in ('image/bmp', 'image/gif', 'image/jpeg', 'image/png',
                         'image/tiff'):
            preview = self._get_preview()
            if preview is not None:
                self.dl_jobject.metadata['preview'] = \
                    dbus.ByteArray(preview)

        datastore.write(self.dl_jobject,
                        transfer_ownership=True,
                        reply_handler=self.__internal_save_cb,
                        error_handler=self.__internal_error_cb,
                        timeout=360)

        if self._start_alert is not None:
            self._activity.remove_alert(self._start_alert)
        self._stop_alert = Alert()
        self._stop_alert.props.title = _('Downloaded')
        self._stop_alert.props.msg = self._suggested_filename

        bundle = None
        if _HAS_BUNDLE_LAUNCHER:
            bundle = get_bundle(object_id=self._object_id)

        if bundle is not None:
            icon = Icon(file=bundle.get_icon())
            label = _('Open with %s') % bundle.get_name()
            response_id = Gtk.ResponseType.APPLY
        else:
            icon = Icon(icon_name='zoom-activity')
            label = _('Show in Journal')
            response_id = Gtk.ResponseType.ACCEPT

        self._stop_alert.add_button(response_id, label, icon)
        icon.show()

        ok_icon = Icon(icon_name='dialog-ok')
        self._stop_alert.add_button(Gtk.ResponseType.OK, _('Ok'), ok_icon)
        ok_icon.show()

        self._activity.add_alert(self._stop_alert)
        self._stop_alert.connect('response', self.__stop_response_cb)
        self._stop_alert.show()

    def __download_failed_cb(self, download, error):
        logging.error('Error downloading URI due to %s' % error)
        self.cleanup()

    def __internal_save_cb(self):
        logging.debug('Object saved succesfully to the datastore.')
        self.cleanup()

    def __internal_error_cb(self, err):
        logging.debug('Error saving activity object to datastore: %s' % err)
        self.cleanup()

    def __start_response_cb(self, alert, response_id):
        if response_id is Gtk.ResponseType.CANCEL:
            logging.debug('Download Canceled')
            self.cancel()
            try:
                datastore.delete(self._object_id)
            except Exception, e:
                logging.warning('Object has been deleted already %s' % e)

            self.cleanup()
            if self._stop_alert is not None:
                self._activity.remove_alert(self._stop_alert)

        self._activity.remove_alert(alert)
        self._start_alert = None
Example #56
0
class BatchOperator(GObject.GObject):
    """
    This class implements the course of actions that happens when clicking
    upon an BatchOperation  (eg. Batch-Copy-Toolbar-button;
                             Batch-Copy-To-Journal-button;
                             Batch-Copy-To-Documents-button;
                             Batch-Copy-To-Mounted-Drive-button;
                             Batch-Copy-To-Clipboard-button;
                             Batch-Erase-Button;
    """
    def __init__(self, journalactivity, uid_list, alert_title, alert_message,
                 operation_cb):
        GObject.GObject.__init__(self)

        self._journalactivity = journalactivity

        self._uid_list = uid_list[:]
        self._alert_title = alert_title
        self._alert_message = alert_message
        self._operation_cb = operation_cb

        self._show_confirmation_alert()

    def _show_confirmation_alert(self):
        self._journalactivity.freeze_ui()
        GObject.idle_add(self.__show_confirmation_alert_internal)

    def __show_confirmation_alert_internal(self):
        # Show a alert requesting confirmation before run the batch operation
        self._confirmation_alert = Alert()
        self._confirmation_alert.props.title = self._alert_title
        self._confirmation_alert.props.msg = self._alert_message

        stop_icon = Icon(icon_name='dialog-cancel')
        self._confirmation_alert.add_button(Gtk.ResponseType.CANCEL, _('Stop'),
                                            stop_icon)
        stop_icon.show()

        ok_icon = Icon(icon_name='dialog-ok')
        self._confirmation_alert.add_button(Gtk.ResponseType.OK, _('Continue'),
                                            ok_icon)
        ok_icon.show()

        self._journalactivity.add_alert(self._confirmation_alert)
        self._confirmation_alert.connect('response',
                                         self.__confirmation_response_cb)
        self._confirmation_alert.show()

    def __confirmation_response_cb(self, alert, response):
        if response == Gtk.ResponseType.CANCEL:
            self._journalactivity.unfreeze_ui()
            self._journalactivity.remove_alert(alert)
            # this is only in the case the operation already started
            # and the user want stop it.
            self._stop_batch_operation()
        else:
            GObject.idle_add(self._prepare_batch_execution)

    def _prepare_batch_execution(self):
        self._object_index = 0
        # Next, proceed with the objects
        self._operate_by_uid()

    def _operate_by_uid(self):
        GObject.idle_add(self._operate_by_uid_internal)

    def _operate_by_uid_internal(self):
        # If there is still some uid left, proceed with the operation.
        # Else, proceed to post-operations.
        if self._object_index < len(self._uid_list):
            uid = self._uid_list[self._object_index]
            metadata = model.get(uid)
            title = None
            if 'title' in metadata:
                title = metadata['title']
            if title is None or title == '':
                title = _('Untitled')
            alert_message = _('%(index)d of %(total)d : %(object_title)s') % {
                'index': self._object_index,
                'total': len(self._uid_list),
                'object_title': title
            }

            self._confirmation_alert.props.msg = alert_message
            GObject.idle_add(self._operate_per_metadata, metadata)
        else:
            self._finish_batch_execution()

    def _operate_per_metadata(self, metadata):
        self._operation_cb(metadata)

        # process the next
        self._object_index = self._object_index + 1
        GObject.idle_add(self._operate_by_uid_internal)

    def _stop_batch_execution(self):
        self._object_index = len(self._uid_list)

    def _finish_batch_execution(self):
        self._journalactivity.unfreeze_ui()
        self._journalactivity.remove_alert(self._confirmation_alert)
        self._journalactivity.update_selected_items_ui()
    def __state_change_cb(self, download, gparamspec):
        state = self._download.get_status()
        if state == WebKit.DownloadStatus.STARTED:
            # Check free space and cancel the download if there is not enough.
            total_size = self._download.get_total_size()
            logging.debug('Total size of the file: %s', total_size)
            enough_space = self.enough_space(total_size, path=self.temp_path)
            if not enough_space:
                logging.debug('Download canceled because of Disk Space')
                self.cancel()

                self._canceled_alert = Alert()
                self._canceled_alert.props.title = _('Not enough space '
                                                     'to download')

                total_size_mb = total_size / 1024.0**2
                free_space_mb = (self._free_available_space(
                    path=self.temp_path) - SPACE_THRESHOLD) \
                    / 1024.0 ** 2
                filename = self._download.get_suggested_filename()
                self._canceled_alert.props.msg = \
                    _('Download "%{filename}" requires %{total_size_in_mb}'
                      ' MB of free space, only %{free_space_in_mb} MB'
                      ' is available' %
                      {'filename': filename,
                       'total_size_in_mb': format_float(total_size_mb),
                       'free_space_in_mb': format_float(free_space_mb)})
                ok_icon = Icon(icon_name='dialog-ok')
                self._canceled_alert.add_button(Gtk.ResponseType.OK, _('Ok'),
                                                ok_icon)
                ok_icon.show()
                self._canceled_alert.connect('response',
                                             self.__stop_response_cb)
                self._activity.add_alert(self._canceled_alert)
            else:
                # FIXME: workaround for SL #4385
                # self._download.connect('notify::progress',
                #                        self.__progress_change_cb)
                self._download.connect('notify::current-size',
                                       self.__current_size_changed_cb)

                self._create_journal_object()
                self._object_id = self.dl_jobject.object_id

                alert = TimeoutAlert(9)
                alert.props.title = _('Download started')
                alert.props.msg = _('%s' %
                                    self._download.get_suggested_filename())
                self._activity.add_alert(alert)
                alert.connect('response', self.__start_response_cb)
                alert.show()
                global _active_downloads
                _active_downloads.append(self)

        elif state == WebKit.DownloadStatus.FINISHED:
            self._stop_alert = Alert()
            self._stop_alert.props.title = _('Download completed')
            self._stop_alert.props.msg = \
                _('%s' % self._download.get_suggested_filename())

            if self._progress_sid is not None:
                GObject.source_remove(self._progress_sid)

            self.dl_jobject.metadata['title'] = \
                self._download.get_suggested_filename()
            self.dl_jobject.metadata['description'] = _('From: %s') \
                % self._source
            self.dl_jobject.metadata['progress'] = '100'
            self.dl_jobject.file_path = self._dest_path

            # sniff for a mime type, no way to get headers from WebKit
            sniffed_mime_type = mime.get_for_file(self._dest_path)
            self.dl_jobject.metadata['mime_type'] = sniffed_mime_type

            if sniffed_mime_type in ('image/bmp', 'image/gif', 'image/jpeg',
                                     'image/png', 'image/tiff'):
                preview = self._get_preview()
                if preview is not None:
                    self.dl_jobject.metadata['preview'] = \
                        dbus.ByteArray(preview)

            datastore.write(self.dl_jobject,
                            transfer_ownership=True,
                            reply_handler=self.__internal_save_cb,
                            error_handler=self.__internal_error_cb,
                            timeout=360)

            bundle = None
            if _HAS_BUNDLE_LAUNCHER:
                bundle = get_bundle(object_id=self._object_id)

            if bundle is not None:
                icon = Icon(file=bundle.get_icon())
                label = _('Open with %s') % bundle.get_name()
                response_type = Gtk.ResponseType.APPLY
            else:
                icon = Icon(icon_name='zoom-activity')
                label = _('Show in Journal')
                response_type = Gtk.ResponseType.ACCEPT

            self._stop_alert.add_button(response_type, label, icon)
            icon.show()

            ok_icon = Icon(icon_name='dialog-ok')
            self._stop_alert.add_button(Gtk.ResponseType.OK, _('Ok'), ok_icon)
            ok_icon.show()

            self._activity.add_alert(self._stop_alert)
            self._stop_alert.connect('response', self.__stop_response_cb)
            self._stop_alert.show()

        elif state == WebKit.DownloadStatus.CANCELLED:
            self.cleanup()
    def _journal_alert(self, object_id, title, msg):
        alert = Alert()
        alert.props.title = title
        alert.props.msg = msg

        bundle = get_bundle(object_id=object_id)
        if bundle is not None:
            alert.add_button(Gtk.ResponseType.ACCEPT,
                             _('Open with {}').format(bundle.get_name()),
                             Icon(file=bundle.get_icon()))
        else:
            alert.add_button(Gtk.ResponseType.APPLY, _('Show in Journal'),
                             Icon(icon_name='zoom-activity'))
        alert.add_button(Gtk.ResponseType.OK, _('Ok'),
                         Icon(icon_name='dialog-ok'))

        # Remove other alerts
        for alert in self._alerts:
            self.remove_alert(alert)

        self.add_alert(alert)
        alert.connect('response', self.__alert_response_cb, object_id)
        alert.show_all()
Example #59
0
    def _add_proxy_section(self, workspace):
        label_proxy = Gtk.Label(_('Proxy'))
        label_proxy.set_alignment(0, 0)
        workspace.pack_start(label_proxy, False, True, 0)
        label_proxy.show()

        box_proxy = Gtk.VBox()
        box_proxy.set_border_width(style.DEFAULT_SPACING * 2)
        box_proxy.set_spacing(style.DEFAULT_SPACING)
        workspace.pack_start(box_proxy, False, True, 0)
        box_proxy.show()

        self._proxy_alert = Alert()
        self._proxy_alert.props.title = _('Error')
        self._proxy_alert.props.msg = _('Proxy settings cannot be verified')
        box_proxy.pack_start(self._proxy_alert, False, False, 0)
        self._proxy_alert.connect('response', self._response_cb)
        self._proxy_alert.hide()

        # GSettings schemas for proxy:
        schemas = [
            'org.sugarlabs.system.proxy', 'org.sugarlabs.system.proxy.http',
            'org.sugarlabs.system.proxy.https',
            'org.sugarlabs.system.proxy.ftp',
            'org.sugarlabs.system.proxy.socks'
        ]

        for schema in schemas:
            proxy_setting = Gio.Settings.new(schema)

            # We are not going to apply the settings immediatly.
            # We'll apply them if the user presses the "accept"
            # button, or we'll revert them if the user presses the
            # "cancel" button.
            proxy_setting.delay()
            alert = InlineAlert()

            self._proxy_settings[schema] = proxy_setting
            self._proxy_inline_alerts[schema] = alert

        size_group = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL)

        automatic_proxy_box = Gtk.VBox(spacing=style.DEFAULT_SPACING)
        manual_proxy_box = Gtk.VBox(spacing=style.DEFAULT_SPACING)

        option_sets = [('None', 'none', Gtk.VBox()),
                       ('Use system proxy', 'system', Gtk.VBox()),
                       ('Manual', 'manual', manual_proxy_box),
                       ('Automatic', 'auto', automatic_proxy_box)]

        box_mode = ComboSettingBox(
            _('Method:'), self._proxy_settings['org.sugarlabs.system.proxy'],
            'mode', option_sets, size_group)

        box_proxy.pack_start(box_mode, False, False, 0)
        box_mode.show()

        url_box = StringSettingBox(
            _('Configuration URL:'),
            self._proxy_settings['org.sugarlabs.system.proxy'],
            'autoconfig-url', size_group)

        automatic_proxy_box.pack_start(url_box, True, True, 0)
        url_box.show()

        wpad_help_text = _('Web Proxy Autodiscovery is used when a'
                           ' Configuration URL is not provided. This is not'
                           ' recommended for untrusted public networks.')
        automatic_proxy_help = Gtk.Label(wpad_help_text)
        automatic_proxy_help.set_alignment(0, 0)
        automatic_proxy_help.set_line_wrap(True)
        automatic_proxy_help.show()
        automatic_proxy_box.pack_start(automatic_proxy_help, True, True, 0)

        # HTTP Section
        schema = 'org.sugarlabs.system.proxy.http'
        box_http = HostPortSettingBox(_('HTTP Proxy:'),
                                      self._proxy_inline_alerts[schema],
                                      self._proxy_settings[schema], size_group)
        manual_proxy_box.pack_start(box_http, False, False, 0)
        box_http.show()
        auth_contents_box = Gtk.VBox(spacing=style.DEFAULT_SPACING)
        auth_box = OptionalSettingsBox(_('Use authentication'),
                                       self._proxy_settings[schema],
                                       'use-authentication', auth_contents_box)
        manual_proxy_box.pack_start(auth_box, False, False, 0)
        auth_box.show()
        proxy_http_setting = Gio.Settings.new(schema)
        proxy_http_setting.delay()
        box_username = StringSettingBox(_('Username:'******'authentication-user', size_group)
        auth_contents_box.pack_start(box_username, False, False, 0)
        box_username.show()
        box_password = StringSettingBox(_('Password:'******'authentication-password',
                                        size_group,
                                        password_field=True)
        auth_contents_box.pack_start(box_password, False, False, 0)
        box_password.show()

        # HTTPS Section
        schema = 'org.sugarlabs.system.proxy.https'
        box_https = HostPortSettingBox(_('HTTPS Proxy:'),
                                       self._proxy_inline_alerts[schema],
                                       self._proxy_settings[schema],
                                       size_group)
        manual_proxy_box.pack_start(box_https, False, False, 0)
        box_https.show()

        # FTP Section
        schema = 'org.sugarlabs.system.proxy.ftp'
        box_ftp = HostPortSettingBox(_('FTP Proxy:'),
                                     self._proxy_inline_alerts[schema],
                                     self._proxy_settings[schema], size_group)
        manual_proxy_box.pack_start(box_ftp, False, False, 0)
        box_ftp.show()

        # SOCKS Section
        schema = 'org.sugarlabs.system.proxy.socks'
        box_socks = HostPortSettingBox(_('SOCKS Proxy:'),
                                       self._proxy_inline_alerts[schema],
                                       self._proxy_settings[schema],
                                       size_group)
        manual_proxy_box.pack_start(box_socks, False, False, 0)
        box_socks.show()

        box_ignore = StringSettingBox_with_convert(
            _('Ignore Hosts:'),
            self._proxy_settings['org.sugarlabs.system.proxy'], 'ignore-hosts',
            type_as_to_string, string_to_type_as, size_group)
        manual_proxy_box.pack_start(box_ignore, False, False, 0)
        box_ignore.show()
Example #60
0
class Download(object):
    def __init__(self, webkit_download, activity):
        self._download = webkit_download
        self._activity = activity

        self._source = self._download.get_request().get_uri()
        logging.debug('START Download %s', self._source)

        self.datastore_deleted_handler = None

        self.dl_jobject = None
        self._object_id = None
        self._start_alert = None
        self._stop_alert = None

        self._dest_path = ''
        self._progress = 0
        self._last_update_progress = 0
        self._progress_sid = None

        self.temp_path = os.path.join(self._activity.get_activity_root(),
                                      'instance')
        if not os.path.exists(self.temp_path):
            os.makedirs(self.temp_path)

        self._download.connect('failed', self.__download_failed_cb)
        self._download.connect('finished', self.__download_finished_cb)
        self._download.connect('received-data',
                               self.__download_received_data_cb)

        # Notify response is called before decide destination
        self._download.connect('notify::response', self.__notify_response_cb)
        self._download.connect('decide-destination',
                               self.__decide_destination_cb)
        self._download.connect('created-destination',
                               self.__created_destination_cb)

    def __notify_response_cb(self, download, pspec):
        logging.debug('__notify_response_cb')
        response = download.get_response()

        # Check free space and cancel the download if there is not enough.
        total_size = response.get_content_length()
        logging.debug('Total size of the file: %s', total_size)
        enough_space = self.enough_space(total_size, path=self.temp_path)
        if not enough_space:
            logging.debug('Download canceled because of Disk Space')
            self.cancel()

            self._canceled_alert = Alert()
            self._canceled_alert.props.title = _('Not enough space '
                                                 'to download')

            total_size_mb = total_size / 1024.0**2
            free_space_mb = (self._free_available_space(
                path=self.temp_path) - SPACE_THRESHOLD) \
                / 1024.0 ** 2
            filename = response.get_suggested_filename()
            self._canceled_alert.props.msg = \
                _('Download "%{filename}" requires %{total_size_in_mb}'
                  ' MB of free space, only %{free_space_in_mb} MB'
                  ' is available' %
                  {'filename': filename,
                   'total_size_in_mb': format_float(total_size_mb),
                   'free_space_in_mb': format_float(free_space_mb)})
            ok_icon = Icon(icon_name='dialog-ok')
            self._canceled_alert.add_button(Gtk.ResponseType.OK, _('Ok'),
                                            ok_icon)
            ok_icon.show()
            self._canceled_alert.connect('response',
                                         self.__canceled_response_cb)
            self._activity.add_alert(self._canceled_alert)

    def __canceled_response_cb(self, alert, response_id):
        self._activity.remove_alert(alert)

    def __decide_destination_cb(self, download, suggested_filename):
        logging.debug('__decide_desintation_cb suggests %s',
                      suggested_filename)
        self._start_alert = TimeoutAlert(9)
        self._start_alert.props.title = _('Downloading')
        self._start_alert.props.msg = suggested_filename
        self._activity.add_alert(self._start_alert)
        self._start_alert.connect('response', self.__start_response_cb)
        self._start_alert.show()

        self._suggested_filename = suggested_filename
        # figure out download URI
        self._dest_path = tempfile.mktemp(dir=self.temp_path,
                                          suffix=suggested_filename,
                                          prefix='tmp')
        logging.debug('Download destination path: %s' % self._dest_path)
        self._download.set_destination('file://' + self._dest_path)
        logging.error(self._download.get_destination)
        return True

    def __created_destination_cb(self, download, dest):
        logging.debug('__created_destination_cb at %s', dest)
        self._create_journal_object()
        self._object_id = self.dl_jobject.object_id

    def _update_progress(self):
        if self._progress > self._last_update_progress:
            self._last_update_progress = self._progress
            self.dl_jobject.metadata['progress'] = str(self._progress)
            datastore.write(self.dl_jobject)

        self._progress_sid = None
        return False

    def __download_received_data_cb(self, download, data_size):
        self._progress = int(self._download.get_estimated_progress() * 100)

        if self._progress_sid is None:
            self._progress_sid = GObject.timeout_add(PROGRESS_TIMEOUT,
                                                     self._update_progress)

    def __download_finished_cb(self, download):
        if hasattr(self._activity, 'busy'):
            self._activity.unbusy()

        if self._progress_sid is not None:
            GObject.source_remove(self._progress_sid)

        if self.dl_jobject is None:
            return  # the "failed" signal was observed

        self.dl_jobject.metadata['title'] = self._suggested_filename
        self.dl_jobject.metadata['description'] = _('From: %s') \
            % self._source
        self.dl_jobject.metadata['progress'] = '100'
        self.dl_jobject.file_path = self._dest_path

        mime_type = Gio.content_type_guess(self._dest_path)[0]
        if mime_type != 'application/vnd.olpc-sugar':
            mime_type = download.get_response().get_mime_type()

        self.dl_jobject.metadata['mime_type'] = mime_type

        if mime_type in ('image/bmp', 'image/gif', 'image/jpeg', 'image/png',
                         'image/tiff'):
            preview = self._get_preview()
            if preview is not None:
                self.dl_jobject.metadata['preview'] = \
                    dbus.ByteArray(preview)

        datastore.write(self.dl_jobject,
                        transfer_ownership=True,
                        reply_handler=self.__internal_save_cb,
                        error_handler=self.__internal_error_cb,
                        timeout=360)

        if self._start_alert is not None:
            self._activity.remove_alert(self._start_alert)
        self._stop_alert = Alert()
        self._stop_alert.props.title = _('Downloaded')
        self._stop_alert.props.msg = self._suggested_filename

        bundle = None
        if _HAS_BUNDLE_LAUNCHER:
            bundle = get_bundle(object_id=self._object_id)

        if bundle is not None:
            icon = Icon(file=bundle.get_icon())
            label = _('Open with %s') % bundle.get_name()
            response_id = Gtk.ResponseType.APPLY
        else:
            icon = Icon(icon_name='zoom-activity')
            label = _('Show in Journal')
            response_id = Gtk.ResponseType.ACCEPT

        self._stop_alert.add_button(response_id, label, icon)
        icon.show()

        ok_icon = Icon(icon_name='dialog-ok')
        self._stop_alert.add_button(Gtk.ResponseType.OK, _('Ok'), ok_icon)
        ok_icon.show()

        self._activity.add_alert(self._stop_alert)
        self._stop_alert.connect('response', self.__stop_response_cb)
        self._stop_alert.show()

    def __download_failed_cb(self, download, error):
        logging.error('Error downloading URI due to %s' % error)
        self.cleanup()

    def __internal_save_cb(self):
        logging.debug('Object saved succesfully to the datastore.')
        self.cleanup()

    def __internal_error_cb(self, err):
        logging.debug('Error saving activity object to datastore: %s' % err)
        self.cleanup()

    def __start_response_cb(self, alert, response_id):
        if response_id is Gtk.ResponseType.CANCEL:
            logging.debug('Download Canceled')
            self.cancel()
            try:
                datastore.delete(self._object_id)
            except Exception as e:
                logging.warning('Object has been deleted already %s' % e)

            self.cleanup()
            if self._stop_alert is not None:
                self._activity.remove_alert(self._stop_alert)

        self._activity.remove_alert(alert)
        self._start_alert = None

    def __stop_response_cb(self, alert, response_id):
        if response_id == Gtk.ResponseType.APPLY:
            launch_bundle(object_id=self._object_id)
        if response_id == Gtk.ResponseType.ACCEPT:
            activity.show_object_in_journal(self._object_id)
        self._activity.remove_alert(alert)

    def cleanup(self):
        global _active_downloads
        if self in _active_downloads:
            _active_downloads.remove(self)

        if self.datastore_deleted_handler is not None:
            self.datastore_deleted_handler.remove()
            self.datastore_deleted_handler = None

        if os.path.isfile(self._dest_path):
            os.remove(self._dest_path)

        if self.dl_jobject is not None:
            self.dl_jobject.destroy()
            self.dl_jobject = None

    def cancel(self):
        self._download.cancel()

    def enough_space(self, size, path='/'):
        """Check if there is enough (size) free space on path

        size -- free space requested in Bytes

        path -- device where the check will be done. For example: '/tmp'

        This method is useful to check the free space, for example,
        before starting a download from internet, creating a big map
        in some game or whatever action that needs some space in the
        Hard Disk.
        """

        free_space = self._free_available_space(path=path)
        return free_space - size > SPACE_THRESHOLD

    def _free_available_space(self, path='/'):
        """Return available space in Bytes

        This method returns the available free space in the 'path' and
        returns this amount in Bytes.
        """

        s = os.statvfs(path)
        return s.f_bavail * s.f_frsize

    def _create_journal_object(self):
        logging.debug('_create_journal_object')
        self.dl_jobject = datastore.create()
        filename = self._download.get_response().get_suggested_filename()
        self.dl_jobject.metadata['title'] = \
            _('Downloading %(filename)s from \n%(source)s.') % \
            {'filename': filename, 'source': self._source}

        self.dl_jobject.metadata['progress'] = '0'
        self.dl_jobject.metadata['keep'] = '0'
        self.dl_jobject.metadata['buddies'] = ''
        self.dl_jobject.metadata['preview'] = ''
        self.dl_jobject.metadata['icon-color'] = \
            profile.get_color().to_string()
        self.dl_jobject.metadata['mime_type'] = ''
        self.dl_jobject.file_path = self._dest_path
        datastore.write(self.dl_jobject)

        bus = dbus.SessionBus()
        obj = bus.get_object(DS_DBUS_SERVICE, DS_DBUS_PATH)
        datastore_dbus = dbus.Interface(obj, DS_DBUS_INTERFACE)
        self.datastore_deleted_handler = datastore_dbus.connect_to_signal(
            'Deleted',
            self.__datastore_deleted_cb,
            arg0=self.dl_jobject.object_id)

    def _get_preview(self):
        # This code borrows from sugar3.activity.Activity.get_preview
        # to make the preview with cairo, and also uses GdkPixbuf to
        # load any GdkPixbuf supported format.
        pixbuf = GdkPixbuf.Pixbuf.new_from_file(self._dest_path)
        image_width = pixbuf.get_width()
        image_height = pixbuf.get_height()

        preview_width, preview_height = activity.PREVIEW_SIZE
        preview_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
                                             preview_width, preview_height)
        cr = cairo.Context(preview_surface)

        scale_w = preview_width * 1.0 / image_width
        scale_h = preview_height * 1.0 / image_height
        scale = min(scale_w, scale_h)

        translate_x = int((preview_width - (image_width * scale)) / 2)
        translate_y = int((preview_height - (image_height * scale)) / 2)

        cr.translate(translate_x, translate_y)
        cr.scale(scale, scale)

        cr.set_source_rgba(1, 1, 1, 0)
        cr.set_operator(cairo.OPERATOR_SOURCE)
        cr.paint()
        Gdk.cairo_set_source_pixbuf(cr, pixbuf, 0, 0)
        cr.paint()

        preview_str = io.BytesIO()
        preview_surface.write_to_png(preview_str)
        return preview_str.getvalue()

    def __datastore_deleted_cb(self, uid):
        logging.debug(
            'Downloaded entry has been deleted'
            ' from the datastore: %r', uid)
        global _active_downloads
        if self in _active_downloads:
            self.cancel()
            self.cleanup()