changeset c49c8c8abedc in /home/hg/repos/gajim

details:http://hg.gajim.org/gajim?cmd=changeset;node=c49c8c8abedc
description: add infobar in chat window for file transfer events. Fixes #1205

diffstat:

 src/chat_control.py         |  168 ++++++++++++++++++++++++++++++++++++++++++++
 src/filetransfers_window.py |  123 +++++++++++++++++---------------
 2 files changed, 233 insertions(+), 58 deletions(-)

diffs (truncated from 336 to 300 lines):

diff -r aae4f1ce73ad -r c49c8c8abedc src/chat_control.py
--- a/src/chat_control.py       Mon Oct 17 18:03:30 2011 +0300
+++ b/src/chat_control.py       Mon Oct 17 17:12:19 2011 +0200
@@ -1592,6 +1592,22 @@
         id_ = widget.connect('value_changed', 
self.on_sound_hscale_value_changed)
         self.handlers[id_] = widget
 
+        self.info_bar = gtk.InfoBar()
+        content_area = self.info_bar.get_content_area()
+        self.info_bar_label = gtk.Label()
+        self.info_bar_label.set_use_markup(True)
+        self.info_bar_label.set_alignment(0, 0)
+        content_area.add(self.info_bar_label)
+        self.info_bar.set_no_show_all(True)
+        widget = self.xml.get_object('vbox2')
+        widget.pack_start(self.info_bar, expand=False, padding=5)
+        widget.reorder_child(self.info_bar, 1)
+
+        # List of waiting infobar messages
+        self.info_bar_queue = []
+
+        self.subscribe_events()
+
         if not session:
             # Don't use previous session if we want to a specific resource
             # and it's not the same
@@ -1661,6 +1677,20 @@
         # instance object
         gajim.plugin_manager.gui_extension_point('chat_control', self)
 
+    def subscribe_events(self):
+        """
+        Register listeners to the events class
+        """
+        gajim.events.event_added_subscribe(self.on_event_added)
+        gajim.events.event_removed_subscribe(self.on_event_removed)
+
+    def unsubscribe_events(self):
+        """
+        Unregister listeners to the events class
+        """
+        gajim.events.event_added_unsubscribe(self.on_event_added)
+        gajim.events.event_removed_unsubscribe(self.on_event_removed)
+
     def _update_toolbar(self):
         # Formatting
         if self.contact.supports(NS_XHTML_IM) and not self.gpg_is_active:
@@ -2598,6 +2628,8 @@
         gajim.ged.remove_event_handler('caps-received', ged.GUI1,
             self._nec_caps_received)
 
+        self.unsubscribe_events()
+
         # Send 'gone' chatstate
         self.send_chatstate('gone', self.contact)
         self.contact.chatstate = None
@@ -3109,3 +3141,139 @@
             self.print_conversation(' (', 'status', simple=True)
             self.print_conversation('%s' % (status), 'status', simple=True)
             self.print_conversation(')', 'status', simple=True)
+
+    def _info_bar_show_message(self):
+        if self.info_bar.get_visible():
+            # A message is already shown
+            return
+        if not self.info_bar_queue:
+            return
+        markup, buttons, args, type_ = self.info_bar_queue[0]
+        self.info_bar_label.set_markup(markup)
+        for button in buttons:
+            self.info_bar.add_action_widget(button, 0)
+        self.info_bar.set_message_type(type_)
+        self.info_bar.set_no_show_all(False)
+        self.info_bar.show_all()
+
+    def _add_info_bar_message(self, markup, buttons, args,
+    type_=gtk.MESSAGE_INFO):
+        self.info_bar_queue.append((markup, buttons, args, type_))
+        self._info_bar_show_message()
+
+    def _get_file_props_event(self, file_props, type_):
+        evs = gajim.events.get_events(self.account, self.contact.jid, [type_])
+        for ev in evs:
+            if ev.parameters == file_props:
+                return ev
+        return None
+
+    def _on_accept_file_request(self, widget, file_props):
+        gajim.interface.instances['file_transfers'].on_file_request_accepted(
+            self.account, self.contact, file_props)
+        ev = self._get_file_props_event(file_props, 'file-request')
+        if ev:
+            gajim.events.remove_events(self.account, self.contact.jid, 
event=ev)
+
+    def _on_cancel_file_request(self, widget, file_props):
+        gajim.connections[self.account].send_file_rejection(file_props)
+        ev = self._get_file_props_event(file_props, 'file-request')
+        if ev:
+            gajim.events.remove_events(self.account, self.contact.jid, 
event=ev)
+
+    def _got_file_request(self, file_props):
+        """
+        Show an InfoBar on top of control
+        """
+        markup = '<b>' + _('File transfer:') + '</b> ' + file_props['name']
+        if file_props['desc']:
+            markup += ' (' + file_props['desc'] + ')'
+        markup += '\n' + _('Size:') + ' ' + helpers.convert_bytes(
+            file_props['size'])
+        b1 = gtk.Button(_('_Accept'))
+        b1.connect('clicked', self._on_accept_file_request, file_props)
+        b2 = gtk.Button(stock=gtk.STOCK_CANCEL)
+        b2.connect('clicked', self._on_cancel_file_request, file_props)
+        self._add_info_bar_message(markup, [b1, b2], file_props,
+            gtk.MESSAGE_QUESTION)
+
+    def _on_open_ft_folder(self, widget, file_props):
+        if 'file-name' not in file_props:
+            return
+        path = os.path.split(file_props['file-name'])[0]
+        if os.path.exists(path) and os.path.isdir(path):
+            helpers.launch_file_manager(path)
+        ev = self._get_file_props_event(file_props, 'file-completed')
+        if ev:
+            gajim.events.remove_events(self.account, self.contact.jid, 
event=ev)
+
+    def _on_ok(self, widget, file_props, type_):
+        ev = self._get_file_props_event(file_props, type_)
+        if ev:
+            gajim.events.remove_events(self.account, self.contact.jid, 
event=ev)
+
+    def _got_file_completed(self, file_props):
+        markup = '<b>' + _('File transfer completed:') + '</b> ' + \
+            file_props['name']
+        if file_props['desc']:
+            markup += ' (' + file_props['desc'] + ')'
+        b1 = gtk.Button(_('_Open Containing Folder'))
+        b1.connect('clicked', self._on_open_ft_folder, file_props)
+        b2 = gtk.Button(stock=gtk.STOCK_OK)
+        b2.connect('clicked', self._on_ok, file_props, 'file-completed')
+        self._add_info_bar_message(markup, [b1, b2], file_props)
+
+    def _got_file_error(self, file_props, type_, pri_txt, sec_txt):
+        markup = '<b>%s:</b> %s' % (pri_txt, sec_txt)
+        b = gtk.Button(stock=gtk.STOCK_OK)
+        b.connect('clicked', self._on_ok, file_props, type_)
+        self._add_info_bar_message(markup, [b], file_props, gtk.MESSAGE_ERROR)
+
+    def on_event_added(self, event):
+        if event.account != self.account:
+            return
+        if event.jid != self.contact.jid:
+            return
+        if event.type_ == 'file-request':
+            self._got_file_request(event.parameters)
+        elif event.type_ == 'file-completed':
+            self._got_file_completed(event.parameters)
+        elif event.type_ in ('file-error', 'file-stopped'):
+            msg_err = ''
+            if event.parameters['error'] == -1:
+                msg_err = _('Remote contact stopped transfer')
+            elif event.parameters['error'] == -6:
+                msg_err = _('Error opening file')
+            self._got_file_error(event.parameters, event.type_,
+                _('File transfer stopped'), msg_err)
+        elif event.type_ in ('file-request-error', 'file-send-error'):
+            self._got_file_error(event.parameters, event.type_,
+                _('File transfer cancelled'),
+                _('Connection with peer cannot be established.'))
+
+    def on_event_removed(self, event_list):
+        """
+        Called when one or more events are removed from the event list
+        """
+        for ev in event_list:
+            if ev.account != self.account:
+                continue
+            if ev.jid != self.contact.jid:
+                continue
+            if ev.type_ not in ('file-request', 'file-completed', 'file-error',
+            'file-stopped', 'file-request-error', 'file-send-error'):
+                continue
+            i = 0
+            for ib_msg in self.info_bar_queue:
+                if ib_msg[2] == ev.parameters:
+                    self.info_bar_queue.remove(ib_msg)
+                    if i == 0:
+                        # We are removing the one currently displayed
+                        area = self.info_bar.get_action_area()
+                        for b in area.get_children():
+                            area.remove(b)
+                        self.info_bar.hide()
+                        # show next one?
+                        gobject.idle_add(self._info_bar_show_message)
+                    break
+                i += 1
diff -r aae4f1ce73ad -r c49c8c8abedc src/filetransfers_window.py
--- a/src/filetransfers_window.py       Mon Oct 17 18:03:30 2011 +0300
+++ b/src/filetransfers_window.py       Mon Oct 17 17:12:19 2011 +0200
@@ -320,6 +320,70 @@
         self.add_transfer(account, contact, file_props)
         gajim.connections[account].send_file_approval(file_props)
 
+    def on_file_request_accepted(self, account, contact, file_props):
+        def on_ok(widget, account, contact, file_props):
+            file_path = dialog2.get_filename()
+            file_path = gtkgui_helpers.decode_filechooser_file_paths(
+                (file_path,))[0]
+            if os.path.exists(file_path):
+                # check if we have write permissions
+                if not os.access(file_path, os.W_OK):
+                    file_name = os.path.basename(file_path)
+                    dialogs.ErrorDialog(
+                        _('Cannot overwrite existing file "%s"' % file_name),
+                        _('A file with this name already exists and you do not 
'
+                        'have permission to overwrite it.'))
+                    return
+                stat = os.stat(file_path)
+                dl_size = stat.st_size
+                file_size = file_props['size']
+                dl_finished = dl_size >= file_size
+
+                def on_response(response):
+                    if response < 0:
+                        return
+                    elif response == 100:
+                        file_props['offset'] = dl_size
+                    dialog2.destroy()
+                    self._start_receive(file_path, account, contact, 
file_props)
+
+                dialog = dialogs.FTOverwriteConfirmationDialog(
+                    _('This file already exists'), _('What do you want to 
do?'),
+                    propose_resume=not dl_finished, on_response=on_response)
+                dialog.set_transient_for(dialog2)
+                dialog.set_destroy_with_parent(True)
+                return
+            else:
+                dirname = os.path.dirname(file_path)
+                if not os.access(dirname, os.W_OK) and os.name != 'nt':
+                    # read-only bit is used to mark special folder under
+                    # windows, not to mark that a folder is read-only.
+                    # See ticket #3587
+                    dialogs.ErrorDialog(_('Directory "%s" is not writable') % \
+                        dirname, _('You do not have permission to create files 
'
+                        'in this directory.'))
+                    return
+            dialog2.destroy()
+            self._start_receive(file_path, account, contact, file_props)
+
+        def on_cancel(widget, account, contact, file_props):
+            dialog2.destroy()
+            gajim.connections[account].send_file_rejection(file_props)
+
+        dialog2 = dialogs.FileChooserDialog(
+            title_text=_('Save File as...'),
+            action=gtk.FILE_CHOOSER_ACTION_SAVE,
+            buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
+            gtk.STOCK_SAVE, gtk.RESPONSE_OK),
+            default_response=gtk.RESPONSE_OK,
+            current_folder=gajim.config.get('last_save_dir'),
+            on_response_ok=(on_ok, account, contact, file_props),
+            on_response_cancel=(on_cancel, account, contact, file_props))
+
+        dialog2.set_current_name(file_props['name'])
+        dialog2.connect('delete-event', lambda widget, event:
+            on_cancel(widget, account, contact, file_props))
+
     def show_file_request(self, account, contact, file_props):
         """
         Show dialog asking for comfirmation and store location of new file
@@ -340,64 +404,7 @@
         dialog = None
 
         def on_response_ok(account, contact, file_props):
-
-            def on_ok(widget, account, contact, file_props):
-                file_path = dialog2.get_filename()
-                file_path = gtkgui_helpers.decode_filechooser_file_paths(
-                        (file_path,))[0]
-                if os.path.exists(file_path):
-                    # check if we have write permissions
-                    if not os.access(file_path, os.W_OK):
-                        file_name = os.path.basename(file_path)
-                        dialogs.ErrorDialog(_('Cannot overwrite existing file 
"%s"' % file_name),
-                        _('A file with this name already exists and you do not 
have permission to overwrite it.'))
-                        return
-                    stat = os.stat(file_path)
-                    dl_size = stat.st_size
-                    file_size = file_props['size']
-                    dl_finished = dl_size >= file_size
-
-                    def on_response(response):
-                        if response < 0:
-                            return
-                        elif response == 100:
-                            file_props['offset'] = dl_size
-                        dialog2.destroy()
-                        self._start_receive(file_path, account, contact, 
file_props)
-
-                    dialog = dialogs.FTOverwriteConfirmationDialog(
_______________________________________________
Commits mailing list
[email protected]
http://lists.gajim.org/cgi-bin/listinfo/commits

Reply via email to