Commit c4fd67f1 authored by Yann Leboulanger's avatar Yann Leboulanger

merge diff from trunk

parent 6e2faf7c
......@@ -5,10 +5,14 @@ Gajim 0.11.1 (XX February 2007)
* Fix International Domain Name usage
* Fix when removing active privacy list
* Fix problem with adhoc command and multi-step forms
* Fixed avatars cache problems in group chats
* KDE integration for XMPP URI
* Support of Banshee Music player
* Support of XEP-0202 (Entity Time)
* Support of XEP-0199 (XMPP Ping)
Gajim 0.11 (19 December 2006)
* New build system, using GNU autotools. See README.html
* Support for link-local messaging via Zeroconf using Avahi (XEP-0174)
* Automatically connect and disconnect to accounts according to network availability (if Network Manager is present)
......
......@@ -2,10 +2,12 @@ Gajim 0.11.1 (XX February 2007)
* Fixes in gajim-remote and the way XMPP URI are handled
* Fix Idle under Windows
* Fix Gajim under non-ascii languages Windows
* Fix International Domain Name usage
* Fix when removing active privacy list
* Fix problem with adhoc command and multi-step forms
* KDE integration for XMPP URI
* Support of XEP-0202 (Entity Time)
* Support of XEP-0199 (XMPP Ping)
Gajim 0.11 (19 December 2006)
* New build system, using GNU autotools. See README.html
......
......@@ -40,6 +40,7 @@ emoticons = {
'(*)': 'star.png',
'B-)': 'coolglasses.png',
'(Z)': 'boy.png',
'(X)': 'girl.png',
'(E)': 'mail.png',
'(N)': 'thumbdown.png',
'(P)': 'photo.png',
......
......@@ -66,6 +66,7 @@ emoticons = {
'(6)': 'devil.png',
'(W)': 'brflower.png',
'(Z)': 'boy.png',
'(X)': 'girl.png',
'(E)': 'mail.png',
'(N)': 'thumbdown.png',
'(P)': 'photo.png',
......
......@@ -66,6 +66,7 @@ emoticons = {
'(6)': 'devil.png',
'(W)': 'brflower.png',
'(Z)': 'boy.png',
'(X)': 'girl.png',
'(E)': 'mail.png',
'(N)': 'thumbdown.png',
'(P)': 'photo.png',
......
data/iconsets/sun/16x16/away.png

724 Bytes | W: | H:

data/iconsets/sun/16x16/away.png

875 Bytes | W: | H:

data/iconsets/sun/16x16/away.png
data/iconsets/sun/16x16/away.png
data/iconsets/sun/16x16/away.png
data/iconsets/sun/16x16/away.png
  • 2-up
  • Swipe
  • Onion skin
data/iconsets/sun/16x16/chat.png

454 Bytes | W: | H:

data/iconsets/sun/16x16/chat.png

928 Bytes | W: | H:

data/iconsets/sun/16x16/chat.png
data/iconsets/sun/16x16/chat.png
data/iconsets/sun/16x16/chat.png
data/iconsets/sun/16x16/chat.png
  • 2-up
  • Swipe
  • Onion skin
data/iconsets/sun/16x16/dnd.png

381 Bytes | W: | H:

data/iconsets/sun/16x16/dnd.png

856 Bytes | W: | H:

data/iconsets/sun/16x16/dnd.png
data/iconsets/sun/16x16/dnd.png
data/iconsets/sun/16x16/dnd.png
data/iconsets/sun/16x16/dnd.png
  • 2-up
  • Swipe
  • Onion skin
data/iconsets/sun/16x16/error.png

412 Bytes | W: | H:

data/iconsets/sun/16x16/error.png

831 Bytes | W: | H:

data/iconsets/sun/16x16/error.png
data/iconsets/sun/16x16/error.png
data/iconsets/sun/16x16/error.png
data/iconsets/sun/16x16/error.png
  • 2-up
  • Swipe
  • Onion skin
data/iconsets/sun/16x16/invisible.png

407 Bytes | W: | H:

data/iconsets/sun/16x16/invisible.png

911 Bytes | W: | H:

data/iconsets/sun/16x16/invisible.png
data/iconsets/sun/16x16/invisible.png
data/iconsets/sun/16x16/invisible.png
data/iconsets/sun/16x16/invisible.png
  • 2-up
  • Swipe
  • Onion skin
data/iconsets/sun/16x16/not_in_roster.png

301 Bytes | W: | H:

data/iconsets/sun/16x16/not_in_roster.png

680 Bytes | W: | H:

data/iconsets/sun/16x16/not_in_roster.png
data/iconsets/sun/16x16/not_in_roster.png
data/iconsets/sun/16x16/not_in_roster.png
data/iconsets/sun/16x16/not_in_roster.png
  • 2-up
  • Swipe
  • Onion skin
data/iconsets/sun/16x16/offline.png

417 Bytes | W: | H:

data/iconsets/sun/16x16/offline.png

657 Bytes | W: | H:

data/iconsets/sun/16x16/offline.png
data/iconsets/sun/16x16/offline.png
data/iconsets/sun/16x16/offline.png
data/iconsets/sun/16x16/offline.png
  • 2-up
  • Swipe
  • Onion skin
data/iconsets/sun/16x16/online.png

458 Bytes | W: | H:

data/iconsets/sun/16x16/online.png

880 Bytes | W: | H:

data/iconsets/sun/16x16/online.png
data/iconsets/sun/16x16/online.png
data/iconsets/sun/16x16/online.png
data/iconsets/sun/16x16/online.png
  • 2-up
  • Swipe
  • Onion skin
data/iconsets/sun/16x16/requested.png

581 Bytes | W: | H:

data/iconsets/sun/16x16/requested.png

886 Bytes | W: | H:

data/iconsets/sun/16x16/requested.png
data/iconsets/sun/16x16/requested.png
data/iconsets/sun/16x16/requested.png
data/iconsets/sun/16x16/requested.png
  • 2-up
  • Swipe
  • Onion skin
data/iconsets/sun/16x16/xa.png

371 Bytes | W: | H:

data/iconsets/sun/16x16/xa.png

877 Bytes | W: | H:

data/iconsets/sun/16x16/xa.png
data/iconsets/sun/16x16/xa.png
data/iconsets/sun/16x16/xa.png
data/iconsets/sun/16x16/xa.png
  • 2-up
  • Swipe
  • Onion skin
data/iconsets/sun/48x48/offline.png

417 Bytes | W: | H:

data/iconsets/sun/48x48/offline.png

2.05 KB | W: | H:

data/iconsets/sun/48x48/offline.png
data/iconsets/sun/48x48/offline.png
data/iconsets/sun/48x48/offline.png
data/iconsets/sun/48x48/offline.png
  • 2-up
  • Swipe
  • Onion skin
data/iconsets/sun/48x48/online.png

458 Bytes | W: | H:

data/iconsets/sun/48x48/online.png

3.89 KB | W: | H:

data/iconsets/sun/48x48/online.png
data/iconsets/sun/48x48/online.png
data/iconsets/sun/48x48/online.png
data/iconsets/sun/48x48/online.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -2,16 +2,16 @@ Source: gajim
Section: net
Priority: optional
Maintainer: Yann Le Boulanger <asterix@lagaule.org>
Build-Depends: debhelper (>= 5.0.37.2), cdbs (>= 0.4.43), python-support (>= 0.3), python2.4-dev, libgtk2.0-dev, python-gtk2-dev, libgtkspell-dev, gettext, libxss-dev, intltool, imagemagick, python-central (>= 0.5)
Build-Depends: debhelper (>= 5.0.37.2), cdbs (>= 0.4.43), python-support (>= 0.3), python-dev, libgtk2.0-dev, python-gtk2-dev, libgtkspell-dev, gettext, libxss-dev, intltool, imagemagick, python-central (>= 0.5)
Build-Conflicts: python2.3
XS-Python-Version: 2.4
XS-Python-Version: >= 2.4
Standards-Version: 3.7.2
Package: gajim
Architecture: any
XB-Python-Version: ${python:Versions}
Depends: ${python:Depends}, python2.4, python-glade2 (>= 2.6.0), python-gtk2 (>= 2.6.0), python2.4-pysqlite2
Recommends: dnsutils, dbus, python2.4-dbus, notification-daemon
Depends: ${python:Depends}, python-glade2 (>= 2.6.0), python-gtk2 (>= 2.6.0), python-pysqlite2
Recommends: dnsutils, dbus, python-dbus, notification-daemon
Suggests: python-gnome2, python-gnupginterface, nautilus-sendto, avahi-daemon, python-avahi, network-manager
Description: Jabber client written in PyGTK
Gajim is a Jabber client. It has a tabbed user interface with normal chats,
......
......@@ -717,11 +717,15 @@ class ChatControlBase(MessageControl):
if diff_y != 0:
if conversation_height + diff_y < min_height:
if message_height + conversation_height - min_height > min_height:
self.msg_scrolledwindow.set_property('vscrollbar-policy',
gtk.POLICY_AUTOMATIC)
self.msg_scrolledwindow.set_property('height-request',
message_height + conversation_height - min_height)
self.bring_scroll_to_end(msg_textview)
policy = self.msg_scrolledwindow.get_property(
'vscrollbar-policy')
# scroll only when scrollbar appear
if policy != gtk.POLICY_AUTOMATIC:
self.msg_scrolledwindow.set_property('vscrollbar-policy',
gtk.POLICY_AUTOMATIC)
self.msg_scrolledwindow.set_property('height-request',
message_height + conversation_height - min_height)
self.bring_scroll_to_end(msg_textview)
else:
self.msg_scrolledwindow.set_property('vscrollbar-policy',
gtk.POLICY_NEVER)
......@@ -1302,6 +1306,8 @@ class ChatControl(ChatControlBase):
# Draw tab label using chatstate
theme = gajim.config.get('roster_theme')
color = None
if not chatstate:
chatstate = self.contact.chatstate
if chatstate is not None:
if chatstate == 'composing':
color = gajim.config.get_per('themes', theme,
......@@ -1323,7 +1329,7 @@ class ChatControl(ChatControlBase):
if chatstate in ('inactive', 'gone') and\
self.parent_win.get_active_control() != self:
color = self.lighten_color(color)
elif chatstate == 'active' : # active, get color from gtk
else: # active or not chatstate, get color from gtk
color = self.parent_win.notebook.style.fg[gtk.STATE_ACTIVE]
......
......@@ -117,7 +117,7 @@ class ChangeStatusCommand(AdHocCommand):
try:
presencetype = form['presence-type'].value
if not presencetype in \
('free-for-chat', 'online', 'away', 'xa', 'dnd', 'offline'):
('free-for-chat', 'online', 'away', 'xa', 'dnd', 'offline'):
self.badRequest(request)
return False
except: # KeyError if there's no presence-type field in form or
......@@ -282,8 +282,8 @@ class ConnectionCommands:
iq = iq_obj.buildReply('result')
q = iq.getTag('query')
q.addChild('identity', attrs = {'type': 'command-node',
'category': 'automation',
'name': cmd.commandname})
'category': 'automation',
'name': cmd.commandname})
q.addChild('feature', attrs = {'var': xmpp.NS_COMMANDS})
for feature in cmd.commandfeatures:
q.addChild('feature', attrs = {'var': feature})
......
......@@ -107,7 +107,7 @@ class Connection(ConnectionHandlers):
def _reconnect(self):
# Do not try to reco while we are already trying
self.time_to_reconnect = None
if self.connected < 2: #connection failed
if self.connected < 2: # connection failed
gajim.log.debug('reconnect')
self.retrycount += 1
signed = self.get_signed_msg(self.status)
......@@ -145,6 +145,11 @@ class Connection(ConnectionHandlers):
if gajim.config.get_per('accounts', self.name, 'autoreconnect'):
self.connected = 1
self.dispatch('STATUS', 'connecting')
if gajim.status_before_autoaway[self.name]:
# We were auto away. So go back online
self.status = gajim.status_before_autoaway[self.name]
gajim.status_before_autoaway[self.name] = ''
self.old_show = 'online'
# this check has moved from _reconnect method
# do exponential backoff until 15 minutes,
# then small linear increase
......@@ -1096,10 +1101,10 @@ class Connection(ConnectionHandlers):
ptype = None
if show == 'offline':
ptype = 'unavailable'
show = helpers.get_xmpp_show(show)
xmpp_show = helpers.get_xmpp_show(show)
p = common.xmpp.Presence(to = '%s/%s' % (jid, nick), typ = ptype,
show = show, status = status)
if gajim.config.get('send_sha_in_gc_presence'):
show = xmpp_show, status = status)
if gajim.config.get('send_sha_in_gc_presence') and show != 'offline':
p = self.add_sha(p, ptype != 'unavailable')
# send instantly so when we go offline, status is sent to gc before we
# disconnect from jabber server
......
......@@ -745,6 +745,10 @@ class ConnectionDisco:
q.addChild('feature', attrs = {'var': common.xmpp.NS_XHTML_IM})
if node in (None, client_version):
q.addChild('feature', attrs = {'var': common.xmpp.NS_MUC})
q.addChild('feature', attrs = {'var': common.xmpp.NS_CHATSTATES})
q.addChild('feature', attrs = {'var': common.xmpp.NS_COMMANDS})
q.addChild('feature', attrs = {'var': common.xmpp.NS_DISCO_INFO})
if q.getChildren():
self.connection.send(iq)
raise common.xmpp.NodeProcessed
......@@ -838,14 +842,14 @@ class ConnectionVcard:
dict[name] = []
entry = {}
for c in info.getChildren():
entry[c.getName()] = c.getData()
entry[c.getName()] = c.getData()
dict[name].append(entry)
elif info.getChildren() == []:
dict[name] = info.getData()
else:
dict[name] = {}
for c in info.getChildren():
dict[name][c.getName()] = c.getData()
dict[name][c.getName()] = c.getData()
return dict
def save_vcard_to_hd(self, full_jid, card):
......@@ -1049,12 +1053,14 @@ class ConnectionVcard:
self.get_metacontacts()
del self.awaiting_answers[id]
def _vCardCB(self, con, vc):
'''Called when we receive a vCard
Parse the vCard and send it to plugins'''
if not vc.getTag('vCard'):
return
if not vc.getTag('vCard').getNamespace() == common.xmpp.NS_VCARD:
return
frm_iq = vc.getFrom()
our_jid = gajim.get_jid_from_account(self.name)
resource = ''
......@@ -1063,75 +1069,74 @@ class ConnectionVcard:
frm, resource = gajim.get_room_and_nick_from_fjid(who)
else:
who = frm = our_jid
if vc.getTag('vCard').getNamespace() == common.xmpp.NS_VCARD:
card = vc.getChildren()[0]
vcard = self.node_to_dict(card)
photo_decoded = None
if vcard.has_key('PHOTO') and isinstance(vcard['PHOTO'], dict) and \
vcard['PHOTO'].has_key('BINVAL'):
photo = vcard['PHOTO']['BINVAL']
try:
photo_decoded = base64.decodestring(photo)
avatar_sha = sha.sha(photo_decoded).hexdigest()
except:
avatar_sha = ''
else:
card = vc.getChildren()[0]
vcard = self.node_to_dict(card)
photo_decoded = None
if vcard.has_key('PHOTO') and isinstance(vcard['PHOTO'], dict) and \
vcard['PHOTO'].has_key('BINVAL'):
photo = vcard['PHOTO']['BINVAL']
try:
photo_decoded = base64.decodestring(photo)
avatar_sha = sha.sha(photo_decoded).hexdigest()
except:
avatar_sha = ''
if avatar_sha:
card.getTag('PHOTO').setTagData('SHA', avatar_sha)
# Save it to file
self.save_vcard_to_hd(who, card)
# Save the decoded avatar to a separate file too, and generate files for dbus notifications
puny_jid = helpers.sanitize_filename(frm)
puny_nick = None
begin_path = os.path.join(gajim.AVATAR_PATH, puny_jid)
if frm in self.room_jids:
puny_nick = helpers.sanitize_filename(resource)
# create folder if needed
if not os.path.isdir(begin_path):
os.mkdir(begin_path, 0700)
begin_path = os.path.join(begin_path, puny_nick)
if photo_decoded:
avatar_file = begin_path + '_notif_size_colored.png'
if frm == our_jid and avatar_sha != self.vcard_sha:
gajim.interface.save_avatar_files(frm, photo_decoded, puny_nick)
elif frm != our_jid and (not os.path.exists(avatar_file) or \
not self.vcard_shas.has_key(frm) or \
avatar_sha != self.vcard_shas[frm]):
gajim.interface.save_avatar_files(frm, photo_decoded, puny_nick)
else:
for ext in ('.jpeg', '.png', '_notif_size_bw.png',
'_notif_size_colored.png'):
path = begin_path + ext
if os.path.isfile(path):
os.remove(path)
if frm != our_jid:
else:
avatar_sha = ''
if avatar_sha:
card.getTag('PHOTO').setTagData('SHA', avatar_sha)
# Save it to file
self.save_vcard_to_hd(who, card)
# Save the decoded avatar to a separate file too, and generate files for dbus notifications
puny_jid = helpers.sanitize_filename(frm)
puny_nick = None
begin_path = os.path.join(gajim.AVATAR_PATH, puny_jid)
frm_jid = frm
if frm in self.room_jids:
puny_nick = helpers.sanitize_filename(resource)
# create folder if needed
if not os.path.isdir(begin_path):
os.mkdir(begin_path, 0700)
begin_path = os.path.join(begin_path, puny_nick)
frm_jid += '/' + resource
if photo_decoded:
avatar_file = begin_path + '_notif_size_colored.png'
if frm_jid == our_jid and avatar_sha != self.vcard_sha:
gajim.interface.save_avatar_files(frm, photo_decoded, puny_nick)
elif frm_jid != our_jid and (not os.path.exists(avatar_file) or \
not self.vcard_shas.has_key(frm_jid) or \
avatar_sha != self.vcard_shas[frm_jid]):
gajim.interface.save_avatar_files(frm, photo_decoded, puny_nick)
if avatar_sha:
self.vcard_shas[frm] = avatar_sha
elif self.vcard_shas.has_key(frm):
del self.vcard_shas[frm]
vcard['jid'] = frm
vcard['resource'] = resource
if frm == our_jid:
self.dispatch('MYVCARD', vcard)
# we re-send our presence with sha if has changed and if we are
# not invisible
if self.vcard_sha == avatar_sha:
return
self.vcard_sha = avatar_sha
if STATUS_LIST[self.connected] == 'invisible':
return
sshow = helpers.get_xmpp_show(STATUS_LIST[self.connected])
p = common.xmpp.Presence(typ = None, priority = self.priority,
show = sshow, status = self.status)
p = self.add_sha(p)
self.connection.send(p)
else:
self.dispatch('VCARD', vcard)
self.vcard_shas[frm_jid] = avatar_sha
elif self.vcard_shas.has_key(frm):
del self.vcard_shas[frm]
else:
for ext in ('.jpeg', '.png', '_notif_size_bw.png',
'_notif_size_colored.png'):
path = begin_path + ext
if os.path.isfile(path):
os.remove(path)
vcard['jid'] = frm
vcard['resource'] = resource
if frm_jid == our_jid:
self.dispatch('MYVCARD', vcard)
# we re-send our presence with sha if has changed and if we are
# not invisible
if self.vcard_sha == avatar_sha:
return
self.vcard_sha = avatar_sha
if STATUS_LIST[self.connected] == 'invisible':
return
sshow = helpers.get_xmpp_show(STATUS_LIST[self.connected])
p = common.xmpp.Presence(typ = None, priority = self.priority,
show = sshow, status = self.status)
p = self.add_sha(p)
self.connection.send(p)
else:
self.dispatch('VCARD', vcard)
class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, ConnectionCommands, ConnectionPubSub):
def __init__(self):
......@@ -1459,7 +1464,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
has_timestamp = False
if msg.timestamp:
has_timestamp = True
if subject:
if subject != None:
self.dispatch('GC_SUBJECT', (frm, subject, msgtxt, has_timestamp))
else:
if not msg.getTag('body'): #no <body>
......@@ -1632,7 +1637,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
errmsg, errcode))
if not ptype or ptype == 'unavailable':
if gajim.config.get('log_contact_status_changes') and self.name\
not in no_log_for and jid_stripped not in no_log_for:
not in no_log_for and jid_stripped not in no_log_for:
gc_c = gajim.contacts.get_gc_contact(self.name, jid_stripped, resource)
st = status or ''
if gc_c:
......@@ -1648,12 +1653,24 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
# contact has no avatar
puny_nick = helpers.sanitize_filename(resource)
gajim.interface.remove_avatar_files(jid_stripped, puny_nick)
if self.vcard_shas.has_key(who):
if self.vcard_shas.has_key(who): # Verify sha cached in mem
if avatar_sha != self.vcard_shas[who]:
# avatar has been updated
self.request_vcard(who, True)
else:
self.vcard_shas[who] = avatar_sha
else: # Verify sha cached in hdd
cached_vcard = self.get_cached_vcard(who, True)
if cached_vcard and cached_vcard.has_key('PHOTO') and \
cached_vcard['PHOTO'].has_key('SHA'):
cached_sha = cached_vcard['PHOTO']['SHA']
else:
cached_sha = ''
if cached_sha != avatar_sha:
# avatar has been updated
# sha in mem will be updated later
self.request_vcard(who, True)
else:
# save sha in mem NOW
self.vcard_shas[who] = avatar_sha
self.dispatch('GC_NOTIFY', (jid_stripped, show, status, resource,
prs.getRole(), prs.getAffiliation(), prs.getJid(),
prs.getReason(), prs.getActor(), prs.getStatusCode(),
......@@ -1846,6 +1863,12 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
errcode = iq_obj.getErrorCode()
self.dispatch('MSGERROR', (jid, errcode, errmsg))
def _IqPingCB(self, con, iq_obj):
gajim.log.debug('IqPingCB')
iq_obj = iq_obj.buildReply('result')
self.connection.send(iq_obj)
raise common.xmpp.NodeProcessed
def _getRosterCB(self, con, iq_obj):
if not self.connection:
return
......@@ -2010,6 +2033,8 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
common.xmpp.NS_DISCO_INFO)
con.RegisterHandler('iq', self._DiscoverItemsGetCB, 'get',
common.xmpp.NS_DISCO_ITEMS)
con.RegisterHandler('iq', self._IqPingCB, 'get',
common.xmpp.NS_PING)
con.RegisterHandler('iq', self._PubSubCB, 'result')
con.RegisterHandler('iq', self._ErrorCB, 'error')
con.RegisterHandler('iq', self._IqCB)
......
......@@ -276,8 +276,12 @@ class Contacts:
else:
contact_groups = contact.groups
if not contact_groups:
# Contact is not in a group, so count it in General group
contact_groups.append(_('General'))
# Contact is not in a group, so count it in General or
# Transports group
if common.gajim.jid_is_transport(jid):
contact_groups = [_('Transports')]
else:
contact_groups = [_('General')]
for group in groups:
if group in contact_groups:
in_groups = True
......
......@@ -34,103 +34,103 @@ So most of the credit goes to this guys, thanks :-)
import time
class FuzzyClock:
def __init__(self):
self.__hour = 0
self.__minute = 0
self.__dayOfWeek = 0
self.__hourNames = [ _('one'), _('two'), _('three'), _('four'), _('five'), _('six'),
_('seven'), _('eight'), _('nine'), _('ten'), _('eleven'),
_('twelve')]
#Strings to use for the output. %0 will be replaced with the preceding hour (e.g. "x PAST %0"), %1 with the coming hour (e.g. "x TO %1). '''
self.__normalFuzzy = [ _("$0 o'clock"), _('five past $0'),
_('ten past $0'), _('quarter past $0'),
_('twenty past $0'), _('twenty five past $0'),
_('half past $0'), _('twenty five to $1'),
_('twenty to $1'), _('quarter to $1'),
_('ten to $1'), _('five to $1'), _("$1 o'clock") ]
#A "singular-form". It is used when talking about hour 0
self.__normalFuzzyOne = [ _("$0 o'clock"), _('five past $0'),
_('ten past $0'), _('quarter past $0'),
_('twenty past $0'), _('twenty five past $0'),
_('half past $0'), _('twenty five to $1'),
_('twenty to $1'), _('quarter to $1'),
_('ten to $1'), _('five to $1'),
_("$1 o'clock") ]
self.__dayTime = [ _('Night'), _('Early morning'), _('Morning'), _('Almost noon'),
_('Noon'), _('Afternoon'), _('Evening'), _('Late evening') ]
self.__fuzzyWeek = [ _('Start of week'), _('Middle of week'), _('End of week'),
_('Weekend!') ]
self.setCurrent()
def setHour(self,hour):
self.__hour = int(hour)
def setMinute(self,minute):
self.__minute=int(minute)
def setDayOfWeek(self,day):
self.__dayOfWeek=int(day)
def setTime(self,time):
timeArray = time.split(":")
self.setHour(timeArray[0])
self.setMinute(timeArray[1])
def setCurrent(self):
hour=time.strftime("%H")
minute=time.strftime("%M")
day=time.strftime("%w")
self.setTime(hour+":"+minute)
self.setDayOfWeek(day)
def getFuzzyTime(self, fuzzyness = 1):
sector = 0
realHour = 0
if fuzzyness == 1 or fuzzyness == 2:
if fuzzyness == 1:
if self.__minute >2:
sector = (self.__minute - 3) / 5 +1
else:
if self.__minute > 6:
sector = ((self.__minute - 7) / 15 + 1) * 3
newTimeStr = self.__normalFuzzy[sector]
#$0 or $1?
deltaHour = int(newTimeStr[newTimeStr.find("$")+1])
if (self.__hour + deltaHour) % 12 > 0:
realHour = (self.__hour + deltaHour) % 12 - 1
else:
realHour = 12 - ((self.__hour + deltaHour) % 12 + 1)
if realHour == 0:
newTimeStr = self.__normalFuzzyOne[sector]
newTimeStr = newTimeStr.replace("$"+str(deltaHour),
self.__hourNames[realHour])
elif fuzzyness == 3:
newTimeStr = self.__dayTime[self.__hour / 3]
else:
dayOfWeek = self.__dayOfWeek
if dayOfWeek == 1:
newTimeStr = self.__fuzzyWeek[0]
elif dayOfWeek >= 2 and dayOfWeek <= 4:
newTimeStr = self.__fuzzyWeek[1]
elif dayOfWeek == 5:
newTimeStr = self.__fuzzyWeek[2]
else:
newTimeStr = self.__fuzzyWeek[3]
return newTimeStr
def __init__(self):
self.__hour = 0
self.__minute = 0
self.__dayOfWeek = 0
self.__hourNames = [ _('one'), _('two'), _('three'), _('four'), _('five'), _('six'),
_('seven'), _('eight'), _('nine'), _('ten'), _('eleven'),
_('twelve')]
#Strings to use for the output. %0 will be replaced with the preceding hour (e.g. "x PAST %0"), %1 with the coming hour (e.g. "x TO %1). '''
self.__normalFuzzy = [ _("$0 o'clock"), _('five past $0'),
_('ten past $0'), _('quarter past $0'),
_('twenty past $0'), _('twenty five past $0'),
_('half past $0'), _('twenty five to $1'),
_('twenty to $1'), _('quarter to $1'),
_('ten to $1'), _('five to $1'), _("$1 o'clock") ]
#A "singular-form". It is used when talking about hour 0
self.__normalFuzzyOne = [ _("$0 o'clock"), _('five past $0'),
_('ten past $0'), _('quarter past $0'),
_('twenty past $0'), _('twenty five past $0'),
_('half past $0'), _('twenty five to $1'),
_('twenty to $1'), _('quarter to $1'),
_('ten to $1'), _('five to $1'),
_("$1 o'clock") ]
self.__dayTime = [ _('Night'), _('Early morning'), _('Morning'), _('Almost noon'),
_('Noon'), _('Afternoon'), _('Evening'), _('Late evening') ]