1
'''a module that contains a class that describes a adium theme'''
2
# -*- coding: utf-8 -*-
4
# This file is part of emesene.
6
# emesene is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 3 of the License, or
9
# (at your option) any later version.
11
# emesene is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
# GNU General Public License for more details.
16
# You should have received a copy of the GNU General Public License
17
# along with emesene; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
import xml.sax.saxutils
29
class AdiumTheme(object):
30
'''a class that contains information of a adium theme
33
def __init__(self, path, timefmt):
36
get information from the theme located in path
38
self.timefmt = timefmt
40
self.resources_path = None
41
self.incoming_path = None
42
self.outgoing_path = None
45
self.incoming_next = None
47
self.outgoing_next = None
50
self.load_information(path)
52
def load_information(self, path):
53
'''load the information of the theme on path
57
info_file = file(os.path.join(path, 'Contents', 'Info.plist'))
58
self.info = parsers.Plist(info_file).info
60
self.resources_path = os.path.join(path, 'Contents', 'Resources')
61
self.incoming_path = os.path.join(self.resources_path, 'Incoming')
62
self.outgoing_path = os.path.join(self.resources_path, 'Outgoing')
64
self.content = read_file(self.resources_path, 'Content.html')
66
self.incoming = read_file(self.incoming_path, 'Content.html')
67
self.incoming_next = read_file(self.incoming_path,
70
self.outgoing = read_file(self.outgoing_path, 'Content.html')
71
self.outgoing_next = read_file(self.outgoing_path,
74
def format_incoming(self, msg, style=None, cedict={}, cedir=None):
75
'''return a string containing the template for the incoming message
76
with the vars replaced
78
# fallback madness, some repetition but well..
80
if self.incoming_next is None:
81
if self.incoming is None:
82
template = self.content
84
template = self.incoming
86
template = self.incoming_next
87
elif self.incoming is None:
88
template = self.content
90
template = self.incoming
92
return self.replace(template, msg, style, cedict, cedir)
94
def format_outgoing(self, msg, style=None, cedict={}, cedir=None):
95
'''return a string containing the template for the outgoing message
96
with the vars replaced
98
# fallback madness, some repetition but well..
100
if self.outgoing_next is None:
101
if self.outgoing is None:
102
if self.incoming is None:
103
template = self.content
105
template = self.incoming
107
template = self.outgoing
109
template = self.outgoing_next
110
elif self.outgoing is None:
111
if self.incoming is None:
112
template = self.content
114
template = self.incoming
116
template = self.outgoing
118
return self.replace(template, msg, style, cedict, cedir)
120
def replace(self, template, msg, style=None, cedict={}, cedir=None):
121
'''replace the variables on template for the values on msg
124
msgtext = MarkupParser.replace_emotes(escape(msg.message), cedict, cedir, msg.sender)
125
msgtext = MarkupParser.urlify(msgtext)
127
if style is not None:
128
msgtext = style_message(msgtext, style)
130
template = template.replace('%sender%', escape(msg.alias))
131
template = template.replace('%senderScreenName%', escape(msg.sender))
132
template = template.replace('%senderDisplayName%',
133
escape(msg.display_name))
134
template = template.replace('%userIconPath%', escape(msg.image_path))
135
template = template.replace('%senderStatusIcon%',
136
escape(msg.status_path))
137
template = template.replace('%messageDirection%',
138
escape(msg.direction))
139
template = template.replace('%message%', msgtext)
141
if msg.timestamp is None:
142
template = template.replace('%time%',
143
escape(time.strftime(self.timefmt)))
146
secs = calendar.timegm(t)
147
return time.localtime(secs)
148
l_time = utc_to_local(msg.timestamp.timetuple()) #time.struct_time
149
d_time = datetime.datetime.fromtimestamp(time.mktime(l_time))
150
template = template.replace('%time%',
151
escape(d_time.strftime('%x %X')))
153
template = re.sub("%time{(.*?)}%", replace_time, template)
154
template = template.replace('%shortTime%',
155
escape(time.strftime("%H:%M")))
156
template = template.replace('%service%', escape(msg.service))
157
template = template.replace('%messageClasses%', escape(msg.classes))
158
template = template.replace('%status%', escape(msg.status))
160
return template.replace('\n', '')
162
def replace_header_or_footer(self, template, source, target,
163
target_display, source_img, target_img):
164
'''replace the variables on template for the parameters
166
template = template.replace('%chatName%', escape(target))
167
template = template.replace('%sourceName%', escape(source))
168
template = template.replace('%destinationName%', escape(target))
169
template = template.replace('%destinationDisplayName%',
170
escape(target_display))
171
template = template.replace('%incomingIconPath%', escape(target_img))
172
template = template.replace('%outgoingIconPath%', escape(source_img))
173
template = template.replace('%timeOpened%',
174
escape(time.strftime("%H:%M")))
175
# TODO: use the format inside the {}
176
template = re.sub("%timeOpened{.*?}%", escape(time.strftime("%H:%M")),
181
def get_body(self, source, target, target_display, source_img, target_img):
182
'''return the template to put as html content
184
template = read_file(os.path.join("gui", "base", "template.html"))
185
css_path = "file://" + os.path.join(self.resources_path, "main.css")
186
variant_name = self.info.get('DefaultVariant', None)
187
template = template.replace("%@", "file://" + self.resources_path + "/", 1)
188
template = template.replace("%@", css_path, 1)
190
if variant_name is not None:
191
variant_css_path = "file://" + os.path.join(self.resources_path,
192
"Variants", variant_name + ".css")
193
variant_tag = '<style id="mainStyle" type="text/css"' + \
194
'media="screen,print"> @import url( "' + variant_css_path + '" ); </style>'
198
template = template.replace("%@", variant_tag, 1)
200
header = read_file(self.resources_path, 'Header.html') or ""
203
header = self.replace_header_or_footer(header, source, target,
204
target_display, source_img, target_img)
206
template = template.replace("%@", header, 1)
207
footer = read_file(self.resources_path, 'Footer.html') or ""
210
footer = self.replace_header_or_footer(footer, source, target,
211
target_display, source_img, target_img)
213
template = template.replace("%@", footer, 1)
217
def read_file(*args):
218
'''read file if exists and is readable, return None otherwise
220
path = os.path.join(*args)
221
if os.access(path, os.R_OK):
222
return file(path).read()
230
'\r\n': '<br>', #windows
242
'''replace the values on dic keys with the values'''
243
return xml.sax.saxutils.escape(string_, __dic)
245
def unescape(string_):
246
'''replace the values on dic_inv keys with the values'''
247
return xml.sax.saxutils.unescape(string_, __dic_inv)
249
def replace_time(match):
250
'''replace the format of the time to it's value'''
251
return time.strftime(match.groups()[0])
253
def style_message(msgtext, style):
254
'''add html markupt to msgtext to format the style of the message'''
255
return '<span style="%s">%s</span>' % (style.to_css(), msgtext)