~jconti/recent-notifications/trunk

« back to all changes in this revision

Viewing changes to unity/MessageItem.py

  • Committer: Jason Conti
  • Date: 2011-04-24 20:48:00 UTC
  • Revision ID: jason.conti@gmail.com-20110424204800-znrodggqqte9nvxb
Ported Config.py to the unity app, promoting it to a proper GObject in the process, so value changes are handled by signals instead of calling functions. Adding a basic set of tests for the new Config class. Adding __init__.py to unity to make it a proper module for testing (will need renaming later). Changed the edge radius to 5px for the message icon.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""
 
2
MessageItem.py
 
3
March 28, 2011
 
4
 
 
5
A widget to represent a notification.
 
6
"""
 
7
 
 
8
import logging
 
9
 
 
10
from gi.repository import GLib, GObject, Gtk, Pango
 
11
 
 
12
import Icon
 
13
import Timestamp
 
14
 
 
15
from RoundedWidgets import RoundedBox, RoundedIcon
 
16
from Translations import _
 
17
 
 
18
logger = logging.getLogger("MessageItem")
 
19
 
 
20
def create_label():
 
21
  label = Gtk.Label()
 
22
  label.set_use_markup(True)
 
23
  label.set_selectable(True)
 
24
  label.set_line_wrap(True)
 
25
  label.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR)
 
26
  label.set_alignment(0, 0)
 
27
  label.set_size_request(300, -1)
 
28
  return label
 
29
 
 
30
def escape_text(text):
 
31
  return GLib.markup_escape_text(text, len(text))
 
32
 
 
33
class MessageItem(RoundedBox):
 
34
  """A widget to represent a notification"""
 
35
  def __init__(self, message):
 
36
    RoundedBox.__init__(self)
 
37
 
 
38
    self.set_border_width(2)
 
39
 
 
40
    self._unread = True
 
41
 
 
42
    self._message = message
 
43
    self._message_icon_size = 48
 
44
 
 
45
    self._hbox = Gtk.HBox()
 
46
    self._hbox.set_border_width(10)
 
47
    self.add(self._hbox)
 
48
 
 
49
    self._image = RoundedIcon(radius = 5)
 
50
    self._hbox.pack_start(self._image, False, False, 10)
 
51
    self.update_image()
 
52
 
 
53
    self._vbox = Gtk.VBox()
 
54
    self._hbox.pack_start(self._vbox, True, True, 0)
 
55
 
 
56
    self._summary_hbox = Gtk.HBox()
 
57
    self._vbox.pack_start(self._summary_hbox, False, False, 1)
 
58
 
 
59
    self._image_unread = Gtk.Image()
 
60
    self._summary_hbox.pack_start(self._image_unread, False, False, 5)
 
61
 
 
62
    try:
 
63
      pixbuf = Icon.load("notification-new", 16)
 
64
    except:
 
65
      logger.exception("Failed to load notification-new icon.")
 
66
    else:
 
67
      self._image_unread.set_from_pixbuf(pixbuf)
 
68
 
 
69
    self._label_summary = create_label()
 
70
    self._summary_hbox.pack_start(self._label_summary, True, True, 0)
 
71
 
 
72
    self._label_body = create_label()
 
73
    self._vbox.pack_start(self._label_body, True, True, 1)
 
74
 
 
75
    self._label_info = create_label()
 
76
    self._vbox.pack_start(self._label_info, False, False, 0)
 
77
    self.update_labels()
 
78
 
 
79
  def get_app_name(self):
 
80
    """Returns the app_name of this item"""
 
81
    return self._message.app_name
 
82
 
 
83
  def escape_body(self, text):
 
84
    """Text needs to be escaped in case it contains characters that will cause errors
 
85
    parsing the markup, but some clients send text that is already escaped. This causes
 
86
    messages to have &, <, and > strings instead of the appropriate characters.
 
87
    This method replaces those with the appropriate characters and then escapes the text.
 
88
    TODO: Create a better HTML/entity parser. 
 
89
    """
 
90
    result = text.replace("&", "&")
 
91
    result = result.replace("'", "'")
 
92
    result = result.replace(">", ">")
 
93
    result = result.replace("&lt;", "<")
 
94
    result = result.replace("&quot;", '"')
 
95
    return self.markup_links(escape_text(result))
 
96
 
 
97
  def is_unread(self):
 
98
    """Get the unread status of this message"""
 
99
    return self._unread
 
100
 
 
101
  def set_unread(self, unread):
 
102
    """Sets the unread status of this messages and the visibility of the icon"""
 
103
    if unread and not self._unread:
 
104
      self._unread = True
 
105
      self._image_unread.show()
 
106
      self._summary_hbox.pack_start(self._image_unread, False, False, 5)
 
107
      self._summary_hbox.reorder_child(self._image_unread, 0)
 
108
 
 
109
    elif not unread and self._unread:
 
110
      self._unread = False
 
111
      self._image_unread.hide()
 
112
      self._summary_hbox.remove(self._image_unread)
 
113
 
 
114
  def set_width(self, width):
 
115
    """Updates the wrap width of the labels in this message item, minus the icon
 
116
    size and various padding."""
 
117
    new_width = width - self._message_icon_size - 60
 
118
    self._label_summary.set_size_request(new_width, -1)
 
119
    self._label_body.set_size_request(new_width, -1)
 
120
    self._label_info.set_size_request(new_width, -1)
 
121
 
 
122
  def markup_links(self, text):
 
123
    """Filters escaped text for web links and makes them clickable"""
 
124
    result = []
 
125
    for s in text.split():
 
126
      if s.startswith("http://"):
 
127
        name = s
 
128
        url = s
 
129
        result.append('<a href="{0}">{1}</a>'.format(url, name))
 
130
      elif s.startswith("www."):
 
131
        name = s
 
132
        url = "http://" + s
 
133
        result.append('<a href="{0}">{1}</a>'.format(url, name))
 
134
      else:
 
135
        result.append(s)
 
136
 
 
137
    return " ".join(result)
 
138
 
 
139
  def update_image(self):
 
140
    """Updates the image"""
 
141
    try:
 
142
      pixbuf = self._message.get_icon(self._message_icon_size)
 
143
    except:
 
144
      logger.exception("Failed to get icon: {0}".format(self._message.app_icon))
 
145
    else:
 
146
      self._image.set_from_pixbuf(pixbuf)
 
147
 
 
148
  def update_labels(self):
 
149
    """Updates the label markup"""
 
150
    summary = escape_text(self._message.summary.encode("utf8"))
 
151
    body = self.escape_body(self._message.body.encode("utf8"))
 
152
    timestamp = escape_text(Timestamp.locale_datetime(self._message.timestamp))
 
153
    app_name = escape_text(self._message.app_name)
 
154
 
 
155
    self._label_summary.set_markup("<b>{0}</b>".format(summary))
 
156
    self._label_body.set_markup(body)
 
157
    self._label_info.set_markup("<small><i>{0} {1} <b>{2}</b></i></small>".format(timestamp,
 
158
      _("from"), app_name))
 
159