PageRenderTime 60ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/dataobjs.py

https://github.com/602p/pesterchum
Python | 332 lines | 326 code | 6 blank | 0 comment | 57 complexity | cf151805ab7fe23f2413215e284f2d84 MD5 | raw file
Possible License(s): GPL-3.0, Cube
  1. from PyQt4 import QtGui, QtCore
  2. from datetime import *
  3. import re
  4. import random
  5. from mood import Mood
  6. from generic import PesterIcon
  7. from parsetools import timeDifference, convertTags, lexMessage, parseRegexpFunctions
  8. from mispeller import mispeller
  9. _groupre = re.compile(r"\\([0-9]+)")
  10. _upperre = re.compile(r"upper\(([\w<>\\]+)\)")
  11. _lowerre = re.compile(r"lower\(([\w<>\\]+)\)")
  12. _scramblere = re.compile(r"scramble\(([\w<>\\]+)\)")
  13. _reversere = re.compile(r"reverse\(([\w<>\\]+)\)")
  14. class pesterQuirk(object):
  15. def __init__(self, quirk):
  16. if type(quirk) != dict:
  17. raise ValueError("Quirks must be given a dictionary")
  18. self.quirk = quirk
  19. self.type = self.quirk["type"]
  20. if "on" not in self.quirk:
  21. self.quirk["on"] = True
  22. self.on = self.quirk["on"]
  23. if "group" not in self.quirk:
  24. self.quirk["group"] = "Miscellaneous"
  25. self.group = self.quirk["group"]
  26. def apply(self, string, first=False, last=False):
  27. if not self.on:
  28. return string
  29. elif self.type == "prefix":
  30. return self.quirk["value"] + string
  31. elif self.type == "suffix":
  32. return string + self.quirk["value"]
  33. elif self.type == "replace":
  34. return string.replace(self.quirk["from"], self.quirk["to"])
  35. elif self.type == "regexp":
  36. fr = self.quirk["from"]
  37. if not first and len(fr) > 0 and fr[0] == "^":
  38. return string
  39. if not last and len(fr) > 0 and fr[len(fr)-1] == "$":
  40. return string
  41. to = self.quirk["to"]
  42. pt = parseRegexpFunctions(to)
  43. return re.sub(fr, pt.expand, string)
  44. elif self.type == "random":
  45. if len(self.quirk["randomlist"]) == 0:
  46. return string
  47. fr = self.quirk["from"]
  48. if not first and len(fr) > 0 and fr[0] == "^":
  49. return string
  50. if not last and len(fr) > 0 and fr[len(fr)-1] == "$":
  51. return string
  52. def randomrep(mo):
  53. choice = random.choice(self.quirk["randomlist"])
  54. pt = parseRegexpFunctions(choice)
  55. return pt.expand(mo)
  56. return re.sub(self.quirk["from"], randomrep, string)
  57. elif self.type == "spelling":
  58. percentage = self.quirk["percentage"]/100.0
  59. words = string.split(" ")
  60. newl = []
  61. ctag = re.compile("(</?c=?.*?>)", re.I)
  62. for w in words:
  63. p = random.random()
  64. if not ctag.search(w) and p < percentage:
  65. newl.append(mispeller(w))
  66. elif p < percentage:
  67. split = ctag.split(w)
  68. tmp = []
  69. for s in split:
  70. if s and not ctag.search(s):
  71. tmp.append(mispeller(s))
  72. else:
  73. tmp.append(s)
  74. newl.append("".join(tmp))
  75. else:
  76. newl.append(w)
  77. return " ".join(newl)
  78. def __str__(self):
  79. if self.type == "prefix":
  80. return "BEGIN WITH: %s" % (self.quirk["value"])
  81. elif self.type == "suffix":
  82. return "END WITH: %s" % (self.quirk["value"])
  83. elif self.type == "replace":
  84. return "REPLACE %s WITH %s" % (self.quirk["from"], self.quirk["to"])
  85. elif self.type == "regexp":
  86. return "REGEXP: %s REPLACED WITH %s" % (self.quirk["from"], self.quirk["to"])
  87. elif self.type == "random":
  88. return "REGEXP: %s RANDOMLY REPLACED WITH %s" % (self.quirk["from"], [r for r in self.quirk["randomlist"]])
  89. elif self.type == "spelling":
  90. return "MISPELLER: %d%%" % (self.quirk["percentage"])
  91. class pesterQuirks(object):
  92. def __init__(self, quirklist):
  93. self.quirklist = []
  94. for q in quirklist:
  95. self.addQuirk(q)
  96. def plainList(self):
  97. return [q.quirk for q in self.quirklist]
  98. def addQuirk(self, q):
  99. if type(q) == dict:
  100. self.quirklist.append(pesterQuirk(q))
  101. elif type(q) == pesterQuirk:
  102. self.quirklist.append(q)
  103. def apply(self, lexed, first=False, last=False):
  104. prefix = [q for q in self.quirklist if q.type=='prefix']
  105. suffix = [q for q in self.quirklist if q.type=='suffix']
  106. newlist = []
  107. for (i, o) in enumerate(lexed):
  108. if type(o) not in [str, unicode]:
  109. if i == 0:
  110. string = " "
  111. for p in prefix:
  112. string += p.apply(string)
  113. newlist.append(string)
  114. newlist.append(o)
  115. continue
  116. lastStr = (i == len(lexed)-1)
  117. string = o
  118. for q in self.quirklist:
  119. if q.type != 'prefix' and q.type != 'suffix':
  120. if q.type == 'regexp' or q.type == 'random':
  121. string = q.apply(string, first=(i==0), last=lastStr)
  122. else:
  123. string = q.apply(string)
  124. elif q.type == 'prefix' and i == 0:
  125. string = q.apply(string)
  126. elif q.type == 'suffix' and lastStr:
  127. string = q.apply(string)
  128. newlist.append(string)
  129. final = []
  130. for n in newlist:
  131. if type(n) in [str, unicode]:
  132. final.extend(lexMessage(n))
  133. else:
  134. final.append(n)
  135. return final
  136. def __iter__(self):
  137. for q in self.quirklist:
  138. yield q
  139. class PesterProfile(object):
  140. def __init__(self, handle, color=None, mood=Mood("offline"), group=None, notes="", chumdb=None):
  141. self.handle = handle
  142. if color is None:
  143. if chumdb:
  144. color = chumdb.getColor(handle, QtGui.QColor("black"))
  145. else:
  146. color = QtGui.QColor("black")
  147. self.color = color
  148. self.mood = mood
  149. if group is None:
  150. if chumdb:
  151. group = chumdb.getGroup(handle, "Chums")
  152. else:
  153. group = "Chums"
  154. self.group = group
  155. self.notes = notes
  156. def initials(self, time=None):
  157. handle = self.handle
  158. caps = [l for l in handle if l.isupper()]
  159. if not caps:
  160. caps = [""]
  161. initials = (handle[0]+caps[0]).upper()
  162. if hasattr(self, 'time') and time:
  163. if self.time > time:
  164. return "F"+initials
  165. elif self.time < time:
  166. return "P"+initials
  167. else:
  168. return "C"+initials
  169. else:
  170. return (handle[0]+caps[0]).upper()
  171. def colorhtml(self):
  172. if self.color:
  173. return self.color.name()
  174. else:
  175. return "#000000"
  176. def colorcmd(self):
  177. if self.color:
  178. (r, g, b, a) = self.color.getRgb()
  179. return "%d,%d,%d" % (r,g,b)
  180. else:
  181. return "0,0,0"
  182. def plaindict(self):
  183. return (self.handle, {"handle": self.handle,
  184. "mood": self.mood.name(),
  185. "color": unicode(self.color.name()),
  186. "group": unicode(self.group),
  187. "notes": unicode(self.notes)})
  188. def blocked(self, config):
  189. return self.handle in config.getBlocklist()
  190. def memsg(self, syscolor, lexmsg, time=None):
  191. suffix = lexmsg[0].suffix
  192. msg = convertTags(lexmsg[1:], "text")
  193. uppersuffix = suffix.upper()
  194. if time is not None:
  195. handle = "%s %s" % (time.temporal, self.handle)
  196. initials = time.pcf+self.initials()+time.number+uppersuffix
  197. else:
  198. handle = self.handle
  199. initials = self.initials()+uppersuffix
  200. return "<c=%s>-- %s%s <c=%s>[%s]</c> %s --</c>" % (syscolor.name(), handle, suffix, self.colorhtml(), initials, msg)
  201. def pestermsg(self, otherchum, syscolor, verb):
  202. return "<c=%s>-- %s <c=%s>[%s]</c> %s %s <c=%s>[%s]</c> at %s --</c>" % (syscolor.name(), self.handle, self.colorhtml(), self.initials(), verb, otherchum.handle, otherchum.colorhtml(), otherchum.initials(), datetime.now().strftime("%H:%M"))
  203. def moodmsg(self, mood, syscolor, theme):
  204. return "<c=%s>-- %s <c=%s>[%s]</c> changed their mood to %s <img src='%s' /> --</c>" % (syscolor.name(), self.handle, self.colorhtml(), self.initials(), mood.name().upper(), theme["main/chums/moods"][mood.name()]["icon"])
  205. def idlemsg(self, syscolor, verb):
  206. return "<c=%s>-- %s <c=%s>[%s]</c> %s --</c>" % (syscolor.name(), self.handle, self.colorhtml(), self.initials(), verb)
  207. def memoclosemsg(self, syscolor, initials, verb):
  208. if type(initials) == type(list()):
  209. return "<c=%s><c=%s>%s</c> %s.</c>" % (syscolor.name(), self.colorhtml(), ", ".join(initials), verb)
  210. else:
  211. return "<c=%s><c=%s>%s%s%s</c> %s.</c>" % (syscolor.name(), self.colorhtml(), initials.pcf, self.initials(), initials.number, verb)
  212. def memonetsplitmsg(self, syscolor, initials):
  213. if len(initials) <= 0:
  214. return "<c=%s>Netsplit quits: <c=black>None</c></c>" % (syscolor.name())
  215. else:
  216. return "<c=%s>Netsplit quits: <c=black>%s</c></c>" % (syscolor.name(), ", ".join(initials))
  217. def memoopenmsg(self, syscolor, td, timeGrammar, verb, channel):
  218. (temporal, pcf, when) = (timeGrammar.temporal, timeGrammar.pcf, timeGrammar.when)
  219. timetext = timeDifference(td)
  220. initials = pcf+self.initials()
  221. return "<c=%s><c=%s>%s</c> %s %s %s.</c>" % \
  222. (syscolor.name(), self.colorhtml(), initials, timetext, verb, channel[1:].upper().replace("_", " "))
  223. def memobanmsg(self, opchum, opgrammar, syscolor, initials, reason):
  224. opinit = opgrammar.pcf+opchum.initials()+opgrammar.number
  225. if type(initials) == type(list()):
  226. if opchum.handle == reason:
  227. return "<c=%s>%s</c> banned <c=%s>%s</c> from responding to memo." % \
  228. (opchum.colorhtml(), opinit, self.colorhtml(), ", ".join(initials))
  229. else:
  230. return "<c=%s>%s</c> banned <c=%s>%s</c> from responding to memo: <c=black>[%s]</c>." % \
  231. (opchum.colorhtml(), opinit, self.colorhtml(), ", ".join(initials), unicode(reason))
  232. else:
  233. initials = timeGrammar.pcf+self.initials()+timeGrammar.number
  234. if opchum.handle == reason:
  235. return "<c=%s>%s</c> banned <c=%s>%s</c> from responding to memo." % \
  236. (opchum.colorhtml(), opinit, self.colorhtml(), initials)
  237. else:
  238. return "<c=%s>%s</c> banned <c=%s>%s</c> from responding to memo: <c=black>[%s]</c>." % \
  239. (opchum.colorhtml(), opinit, self.colorhtml(), initials, unicode(reason))
  240. def memopermabanmsg(self, opchum, opgrammar, syscolor, timeGrammar):
  241. initials = timeGrammar.pcf+self.initials()+timeGrammar.number
  242. opinit = opgrammar.pcf+opchum.initials()+opgrammar.number
  243. return "<c=%s>%s</c> permabanned <c=%s>%s</c> from the memo." % \
  244. (opchum.colorhtml(), opinit, self.colorhtml(), initials)
  245. def memojoinmsg(self, syscolor, td, timeGrammar, verb):
  246. (temporal, pcf, when) = (timeGrammar.temporal, timeGrammar.pcf, timeGrammar.when)
  247. timetext = timeDifference(td)
  248. initials = pcf+self.initials()+timeGrammar.number
  249. return "<c=%s><c=%s>%s %s [%s]</c> %s %s.</c>" % \
  250. (syscolor.name(), self.colorhtml(), temporal, self.handle,
  251. initials, timetext, verb)
  252. def memoopmsg(self, opchum, opgrammar, syscolor):
  253. opinit = opgrammar.pcf+opchum.initials()+opgrammar.number
  254. return "<c=%s>%s</c> made <c=%s>%s</c> an OP." % \
  255. (opchum.colorhtml(), opinit, self.colorhtml(), self.initials())
  256. def memodeopmsg(self, opchum, opgrammar, syscolor):
  257. opinit = opgrammar.pcf+opchum.initials()+opgrammar.number
  258. return "<c=%s>%s</c> took away <c=%s>%s</c>'s OP powers." % \
  259. (opchum.colorhtml(), opinit, self.colorhtml(), self.initials())
  260. def memovoicemsg(self, opchum, opgrammar, syscolor):
  261. opinit = opgrammar.pcf+opchum.initials()+opgrammar.number
  262. return "<c=%s>%s</c> gave <c=%s>%s</c> voice." % \
  263. (opchum.colorhtml(), opinit, self.colorhtml(), self.initials())
  264. def memodevoicemsg(self, opchum, opgrammar, syscolor):
  265. opinit = opgrammar.pcf+opchum.initials()+opgrammar.number
  266. return "<c=%s>%s</c> took away <c=%s>%s</c>'s voice." % \
  267. (opchum.colorhtml(), opinit, self.colorhtml(), self.initials())
  268. def memomodemsg(self, opchum, opgrammar, syscolor, modeverb, modeon):
  269. opinit = opgrammar.pcf+opchum.initials()+opgrammar.number
  270. if modeon: modeon = "now"
  271. else: modeon = "no longer"
  272. return "<c=%s>Memo is %s <c=black>%s</c> by <c=%s>%s</c></c>" % \
  273. (syscolor.name(), modeon, modeverb, opchum.colorhtml(), opinit)
  274. def memoquirkkillmsg(self, opchum, opgrammar, syscolor):
  275. opinit = opgrammar.pcf+opchum.initials()+opgrammar.number
  276. return "<c=%s><c=%s>%s</c> turned off your quirk.</c>" % \
  277. (syscolor.name(), opchum.colorhtml(), opinit)
  278. @staticmethod
  279. def checkLength(handle):
  280. return len(handle) <= 256
  281. @staticmethod
  282. def checkValid(handle):
  283. caps = [l for l in handle if l.isupper()]
  284. if len(caps) != 1:
  285. return (False, "Must have exactly 1 uppercase letter")
  286. if handle[0].isupper():
  287. return (False, "Cannot start with uppercase letter")
  288. if re.search("[^A-Za-z0-9]", handle) is not None:
  289. return (False, "Only alphanumeric characters allowed")
  290. return (True,)
  291. class PesterHistory(object):
  292. def __init__(self):
  293. self.history = []
  294. self.current = 0
  295. self.saved = None
  296. def next(self, text):
  297. if self.current == 0:
  298. return None
  299. if self.current == len(self.history):
  300. self.save(text)
  301. self.current -= 1
  302. text = self.history[self.current]
  303. return text
  304. def prev(self):
  305. self.current += 1
  306. if self.current >= len(self.history):
  307. self.current = len(self.history)
  308. return self.retrieve()
  309. return self.history[self.current]
  310. def reset(self):
  311. self.current = len(self.history)
  312. self.saved = None
  313. def save(self, text):
  314. self.saved = text
  315. def retrieve(self):
  316. return self.saved
  317. def add(self, text):
  318. if len(self.history) == 0 or text != self.history[len(self.history)-1]:
  319. self.history.append(text)
  320. self.reset()