Beispiel #1
0
 def __sending_status(self, status):
     message = '<span font_desc="belgrano 10" foreground="#F654CA"><b>  ' +  status  + '  </b></span>'
     frame = self.status_bar.get_children()[0]
     hbox = self.status_bar.get_children()[0].child
     label = self.status_bar.get_children()[0].child.get_children()[0]
     label.set_ellipsize(False)
     frame.hide_all()
     hbox.remove(label)
     label.set_markup(message)
     label.set_tooltip_markup(message)
     from spinner import Spin
     self.__spnnier = Spin('', 100, 24, 24, 2.6, 8)
     hbox.pack_start(label, True, True)
     hbox.pack_start(self.__spnnier, True, True)
     alignment = gtk.Alignment(0, 0, 0, 1)
     frame.remove(hbox)
     frame.add(alignment)
     alignment.add(hbox)
     self.status_bar.show_all()
     self.__spnnier.start()
     return True
Beispiel #2
0
class Interface(gtk.Window):
    'The main user interface'

    def add_contacts(self):
        database = DataBase()
        for contacts in self.__contact_box.get_children():
            contacts.hide_all()
            self.__contact_box.remove(contacts)
            contacts.destroy()
        for contacts in database.select_rows('contacts'):
            from contacts import Contact
            contact = Contact(contacts)
            contact.connect('toggle', self._append_number_to_receivers)
            self.__contact_box.pack_start(contact, False, False)
        self.__contact_box.show_all()

    def __add_user(self, unused):
        self.__generalize_status_bar()
        self.__push_status_message('')
        from contacts import PhoneBook
        PhoneBook()
        gtk.main()
        self.add_contacts()
        return False

    def __delete_user(self, unused):
        self.__generalize_status_bar()
        database = DataBase()
        edit_list = [contacts for contacts in self.__contact_box if
                     contacts.get_child().get_children()[0].get_active()]
        if not edit_list:
            self.__push_status_message('<span font_desc="belgrano 10">  Select at least <b><span foreground="#FF0000">one</span></b> contact</span>')
            return False
        contacts = [contact.get_contact_info()[1] for contact in edit_list]
        for number in contacts:
            database.delete('contacts', number)
        database.close()
        self.add_contacts()
        return False

    def __edit_user(self, unused):
        self.__generalize_status_bar()
        from contacts import PhoneBook
        edit_list = [contacts for contacts in self.__contact_box if
                     contacts.get_child().get_children()[0].get_active()]
        if not edit_list:
            self.__push_status_message('<span font_desc="belgrano 10">  Select at least <b><span foreground="#FF0000">one</span></b> contact</span>')
            return False
        PhoneBook(edit_list[0].get_contact_info())
        gtk.main()
        self.add_contacts()
        return False
    
    def _append_number_to_receivers(self, widget,state, number):
        if state:
            self._receiver_widget.append_text(number)
            self._receiver.append(number)
        else:
            if number in self._receiver:
                self._receiver_widget.remove_text(self._receiver.index(number))
                self._receiver.remove(number)

    def __init__(self, login_thread_list):
        super(Interface, self).__init__()
        self.set_size_request(460, 400)
        self.set_border_width(4)
        self.set_title('SMS')
        self.set_icon_from_file(ICON_PATH + '/logo.png')
        self.set_decorated(True)
        self.set_position(gtk.WIN_POS_MOUSE)
        text_field = gtk.TextView()
        text_field.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ffffff'))
        text_field.set_border_width(10)
        text_field.modify_font(pango.FontDescription('belgrano'))
        text_buffer = gtk.TextBuffer()
        text_field.set_buffer(text_buffer)
        text_field.set_wrap_mode(gtk.WRAP_WORD_CHAR)
        text_field.set_tooltip_markup('   Type in your\n<b>MESSAGE</b> here')
        text_field.set_sensitive(False)
        def _enable_text_view_widget(field, thread_list):
            for thread in thread_list:
                if thread.isAlive():
                    return True
            status = True
            for thread in thread_list:
                status = status and thread.getStatus()
            field.set_sensitive(status)
            if not status:
                self.__push_status_message('<span font_desc="belgrano 10"><b>  Login Failed - Network Error</b></span>')
            return False
        gobject.timeout_add(200, _enable_text_view_widget, text_field, login_thread_list)
        self.spell_check_enable = False
        spell_correction = None
        size_tag = text_buffer.create_tag("size", size_points = 11)
        error_tag = text_buffer.create_tag("error", underline = pango.UNDERLINE_ERROR)
        frame = gtk.Frame('Message Body')
        frame.get_label_widget().modify_font(pango.FontDescription('belgrano'))
        frame.set_label_align(0.5, 0.5)
        frame.set_shadow_type(gtk.SHADOW_IN)
        frame.get_label_widget().set_sensitive(False)
        scroll = gtk.ScrolledWindow()
        scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        scroll.set_border_width(4)
        scroll.add_with_viewport(text_field)
        scroll.get_child().modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ffffff'))
        frame.add(scroll)
        frame.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#70EDF7'))
        vbox = gtk.VBox(False, 4)
        hbox = gtk.HBox(False, 20)
        alignment = gtk.Alignment(1, 0.5, 1, 1)
        send = Button(ICON_PATH + '/send.png', 'Send Message')
        clear = Button(ICON_PATH + '/clear.png', 'Clear Field')
        send.connect("clicked", self.__send, text_buffer)
        clear.connect("clicked", self.__clear, text_buffer)
        def check_number(entry):
            'enforces only digits in the entry field'

            text = entry.get_active_text().strip()
            entry.child.set_text(''.join([i for i in text if i in '0123456789']))
            if not len(entry.child.get_text()):
                if self._receiver_index != -1:
                    index = self._receiver_index
                    self._receiver_index = -1
                    del self._receiver[index]
                    self._receiver_widget.remove_text(index)
            if len(entry.child.get_text()) == 10:
                if entry.get_active() != -1:
                    self._receiver_index = entry.get_active()
                if entry.child.get_text() not in self._receiver:
                    if self._receiver_index != -1:
                        self._receiver[self._receiver_index] = entry.child.get_text()
                        self._receiver_widget.remove_text(self._receiver_index)
                        self._receiver_widget.insert_text(self._receiver_index, entry.child.get_text())
                        self._receiver_index = -1
                    else:
                        entry.append_text(entry.child.get_text())
                        self._receiver.append(entry.child.get_text())
                    entry.child.set_text('')
            return False
        receiver_box = gtk.VBox(False, 4)
        label = gtk.Label()
        label.set_markup('<span font_desc="belgrano 10"><b>Receivers</b></span>')
        self._receiver = []
        self._receiver_index = -1
        self._receiver_widget = gtk.combo_box_entry_new_text()
        self._receiver_widget.child.modify_font(pango.FontDescription('CrashNumberingGothic'))
        self._receiver_widget.child.set_max_length(10)
        self._receiver_widget.child.set_tooltip_text("Enter Receivers'\n Numbers Here")
        self._receiver_widget.set_size_request(120, -1)
        self._receiver_widget.child.modify_text(gtk.STATE_NORMAL, gtk.gdk.color_parse('#0000ff'))
        self._receiver_widget.connect('changed', check_number)
        receiver_box.pack_start(label)
        receiver_box.pack_start(self._receiver_widget)
        hbox.pack_start(receiver_box, True, False)
        hbox.pack_start(clear, False, False)
        hbox.pack_start(send, False, False)
        alignment.add(hbox)
        vbox.pack_start(frame, True, True)
        vbox.pack_start(alignment, False, False)
        paned = gtk.HPaned()
        v_box = gtk.VBox(False, 8)
        paned.pack1(vbox, True, False)
        frame = gtk.Frame('Phone Book')
        frame.get_label_widget().modify_font(pango.FontDescription('belgrano'))
        frame.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#70EDF7'))
        frame.set_label_align(0.5, 0.5)
        frame.set_shadow_type(gtk.SHADOW_IN)
        frame.get_label_widget().set_sensitive(False)
        self.__contact_box = gtk.VBox(False, 10)
        alignment = gtk.Alignment(0, 0, 0, 0)
        alignment.set_border_width(4)
        alignment.add(self.__contact_box)
        self.add_contacts()
        scroll = gtk.ScrolledWindow()
        scroll.set_size_request(140, -1)
        scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        scroll.set_border_width(4)
        scroll.add_with_viewport(alignment)
        scroll.get_child().modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ffffff'))
        vbox = gtk.VBox(False, 2)
        hbox = gtk.HBox(True, 0)
        add = Button(ICON_PATH + '/add-user.png', 'Add Contact')
        add.set_border_width(2)
        add.connect('clicked', self.__add_user)
        edit = Button(ICON_PATH + '/edit-user.png', 'Edit Contact\nInformation')
        edit.connect('clicked', self.__edit_user)
        delete = Button(ICON_PATH + '/remove-user.png', 'Remove Contact')
        delete.set_border_width(2)
        delete.connect('clicked', self.__delete_user)
        vbox.pack_start(scroll, True, True)
        hbox.pack_start(add, True, True)
        hbox.pack_start(delete, True, True)
        alignment = gtk.Alignment(0.5, 0, 0, 0)
        alignment.add(hbox)
        vbox.pack_start(alignment, False, False)
        alignment = gtk.Alignment(0.5, 0, 0, 0)
        alignment.add(edit)
        vbox.pack_start(alignment, False, False)
        frame.add(vbox)
        paned.pack2(frame, False, False)
        def manage_account(unused):
            from account import AccountManager
            AccountManager()
            gtk.main()
        def show_about(unused):
            About()
        def show_history(unused):
            from history import HistoryManager
            HistoryManager()
            gtk.main()
        def load_from_file(unused):
            from path import HOME_PATH
            loader = gtk.FileChooserDialog(title = 'Open ...', action = gtk.FILE_CHOOSER_ACTION_OPEN, buttons = (gtk.STOCK_CANCEL,
                                                                            gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))
            loader.set_icon_from_file(ICON_PATH + '/logo.png')
            loader.set_current_folder(HOME_PATH + '/Desktop')
            loader.set_default_response(gtk.RESPONSE_OK)
            filter = gtk.FileFilter()
            filter.set_name("Text")
            filter.add_pattern("*.txt")
            loader.add_filter(filter)
            filter = gtk.FileFilter()
            filter.set_name("All files")
            filter.add_pattern("*")
            loader.add_filter(filter)
            response = loader.run()
            if response == gtk.RESPONSE_OK:
                text_buffer.set_text(open(loader.get_filename()).read())
            loader.destroy()
            return
        def save_to_file(unused):
            from path import HOME_PATH
            import os
            if not os.path.exists(HOME_PATH + '/.sms/saved messages/'):
                os.makedirs(HOME_PATH + '/.sms/saved messages/')
            files = len([name for name in os.listdir(HOME_PATH + '/.sms/saved messages/')])
            loader = gtk.FileChooserDialog(title = "Save ...", action = gtk.FILE_CHOOSER_ACTION_SAVE, buttons = (gtk.STOCK_CANCEL,
                                                                            gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))
            loader.set_icon_from_file(ICON_PATH + '/logo.png')
            loader.set_current_folder(HOME_PATH + '/.sms/saved messages/')
            loader.set_default_response(gtk.RESPONSE_OK)
            loader.set_current_name('message %s.txt' % str(files + 1))
            text = text_buffer.get_text(text_buffer.get_start_iter(), text_buffer.get_end_iter())
            response = loader.run()
            if response == gtk.RESPONSE_OK and text:
                filename = loader.get_filename()
                file = open(filename, 'w')
                file.write(text)
                file.close()
            loader.destroy()
            return
        def check_spell(unused):
            from SpellCheck import spell_check
            global spell_correction
            spell_correction = {}
            thread.start_new(spell_check, (text_buffer.get_text(text_buffer.get_start_iter(), text_buffer.get_end_iter()), spell_correction))
            text_buffer.remove_tag(error_tag, text_buffer.get_start_iter(), text_buffer.get_end_iter())
            text_buffer.apply_tag(size_tag, text_buffer.get_start_iter(), text_buffer.get_end_iter())
            gtk.main()
            if spell_correction:
                self.spell_check_enable = True
                for key in spell_correction.keys():
                    text_buffer.apply_tag(error_tag, text_buffer.get_iter_at_offset(key[0] - 1), text_buffer.get_iter_at_offset(key[0] + key[1] - 1))
        menu_bar = gtk.MenuBar()
        menu_bar.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ff0000'))
        menu = gtk.Menu()
        menu.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ff8800'))
        menu_item = gtk.MenuItem("Load")
        menu.append(menu_item)
        menu_item.connect('activate', load_from_file)
        menu_item = gtk.MenuItem("Save")
        menu.append(menu_item)
        menu_item.connect('activate', save_to_file)
        menu_item = gtk.MenuItem("User Account")
        menu.append(menu_item)
        menu_item.connect('activate', manage_account)
        menu_item = gtk.SeparatorMenuItem()
        menu.append(menu_item)
        menu_item = gtk.MenuItem("Quit")
        menu.append(menu_item)
        menu_item.connect('activate', gtk.main_quit)
        action_menu = gtk.MenuItem("_Action")
        action_menu.set_submenu(menu)
        menu_bar.append(action_menu)
        menu = gtk.Menu()
        menu.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ff8800'))
        menu_item = gtk.MenuItem("History")
        menu.append(menu_item)
        message_menu = gtk.MenuItem("_Message")
        menu_item.connect('activate', show_history)
        menu_item = gtk.MenuItem("Spell Check")
        menu.append(menu_item)
        menu_item.connect('activate', check_spell)
        message_menu.set_submenu(menu)
        menu_bar.append(message_menu)
        menu = gtk.Menu()
        menu.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ff8800'))
        menu_item = gtk.MenuItem("About")
        menu.append(menu_item)
        help_menu = gtk.MenuItem("_Help")
        menu_item.connect('activate', show_about)
        help_menu.set_submenu(menu)
        menu_bar.append(help_menu)
        self.status_bar = gtk.Statusbar()
        self.status_bar.set_size_request(-1, 28)
        self.status_bar.set_has_resize_grip(True)
        hbox = gtk.HBox(False, 2)
        hbox.pack_start(menu_bar, True, True)
        v_box.pack_start(hbox, False, False)
        v_box.pack_start(paned, True, True)
        v_box.pack_start(self.status_bar, False, False)
        self.add(v_box)
        text_buffer.connect("changed", self.__current_char, size_tag, error_tag)
        def spell_check_context_menu(unused, menu):
            global spell_correction
            cursor_pos = text_buffer.props.cursor_position
            if not self.spell_check_enable:
                return
            def replace_rectified(unused, word, key):
                del(spell_correction[key])
                start = text_buffer.get_iter_at_offset(key[0] - 1)
                end = text_buffer.get_iter_at_offset(key[0] + key[1] - 1)
                replaced = text_buffer.get_text(start, end)
                text_buffer.delete(start, end)
                text_buffer.insert(start, word)
                diff = len(replaced) - len(word)
                if diff:
                    for (k, v) in spell_correction.items()[:]:
                        del(spell_correction[k])
                        if key[0] < k[0]:
                            spell_correction[(k[0] - diff, k[1])] = v
                        else:
                            spell_correction[(k[0], k[1])] = v
                for key in spell_correction.keys():
                    text_buffer.apply_tag(error_tag,
                                    text_buffer.get_iter_at_offset(key[0] - 1),
                           text_buffer.get_iter_at_offset(key[0] + key[1] - 1))
                self.spell_check_enable = True
                return
            for key in spell_correction.keys():
                if cursor_pos >= key[0] - 1 and cursor_pos <= key[0] + key[1] - 1:
                    correct = spell_correction[key][:]
                    correct.reverse()
                    for word in correct:
                        menu_item = gtk.MenuItem(word)
                        menu.prepend(menu_item)
                        menu_item.connect('activate', replace_rectified, word, key)
                    menu.show_all()
                    break
            return
        text_field.connect('populate-popup', spell_check_context_menu)
        def destroy(unused):
            gtk.main_quit()
            return
        self.connect("destroy", destroy)
        self.set_focus(text_field)
        self.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ffffff'))
        self.show_all()

    def __generalize_status_bar(self):
        if self.status_bar.get_children()[0].child.__class__ == type(gtk.HBox()
                                                                     ) :
            self.status_bar.get_children()[0].child.get_children()[0].set_text(
                                                                            '')
            self.status_bar.get_children()[0].child.get_children()[0].set_markup('')
            return
        frame = self.status_bar.get_children()[0]
        alignment = self.status_bar.get_children()[0].child
        hbox = self.status_bar.get_children()[0].child.child
        hbox_children = self.status_bar.get_children()[0].child.child.get_children()
        for child in hbox_children:
            if type(child) == type(gtk.Label()):
                child.set_ellipsize(True)
                child.set_text('')
                child.set_markup('')
                break
        frame.hide_all()
        alignment.remove(hbox)
        frame.remove(alignment)
        for index in range(len(hbox_children)):
            if type(hbox_children[index]) != type(gtk.Label()):
                hbox.remove(hbox_children[index])
        frame.add(hbox)
        frame.show_all()

    def __custom_status(self, success, failure = None):
        icon = success and '/success.png' or '/failure.png'
        image = gtk.image_new_from_pixbuf(gtk.gdk.pixbuf_new_from_file(ICON_PATH + icon).scale_simple(28, 28, gtk.gdk.INTERP_HYPER))
        frame = self.status_bar.get_children()[0]
        hbox = self.status_bar.get_children()[0].child
        label = self.status_bar.get_children()[0].child.get_children()[0]
        label.set_ellipsize(False)
        frame.hide_all()
        hbox.remove(label)
        hbox.pack_start(image, False, False)
        hbox.pack_start(label, True, True)
        message = success and '<span font_desc="belgrano 10"> Message has been <span foreground="#3BB048"><b>submitted successfully</b></span></span>'\
or '<span font_desc="belgrano 10"><span foreground="#FF0000"><b> Submission failed</b></span> to </span>'
        self.status_bar.get_children()[0].child.get_children()[1].set_markup(message)
        tooltip = '<span font_desc="belgrano 10" foreground="#%s"><b>Submission %s</b></span>'
        tooltip_status = success and ('3BB048', 'Successful') or ('FF0000', 'Failure')
        self.status_bar.get_children()[0].child.get_children()[1].set_tooltip_markup(tooltip % tooltip_status)
        if not success:
            combo = gtk.combo_box_new_text()
            combo.child.modify_font(pango.FontDescription('CrashNumberingGothic'))
            combo.set_size_request(-1, 28)
            for number in failure:
                combo.append_text(str(number))
            combo.set_active(0)
            hbox.pack_start(combo, False, False)
            relog = gtk.EventBox()
            relog.add(gtk.image_new_from_pixbuf(gtk.gdk.pixbuf_new_from_file(ICON_PATH + '/refresh.png').scale_simple(28, 28, gtk.gdk.INTERP_HYPER)))
            relog.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#FFFFFF'))
            relog.set_tooltip_text('Retry by setting\n   new cookie')
            hbox.pack_start(relog, False, False)
            def set_cursor(unused_widget, unused_event):
                relog.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2))
            def unset_cursor(unused_widget, unused_event):
                relog.window.set_cursor(None)
            def re_log_in(unused_widget, unused_event):
                from way2sms import login
                import time
                database = DataBase()
                user = database.get_default()
                thread.start_new_thread(login, (str(user[0]), user[1], True))
                database.close()
                time.sleep(3.4)
                self.__generalize_status_bar()
                self.__push_status_message('<span font_desc="belgrano 10"><b>  Try to <span foreground="#0000FF">re send</span> once more</b></span>')
                return
            relog.connect('enter_notify_event', set_cursor)
            relog.connect('leave_notify_event', unset_cursor)
            relog.connect('button_release_event', re_log_in)
        alignment = gtk.Alignment(0, 0, 0, 1)
        frame.remove(hbox)
        frame.add(alignment)
        alignment.add(hbox)
        self.status_bar.show_all()

    def __push_status_message(self, message):
        self.status_bar.get_children()[0].child.get_children()[0].set_markup(message)
        self.status_bar.get_children()[0].child.get_children()[0].set_tooltip_markup(message)

    def __clear(self, unused, buffer):
        self.__generalize_status_bar()
        buffer.set_text('')
        self.__push_status_message('')
        return False

    def __check_send_status(self, button, status, receiver, message):
        flag = True
        for key in status.keys():
            if not status[key][1]:
                flag = False
                break
        if flag:
            button.set_sensitive(True)
            self.__spnnier.stop()
            failure = []
            for key in status.keys():
                if not status[key][0]:
                    failure.append(key)
            self.__generalize_status_bar()
            if not failure:
                self.__custom_status(True)
            else:
                self.__custom_status(False, failure)
            for failed in failure:
                receiver.remove(failed)
            if receiver:
                database = DataBase()
                database.save_message(message, receiver, time_stamp())
                database.close()
            return False
        return True

    def __send_message(self, number, message, status):
        from way2sms import send
        import time
        database = DataBase()
        customer_id = database.get_default()[2]
        for text in message:
            text = text.strip()
            status[number][0] = status[number][0] and send(customer_id, number, text)
            time.sleep(1.4)
        status[number][1] = True
        return

    def __sending_status(self, status):
        message = '<span font_desc="belgrano 10" foreground="#F654CA"><b>  ' +  status  + '  </b></span>'
        frame = self.status_bar.get_children()[0]
        hbox = self.status_bar.get_children()[0].child
        label = self.status_bar.get_children()[0].child.get_children()[0]
        label.set_ellipsize(False)
        frame.hide_all()
        hbox.remove(label)
        label.set_markup(message)
        label.set_tooltip_markup(message)
        from spinner import Spin
        self.__spnnier = Spin('', 100, 24, 24, 2.6, 8)
        hbox.pack_start(label, True, True)
        hbox.pack_start(self.__spnnier, True, True)
        alignment = gtk.Alignment(0, 0, 0, 1)
        frame.remove(hbox)
        frame.add(alignment)
        alignment.add(hbox)
        self.status_bar.show_all()
        self.__spnnier.start()
        return True

    def __send(self, button, buffer):
        self.__generalize_status_bar()
        text = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter()).strip().expandtabs(4)
        message = format_message(text)
        for index in range(len(message)):
            if index != len(message) - 1:
                message[index] = message[index].rstrip() + '\n- #%d' % (index + 1)
        if not message:
            self.__push_status_message('<span font_desc="belgrano 10"><span foreground="#FF0000"><b>  No message</b></span> to send</span>')
            return False
        if not len(self._receiver):
            self.__push_status_message('<span font_desc="belgrano 10">  <span foreground="#FF0000"><b>No receiver</b></span> selected for your message</span>')
            return False
        status = {}
        button.set_sensitive(False)
        self.__sending_status('Sending Message')
        for contact in self._receiver:
            status[contact] = [True, False]
            thread.start_new_thread(self.__send_message, (contact, message, status))
        gobject.timeout_add(180, self.__check_send_status, button, status, self._receiver, text)
        return False

    def __current_char(self, buffer, size, error):
        self.spell_check_enable = False
        self.__generalize_status_bar()
        message = "<span font_desc='belgrano 10'>  Message contains <span font_desc='CrashNumberingGothic 10' foreground='#4C8AF1'><b><i>%d</i></b></span> \
character(s)</span>" % buffer.get_char_count()
        self.__push_status_message(message)
        buffer.apply_tag(size, buffer.get_start_iter(), buffer.get_end_iter())
        buffer.remove_tag(error, buffer.get_start_iter(), buffer.get_end_iter())