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
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())