示例#1
0
    def show_file_send_request(self, account, contact):
        win = Gtk.ScrolledWindow()
        win.set_shadow_type(Gtk.ShadowType.IN)
        win.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.NEVER)

        from message_textview import MessageTextView
        desc_entry = MessageTextView()
        win.add(desc_entry)

        def on_ok(widget):
            file_dir = None
            files_path_list = dialog.get_filenames()
            text_buffer = desc_entry.get_buffer()
            desc = text_buffer.get_text(text_buffer.get_start_iter(),
                text_buffer.get_end_iter(), True)
            for file_path in files_path_list:
                if self.send_file(account, contact, file_path, desc) \
                and file_dir is None:
                    file_dir = os.path.dirname(file_path)
            if file_dir:
                gajim.config.set('last_send_dir', file_dir)
                dialog.destroy()

        dialog = dialogs.FileChooserDialog(_('Choose File to Send…'),
                Gtk.FileChooserAction.OPEN, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL),
                Gtk.ResponseType.OK,
                True, # select multiple true as we can select many files to send
                gajim.config.get('last_send_dir'),
                on_response_ok=on_ok,
                on_response_cancel=lambda e:dialog.destroy(),
                transient_for=gajim.interface.roster.window
                )

        btn = Gtk.Button.new_with_mnemonic(_('_Send'))
        btn.set_property('can-default', True)
        # FIXME: add send icon to this button (JUMP_TO)
        dialog.add_action_widget(btn, Gtk.ResponseType.OK)
        dialog.set_default_response(Gtk.ResponseType.OK)

        desc_hbox = Gtk.HBox(homogeneous=False, spacing=5)
        desc_hbox.pack_start(Gtk.Label.new(_('Description: ')), False, False, 0)
        desc_hbox.pack_start(win, True, True, 0)

        dialog.vbox.pack_start(desc_hbox, False, False, 0)

        btn.show()
        desc_hbox.show_all()
示例#2
0
    def __init__(self, type_id, parent_win, widget_name, contact):
        # Undo needs this variable to know if space has been pressed.
        # Initialize it to True so empty textview is saved in undo list
        self.space_pressed = True

        MessageControl.__init__(self, type_id, parent_win, widget_name, contact)

        # Create textviews and connect signals
        self.conv_textview = ConversationTextview()

        id_ = self.conv_textview.tv.connect('key_press_event',
            self._conv_textview_key_press_event)
        self.handlers[id_] = self.conv_textview.tv


        self.conv_scrolledwindow = self.xml.get_object(
            'conversation_scrolledwindow')
        self.conv_scrolledwindow.add(self.conv_textview.tv)
        widget = self.conv_scrolledwindow.get_vadjustment()
        id_ = widget.connect('value-changed',
            self.on_conversation_vadjustment_value_changed)
        self.handlers[id_] = widget
        id_ = widget.connect('changed',
            self.on_conversation_vadjustment_changed)
        self.handlers[id_] = widget
        self.scroll_to_end_id = None
        self.was_at_the_end = True
        self.correcting = False
        self.last_sent_msg = None
        self.last_sent_txt = None
        self.last_received_txt = {} # one per name
        self.last_received_id = {} # one per name

        # add MessageTextView to UI and connect signals
        self.msg_scrolledwindow = self.xml.get_object('message_scrolledwindow')
        self.msg_textview = MessageTextView()
        id_ = self.msg_textview.connect('mykeypress',
            self._on_message_textview_mykeypress_event)
        self.handlers[id_] = self.msg_textview
        self.msg_scrolledwindow.add(self.msg_textview)
        id_ = self.msg_textview.connect('key_press_event',
            self._on_message_textview_key_press_event)
        self.handlers[id_] = self.msg_textview
        #id_ = self.msg_textview.connect('configure-event',
        #    self.on_configure_event)
        #self.handlers[id_] = self.msg_textview
        #id_ = self.msg_textview.connect('populate_popup',
        #    self.on_msg_textview_populate_popup)
        #self.handlers[id_] = self.msg_textview
        # Setup DND
        #id_ = self.msg_textview.connect('drag_data_received',
        #    self._on_drag_data_received)
        #self.handlers[id_] = self.msg_textview
        #self.msg_textview.drag_dest_set(Gtk.DestDefaults.MOTION |
        #    Gtk.DestDefaults.HIGHLIGHT, self.dnd_list, Gdk.DragAction.COPY)

        #self.update_font()

        # Hook up send button
        #widget = self.xml.get_object('send_button')
        #id_ = widget.connect('clicked', self._on_send_button_clicked)
        #widget.set_sensitive(False)
        #self.handlers[id_] = widget

        #widget = self.xml.get_object('formattings_button')
        #id_ = widget.connect('clicked', self.on_formattings_button_clicked)
        #self.handlers[id_] = widget

        # the following vars are used to keep history of user's messages
        self.sent_history = []
        self.sent_history_pos = 0
        self.received_history = []
        self.received_history_pos = 0
        self.orig_msg = None

        # Attach speller
        #if gajim.config.get('use_speller') and HAS_GTK_SPELL:
        #    self.set_speller()
        #self.conv_textview.tv.show()
        #self._paint_banner()

        # For XEP-0172
        self.user_nick = None

        self.smooth = True

        self.command_hits = []
        self.last_key_tabs = False
示例#3
0
class ChatControlBase(MessageControl):

    def __init__(self, type_id, parent_win, widget_name, contact):
        # Undo needs this variable to know if space has been pressed.
        # Initialize it to True so empty textview is saved in undo list
        self.space_pressed = True

        MessageControl.__init__(self, type_id, parent_win, widget_name, contact)

        # Create textviews and connect signals
        self.conv_textview = ConversationTextview()

        id_ = self.conv_textview.tv.connect('key_press_event',
            self._conv_textview_key_press_event)
        self.handlers[id_] = self.conv_textview.tv


        self.conv_scrolledwindow = self.xml.get_object(
            'conversation_scrolledwindow')
        self.conv_scrolledwindow.add(self.conv_textview.tv)
        widget = self.conv_scrolledwindow.get_vadjustment()
        id_ = widget.connect('value-changed',
            self.on_conversation_vadjustment_value_changed)
        self.handlers[id_] = widget
        id_ = widget.connect('changed',
            self.on_conversation_vadjustment_changed)
        self.handlers[id_] = widget
        self.scroll_to_end_id = None
        self.was_at_the_end = True
        self.correcting = False
        self.last_sent_msg = None
        self.last_sent_txt = None
        self.last_received_txt = {} # one per name
        self.last_received_id = {} # one per name

        # add MessageTextView to UI and connect signals
        self.msg_scrolledwindow = self.xml.get_object('message_scrolledwindow')
        self.msg_textview = MessageTextView()
        id_ = self.msg_textview.connect('mykeypress',
            self._on_message_textview_mykeypress_event)
        self.handlers[id_] = self.msg_textview
        self.msg_scrolledwindow.add(self.msg_textview)
        id_ = self.msg_textview.connect('key_press_event',
            self._on_message_textview_key_press_event)
        self.handlers[id_] = self.msg_textview
        #id_ = self.msg_textview.connect('configure-event',
        #    self.on_configure_event)
        #self.handlers[id_] = self.msg_textview
        #id_ = self.msg_textview.connect('populate_popup',
        #    self.on_msg_textview_populate_popup)
        #self.handlers[id_] = self.msg_textview
        # Setup DND
        #id_ = self.msg_textview.connect('drag_data_received',
        #    self._on_drag_data_received)
        #self.handlers[id_] = self.msg_textview
        #self.msg_textview.drag_dest_set(Gtk.DestDefaults.MOTION |
        #    Gtk.DestDefaults.HIGHLIGHT, self.dnd_list, Gdk.DragAction.COPY)

        #self.update_font()

        # Hook up send button
        #widget = self.xml.get_object('send_button')
        #id_ = widget.connect('clicked', self._on_send_button_clicked)
        #widget.set_sensitive(False)
        #self.handlers[id_] = widget

        #widget = self.xml.get_object('formattings_button')
        #id_ = widget.connect('clicked', self.on_formattings_button_clicked)
        #self.handlers[id_] = widget

        # the following vars are used to keep history of user's messages
        self.sent_history = []
        self.sent_history_pos = 0
        self.received_history = []
        self.received_history_pos = 0
        self.orig_msg = None

        # Attach speller
        #if gajim.config.get('use_speller') and HAS_GTK_SPELL:
        #    self.set_speller()
        #self.conv_textview.tv.show()
        #self._paint_banner()

        # For XEP-0172
        self.user_nick = None

        self.smooth = True

        self.command_hits = []
        self.last_key_tabs = False

        # PluginSystem: adding GUI extension point for ChatControlBase
        # instance object (also subclasses, eg. ChatControl or GroupchatControl)
        #gajim.plugin_manager.gui_extension_point('chat_control_base', self)

        #gajim.ged.register_event_handler('our-show', ged.GUI1,
        #    self._nec_our_status)
        #gajim.ged.register_event_handler('ping-sent', ged.GUI1,
        #    self._nec_ping_sent)
        #gajim.ged.register_event_handler('ping-reply', ged.GUI1,
        #    self._nec_ping_reply)
        #gajim.ged.register_event_handler('ping-error', ged.GUI1,
        #    self._nec_ping_error)

        # This is bascially a very nasty hack to surpass the inability
        # to properly use the super, because of the old code.
        #CommandTools.__init__(self)

    def _conv_textview_key_press_event(self, widget, event):
        # translate any layout to latin_layout
        valid, entries = self.keymap.get_entries_for_keyval(event.keyval)
        keycode = entries[0].keycode
        if (event.get_state() & Gdk.ModifierType.CONTROL_MASK and keycode in (
        self.keycode_c, self.keycode_ins)) or (
        event.get_state() & Gdk.ModifierType.SHIFT_MASK and \
        event.keyval in (Gdk.KEY_Page_Down, Gdk.KEY_Page_Up)):
            return False
        self.parent_win.notebook.event(event)
        return True

    def _on_message_textview_key_press_event(self, widget, event):
        if event.keyval == Gdk.KEY_space:
            self.space_pressed = True

        elif (self.space_pressed or self.msg_textview.undo_pressed) and \
        event.keyval not in (Gdk.KEY_Control_L, Gdk.KEY_Control_R) and \
        not (event.keyval == Gdk.KEY_z and event.get_state() & Gdk.ModifierType.CONTROL_MASK):
            # If the space key has been pressed and now it hasnt,
            # we save the buffer into the undo list. But be carefull we're not
            # pressiong Control again (as in ctrl+z)
            _buffer = widget.get_buffer()
            start_iter, end_iter = _buffer.get_bounds()
            self.msg_textview.save_undo(_buffer.get_text(start_iter, end_iter, True))
            self.space_pressed = False

        # Ctrl [+ Shift] + Tab are not forwarded to notebook. We handle it here
        if self.widget_name == 'groupchat_control':
            if event.keyval not in (Gdk.KEY_ISO_Left_Tab, Gdk.KEY_Tab):
                self.last_key_tabs = False
        if event.get_state() & Gdk.ModifierType.SHIFT_MASK:
            # CTRL + SHIFT + TAB
            if event.get_state() & Gdk.ModifierType.CONTROL_MASK and \
                            event.keyval == Gdk.KEY_ISO_Left_Tab:
                self.parent_win.move_to_next_unread_tab(False)
                return True
            # SHIFT + PAGE_[UP|DOWN]: send to conv_textview
            elif event.keyval == Gdk.KEY_Page_Down or \
                            event.keyval == Gdk.KEY_Page_Up:
                self.conv_textview.tv.event(event)
                return True
        elif event.get_state() & Gdk.ModifierType.CONTROL_MASK:
            if event.keyval == Gdk.KEY_Tab:  # CTRL + TAB
                self.parent_win.move_to_next_unread_tab(True)
                return True
################################################################################
        # temporary solution instead Gtk.binding_entry_add_signal
        message_buffer = self.msg_textview.get_buffer()
        event_state = event.get_state()
        if event.keyval == Gdk.KEY_Up:
            if event_state & Gdk.ModifierType.CONTROL_MASK:
                if event_state & Gdk.ModifierType.SHIFT_MASK: # Ctrl+Shift+UP
                    self.scroll_messages('up', message_buffer, 'received')
                else:  # Ctrl+UP
                    self.scroll_messages('up', message_buffer, 'sent')
            return True
        elif event.keyval == Gdk.KEY_Down:
            if event_state & Gdk.ModifierType.CONTROL_MASK:
                if event_state & Gdk.ModifierType.SHIFT_MASK: # Ctrl+Shift+Down
                    self.scroll_messages('down', message_buffer, 'received')
                else:  # Ctrl+Down
                    self.scroll_messages('down', message_buffer, 'sent')
            return True

        elif event.keyval == Gdk.KEY_Return or \
        event.keyval == Gdk.KEY_KP_Enter:  # ENTER
            message_textview = widget
            message_buffer = message_textview.get_buffer()
            start_iter, end_iter = message_buffer.get_bounds()
            message = message_buffer.get_text(start_iter, end_iter, False)
            xhtml = self.msg_textview.get_xhtml()

            if event_state & Gdk.ModifierType.CONTROL_MASK:  # Ctrl + ENTER
                end_iter = message_buffer.get_end_iter()
                message_buffer.insert_at_cursor('\n')
                send_message = False
            else: # ENTER
                send_message = True

            #if gajim.connections[self.account].connected < 2 and send_message:
                # we are not connected
            #    dialogs.ErrorDialog(_('A connection is not available'),
            #            _('Your message can not be sent until you are connected.'))
            #    send_message = False

            if send_message:
                self.send_message(message) # send the message
            return True
        elif event.keyval == Gdk.KEY_z: # CTRL+z
            if event_state & Gdk.ModifierType.CONTROL_MASK:
                self.msg_textview.undo()
                return True
################################################################################
        return False


    def _on_message_textview_mykeypress_event(self, widget, event_keyval,
    event_keymod):
        """
        When a key is pressed: if enter is pressed without the shift key, message
        (if not empty) is sent and printed in the conversation
        """
        # NOTE: handles mykeypress which is custom signal connected to this
        # CB in new_tab(). for this singal see message_textview.py
        message_textview = widget
        message_buffer = message_textview.get_buffer()
        start_iter, end_iter = message_buffer.get_bounds()
        message = message_buffer.get_text(start_iter, end_iter, False)
        xhtml = self.msg_textview.get_xhtml()

        # construct event instance from binding
        event = Gdk.Event(Gdk.EventType.KEY_PRESS)  # it's always a key-press here
        event.keyval = event_keyval
        event.state = event_keymod
        event.time = 0  # assign current time

        if event.keyval == Gdk.KEY_Up:
            if event.get_state() == Gdk.ModifierType.CONTROL_MASK:  # Ctrl+UP
                self.scroll_messages('up', message_buffer, 'sent')
            # Ctrl+Shift+UP
            elif event.get_state() == (Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK):
                self.scroll_messages('up', message_buffer, 'received')
        elif event.keyval == Gdk.KEY_Down:
            if event.get_state() == Gdk.ModifierType.CONTROL_MASK:  # Ctrl+Down
                self.scroll_messages('down', message_buffer, 'sent')
            # Ctrl+Shift+Down
            elif event.get_state() == (Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK):
                self.scroll_messages('down', message_buffer, 'received')
        elif event.keyval == Gdk.KEY_Return or \
                event.keyval == Gdk.KEY_KP_Enter:  # ENTER
            # NOTE: SHIFT + ENTER is not needed to be emulated as it is not
            # binding at all (textview's default action is newline)

            if gajim.config.get('send_on_ctrl_enter'):
                # here, we emulate GTK default action on ENTER (add new line)
                # normally I would add in keypress but it gets way to complex
                # to get instant result on changing this advanced setting
                if event.get_state() == 0:  # no ctrl, no shift just ENTER add newline
                    end_iter = message_buffer.get_end_iter()
                    message_buffer.insert_at_cursor('\n')
                    send_message = False
                elif event.get_state() & Gdk.ModifierType.CONTROL_MASK:  # CTRL + ENTER
                    send_message = True
            else: # send on Enter, do newline on Ctrl Enter
                if event.get_state() & Gdk.ModifierType.CONTROL_MASK:  # Ctrl + ENTER
                    end_iter = message_buffer.get_end_iter()
                    message_buffer.insert_at_cursor('\n')
                    send_message = False
                else: # ENTER
                    send_message = True

            if gajim.connections[self.account].connected < 2 and send_message:
                # we are not connected
                dialogs.ErrorDialog(_('A connection is not available'),
                        _('Your message can not be sent until you are connected.'))
                send_message = False

            if send_message:
                self.send_message(message, xhtml=xhtml) # send the message
        elif event.keyval == Gdk.KEY_z: # CTRL+z
            if event.get_state() & Gdk.ModifierType.CONTROL_MASK:
                self.msg_textview.undo()
        else:
            # Give the control itself a chance to process
            self.handle_message_textview_mykey_press(widget, event_keyval,
                    event_keymod)


    def on_conversation_vadjustment_changed(self, adjustment):
        # used to stay at the end of the textview when we shrink conversation
        # textview.
        if self.was_at_the_end:
            if self.conv_textview.at_the_end():
                # we are at the end
                self.conv_textview.bring_scroll_to_end(-18)
            else:
                self.conv_textview.bring_scroll_to_end(-18, use_smooth=False)
        self.was_at_the_end = (adjustment.get_upper() - adjustment.get_value()\
            - adjustment.get_page_size()) < 18

    def on_conversation_vadjustment_value_changed(self, adjustment):
        # stop automatic scroll when we manually scroll
        if not self.conv_textview.auto_scrolling:
            self.conv_textview.stop_scrolling()
        self.was_at_the_end = (adjustment.get_upper() - adjustment.get_value() \
            - adjustment.get_page_size()) < 18

    def shutdown(self):
        super(ChatControlBase, self).shutdown()



    def send_message(self, message):
        """
        Send the given message to the active tab. Doesn't return None if error
        """
        if not message or message == '\n':
            return None

        #if process_commands and self.process_as_command(message):
        #    return

        #label = self.get_seclabel()

        def _cb(msg, cb, *cb_args):
            self.last_sent_msg = msg
            self.last_sent_txt = cb_args[0]
            if cb:
                cb(msg, *cb_args)

        if self.correcting and self.last_sent_msg:
            correction_msg = self.last_sent_msg
        else:
            correction_msg = None

        #gajim.nec.push_outgoing_event(MessageOutgoingEvent(None,
        #    account=self.account, jid=self.contact.jid, message=message,
        #    keyID=keyID, type_=type_, chatstate=chatstate, msg_id=msg_id,
        #    resource=resource, user_nick=self.user_nick, xhtml=xhtml,
        #    label=label, callback=_cb, callback_args=[callback] + callback_args,
        #    control=self, attention=attention, correction_msg=correction_msg))

        print('sending message...')
        import push_message
        threading.Thread(target=push_message.handleSendMms,
             args=(message, self.contact ),
              ).start()
        #self.set_chat_text(' > ' + message, widget)

        # Record the history of sent messages
        #self.save_message(message, 'sent')

        # Be sure to send user nickname only once according to JEP-0172
        #self.user_nick = None

        # Clear msg input
        message_buffer = self.msg_textview.get_buffer()
        message_buffer.set_text('') # clear message buffer (and tv of course)


    def print_conversation_line(self, text, kind, name):
        """
        Print 'chat' type messages
        correct_id = (message_id, correct_id)
        """
        jid = self.contact
        full_jid = self.get_alias()
        textview = self.conv_textview
        end = False
        if self.was_at_the_end or kind == 'outgoing':
            end = True
        old_txt = ''
        if name in self.last_received_txt:
            old_txt = self.last_received_txt[name]

        textview.print_conversation_line(text, jid, kind, name)

        if not self.parent_win:
            return

        if (not self.parent_win.get_active_control() or \
        self != self.parent_win.get_active_control() or \
        not self.parent_win.is_active() or not end) and \
        kind in ('incoming', 'incoming_queue', 'error'):
            self.parent_win.redraw_tab(self)