-import gobject
-import pango
-import gtk
-
-import gtk_toolbox
-import hildonize
-from backends import gv_backend
-from backends import null_backend
-
-
-_moduleLogger = logging.getLogger("gv_views")
-
-
-def make_ugly(prettynumber):
- """
- function to take a phone number and strip out all non-numeric
- characters
-
- >>> make_ugly("+012-(345)-678-90")
- '+01234567890'
- """
- return normalize_number(prettynumber)
-
-
-def normalize_number(prettynumber):
- """
- function to take a phone number and strip out all non-numeric
- characters
-
- >>> normalize_number("+012-(345)-678-90")
- '+01234567890'
- >>> normalize_number("1-(345)-678-9000")
- '+13456789000'
- >>> normalize_number("+1-(345)-678-9000")
- '+13456789000'
- """
- uglynumber = re.sub('[^0-9+]', '', prettynumber)
- if uglynumber.startswith("+"):
- pass
- elif uglynumber.startswith("1") and len(uglynumber) == 11:
- uglynumber = "+"+uglynumber
- elif len(uglynumber) == 10:
- uglynumber = "+1"+uglynumber
- else:
- pass
-
- #validateRe = re.compile("^\+?[0-9]{10,}$")
- #assert validateRe.match(uglynumber) is not None
-
- return uglynumber
-
-
-def _make_pretty_with_areacodde(phonenumber):
- prettynumber = "(%s)" % (phonenumber[0:3], )
- if 3 < len(phonenumber):
- prettynumber += " %s" % (phonenumber[3:6], )
- if 6 < len(phonenumber):
- prettynumber += "-%s" % (phonenumber[6:], )
- return prettynumber
-
-
-def _make_pretty_local(phonenumber):
- prettynumber = "%s" % (phonenumber[0:3], )
- if 3 < len(phonenumber):
- prettynumber += "-%s" % (phonenumber[3:], )
- return prettynumber
-
-
-def _make_pretty_international(phonenumber):
- prettynumber = phonenumber
- if phonenumber.startswith("0"):
- prettynumber = "+%s " % (phonenumber[0:3], )
- if 3 < len(phonenumber):
- prettynumber += _make_pretty_with_areacodde(phonenumber[3:])
- if phonenumber.startswith("1"):
- prettynumber = "1 "
- prettynumber += _make_pretty_with_areacodde(phonenumber[1:])
- return prettynumber
-
-
-def make_pretty(phonenumber):
- """
- Function to take a phone number and return the pretty version
- pretty numbers:
- if phonenumber begins with 0:
- ...-(...)-...-....
- if phonenumber begins with 1: ( for gizmo callback numbers )
- 1 (...)-...-....
- if phonenumber is 13 digits:
- (...)-...-....
- if phonenumber is 10 digits:
- ...-....
- >>> make_pretty("12")
- '12'
- >>> make_pretty("1234567")
- '123-4567'
- >>> make_pretty("2345678901")
- '+1 (234) 567-8901'
- >>> make_pretty("12345678901")
- '+1 (234) 567-8901'
- >>> make_pretty("01234567890")
- '+012 (345) 678-90'
- >>> make_pretty("+01234567890")
- '+012 (345) 678-90'
- >>> make_pretty("+12")
- '+1 (2)'
- >>> make_pretty("+123")
- '+1 (23)'
- >>> make_pretty("+1234")
- '+1 (234)'
- """
- if phonenumber is None or phonenumber is "":
- return ""
-
- phonenumber = normalize_number(phonenumber)
-
- if phonenumber[0] == "+":
- prettynumber = _make_pretty_international(phonenumber[1:])
- if not prettynumber.startswith("+"):
- prettynumber = "+"+prettynumber
- elif 8 < len(phonenumber) and phonenumber[0] in ("0", "1"):
- prettynumber = _make_pretty_international(phonenumber)
- elif 7 < len(phonenumber):
- prettynumber = _make_pretty_with_areacodde(phonenumber)
- elif 3 < len(phonenumber):
- prettynumber = _make_pretty_local(phonenumber)
- else:
- prettynumber = phonenumber
- return prettynumber.strip()
-
-
-def abbrev_relative_date(date):
- """
- >>> abbrev_relative_date("42 hours ago")
- '42 h'
- >>> abbrev_relative_date("2 days ago")
- '2 d'
- >>> abbrev_relative_date("4 weeks ago")
- '4 w'
- """
- parts = date.split(" ")
- return "%s %s" % (parts[0], parts[1][0])
-
-
-def _collapse_message(messageLines, maxCharsPerLine, maxLines):
- lines = 0
-
- numLines = len(messageLines)
- for line in messageLines[0:min(maxLines, numLines)]:
- linesPerLine = max(1, int(len(line) / maxCharsPerLine))
- allowedLines = maxLines - lines
- acceptedLines = min(allowedLines, linesPerLine)
- acceptedChars = acceptedLines * maxCharsPerLine
-
- if acceptedChars < (len(line) + 3):
- suffix = "..."
- else:
- acceptedChars = len(line) # eh, might as well complete the line
- suffix = ""
- abbrevMessage = "%s%s" % (line[0:acceptedChars], suffix)
- yield abbrevMessage
-
- lines += acceptedLines
- if maxLines <= lines:
- break
-
-
-def collapse_message(message, maxCharsPerLine, maxLines):
- r"""
- >>> collapse_message("Hello", 60, 2)
- 'Hello'
- >>> collapse_message("Hello world how are you doing today? 01234567890123456789012345678901234567890123456789012345678901234567890123456789", 60, 2)
- 'Hello world how are you doing today? 01234567890123456789012...'
- >>> collapse_message('''Hello world how are you doing today?
- ... 01234567890123456789
- ... 01234567890123456789
- ... 01234567890123456789
- ... 01234567890123456789''', 60, 2)
- 'Hello world how are you doing today?\n01234567890123456789'
- >>> collapse_message('''
- ... Hello world how are you doing today? 01234567890123456789012345678901234567890123456789012345678901234567890123456789
- ... Hello world how are you doing today? 01234567890123456789012345678901234567890123456789012345678901234567890123456789
- ... Hello world how are you doing today? 01234567890123456789012345678901234567890123456789012345678901234567890123456789
- ... Hello world how are you doing today? 01234567890123456789012345678901234567890123456789012345678901234567890123456789
- ... Hello world how are you doing today? 01234567890123456789012345678901234567890123456789012345678901234567890123456789
- ... Hello world how are you doing today? 01234567890123456789012345678901234567890123456789012345678901234567890123456789''', 60, 2)
- '\nHello world how are you doing today? 01234567890123456789012...'
- """
- messageLines = message.split("\n")
- return "\n".join(_collapse_message(messageLines, maxCharsPerLine, maxLines))
-
-
-class SmsEntryWindow(object):
-
- MAX_CHAR = 160
-
- def __init__(self, widgetTree):
- self._clipboard = gtk.clipboard_get()
- self._widgetTree = widgetTree
- self._window = self._widgetTree.get_widget("smsWindow")
- self._window.connect("delete-event", self._on_delete)
- self._window.connect("key-press-event", self._on_key_press)
-
- self._smsButton = self._widgetTree.get_widget("sendSmsButton")
- self._smsButton.connect("clicked", self._on_send)
- self._dialButton = self._widgetTree.get_widget("dialButton")
- self._dialButton.connect("clicked", self._on_dial)
-
- self._letterCountLabel = self._widgetTree.get_widget("smsLetterCount")
-
- self._messagemodel = gtk.ListStore(gobject.TYPE_STRING)
- self._messagesView = self._widgetTree.get_widget("smsMessages")
-
- textrenderer = gtk.CellRendererText()
- textrenderer.set_property("wrap-mode", pango.WRAP_WORD)
- textrenderer.set_property("wrap-width", 450)
- messageColumn = gtk.TreeViewColumn("")
- messageColumn.pack_start(textrenderer, expand=True)
- messageColumn.add_attribute(textrenderer, "markup", 0)
- messageColumn.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
- self._messagesView.append_column(messageColumn)
- self._messagesView.set_headers_visible(False)
- self._messagesView.set_model(self._messagemodel)
- self._messagesView.set_fixed_height_mode(False)
-
- self._conversationView = self._messagesView.get_parent()
- self._conversationViewPort = self._conversationView.get_parent()
- self._scrollWindow = self._conversationViewPort.get_parent()
-
- self._targetList = self._widgetTree.get_widget("smsTargetList")
- self._phoneButton = self._widgetTree.get_widget("phoneTypeSelection")
- self._phoneButton.connect("clicked", self._on_phone)
- self._smsEntry = self._widgetTree.get_widget("smsEntry")
- self._smsEntry.get_buffer().connect("changed", self._on_entry_changed)
- self._smsEntrySize = None
-
- self._numberIndex = -1
- self._contacts = []
-
- def add_contact(self, contactDetails, messages = (), parent = None, defaultIndex = -1):
- contactNumbers = list(self._to_contact_numbers(contactDetails))
- assert contactNumbers
- contactIndex = defaultIndex if defaultIndex != -1 else 0
- contact = contactNumbers, contactIndex, messages
- self._contacts.append(contact)
-
- selector = gtk.Button(contactNumbers[0][1])
- #selector.connect("clicked", , len(self._contacts)) TODO
- removeContact = gtk.Button(stock="gtk-delete")
- #removeContact.connect("clicked", , len(self._contacts)) TODO
- row = gtk.HBox()
- row.pack_start(selector, True, True)
- row.pack_start(removeContact, False, False)
- row.show_all()
- # @bug List appears to be coming up backwards
- self._targetList.pack_end(row)
- self._update_button_state()
- self._update_context()
-
- if parent is not None:
- parentSize = parent.get_size()
- self._window.resize(parentSize[0], max(parentSize[1]-10, 100))
- self._window.show()
- self._window.present()
-
- self._smsEntry.grab_focus()
- dx = self._conversationView.get_allocation().height - self._conversationViewPort.get_allocation().height
- dx = max(dx, 0)
- adjustment = self._scrollWindow.get_vadjustment()
- adjustment.value = dx
-
- def clear(self):
- del self._contacts[:]
-
- for contactNumberSelector in list(self._targetList.get_children()):
- self._targetList.remove(contactNumberSelector)
- self._smsEntry.get_buffer().set_text("")
- self._update_letter_count()
- self._update_context()
-
- def _remove_contact(self, contactIndex):
- del self._contacts[contactIndex]
-
- contactNumberSelector = list(self._targetList.get_children())[contactIndex]
- self._targetList.remove(contactNumberSelector)
- self._update_button_state()
- self._update_context()
-
- def _update_letter_count(self):
- if self._smsEntrySize is None:
- self._smsEntrySize = self._smsEntry.size_request()
- else:
- self._smsEntry.set_size_request(*self._smsEntrySize)
- entryLength = self._smsEntry.get_buffer().get_char_count()
-
- numTexts, numCharInText = divmod(entryLength, self.MAX_CHAR)
- if numTexts:
- self._letterCountLabel.set_text("%s.%s" % (numTexts, numCharInText))
- else:
- self._letterCountLabel.set_text("%s" % (numCharInText, ))
-
- self._update_button_state()
-
- def _update_context(self):
- self._messagemodel.clear()
- if len(self._contacts) == 0:
- self._messagesView.hide()
- self._targetList.hide()
- self._phoneButton.hide()
- self._phoneButton.set_label("Error: You shouldn't see this")
- elif len(self._contacts) == 1:
- contactNumbers, index, messages = self._contacts[0]
- if messages:
- self._messagesView.show()
- for message in messages:
- row = (message, )
- self._messagemodel.append(row)
- messagesSelection = self._messagesView.get_selection()
- messagesSelection.select_path((len(messages)-1, ))
- else:
- self._messagesView.hide()
- self._targetList.hide()
- self._phoneButton.show()
- self._phoneButton.set_label(contactNumbers[index][1])
- if 1 < len(contactNumbers):
- self._phoneButton.set_sensitive(True)
- else:
- self._phoneButton.set_sensitive(False)
- else:
- self._messagesView.hide()
- self._targetList.show()
- self._phoneButton.hide()
- self._phoneButton.set_label("Error: You shouldn't see this")
-
- def _update_button_state(self):
- if len(self._contacts) == 0:
- self._dialButton.set_sensitive(False)
- self._smsButton.set_sensitive(False)
- elif len(self._contacts) == 1:
- entryLength = self._smsEntry.get_buffer().get_char_count()
- if entryLength == 0:
- self._dialButton.set_sensitive(True)
- self._smsButton.set_sensitive(False)
- else:
- self._dialButton.set_sensitive(False)
- self._smsButton.set_sensitive(True)
- else:
- self._dialButton.set_sensitive(False)
- self._smsButton.set_sensitive(True)
-
- def _to_contact_numbers(self, contactDetails):
- for phoneType, phoneNumber in contactDetails:
- display = " - ".join((make_pretty(phoneNumber), phoneType))
- yield (phoneNumber, display)
-
- def _request_number(self):
- try:
- assert 0 <= self._numberIndex, "%r" % self._numberIndex