PageRenderTime 68ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/memos.py

https://github.com/602p/pesterchum
Python | 1289 lines | 1239 code | 44 blank | 6 comment | 74 complexity | bcb62b3bba861b4aa0e3a809abb35cb3 MD5 | raw file
Possible License(s): GPL-3.0, Cube

Large files files are truncated, but you can click here to view the full file

  1. from string import Template
  2. import re
  3. from copy import copy
  4. from PyQt4 import QtGui, QtCore
  5. from datetime import time, timedelta, datetime
  6. from mood import Mood
  7. from dataobjs import PesterProfile, PesterHistory
  8. from generic import PesterIcon, RightClickList, mysteryTime
  9. from convo import PesterConvo, PesterInput, PesterText, PesterTabWindow
  10. from parsetools import convertTags, addTimeInitial, timeProtocol, \
  11. lexMessage, colorBegin, colorEnd, mecmd, smiledict, oocre
  12. from logviewer import PesterLogViewer
  13. def delta2txt(d, format="pc"):
  14. if type(d) is mysteryTime:
  15. return "?"
  16. if format == "pc":
  17. sign = "+" if d >= timedelta(0) else "-"
  18. else:
  19. if d == timedelta(0):
  20. return "i"
  21. sign = "F" if d >= timedelta(0) else "P"
  22. d = abs(d)
  23. totalminutes = (d.days*86400 + d.seconds) // 60
  24. hours = totalminutes // 60
  25. leftovermins = totalminutes % 60
  26. if hours < 100:
  27. if format == "pc":
  28. return "%s%d:%02d" % (sign, hours, leftovermins)
  29. else:
  30. return "%s%02d:%02d" % (sign, hours, leftovermins)
  31. else:
  32. if format == "pc":
  33. return "%s%d" % (sign, hours)
  34. else:
  35. return "%s%02d:%02d" % (sign, hours, leftovermins)
  36. def txt2delta(txt):
  37. sign = 1
  38. if txt[0] == '?':
  39. return mysteryTime()
  40. if txt[0] == '+':
  41. txt = txt[1:]
  42. elif txt[0] == '-':
  43. sign = -1
  44. txt = txt[1:]
  45. l = txt.split(":")
  46. try:
  47. h = int(l[0])
  48. m = 0
  49. if len(l) > 1:
  50. m = int(l[1])
  51. timed = timedelta(0, h*3600+m*60)
  52. except ValueError:
  53. timed = timedelta(0)
  54. except OverflowError:
  55. if sign < 0:
  56. return timedelta(min)
  57. else:
  58. return timedelta(max)
  59. return sign*timed
  60. def pcfGrammar(td):
  61. if type(td) is mysteryTime:
  62. when = "???"
  63. temporal = "???"
  64. pcf = "?"
  65. elif td > timedelta(0):
  66. when = "FROM NOW"
  67. temporal = "FUTURE"
  68. pcf = "F"
  69. elif td < timedelta(0):
  70. when = "AGO"
  71. temporal = "PAST"
  72. pcf = "P"
  73. else:
  74. when = "RIGHT NOW"
  75. temporal = "CURRENT"
  76. pcf = "C"
  77. return (temporal, pcf, when)
  78. class TimeGrammar(object):
  79. def __init__(self, temporal, pcf, when, number="0"):
  80. self.temporal = temporal
  81. self.pcf = pcf
  82. self.when = when
  83. if number == "0" or number == 0:
  84. self.number = ""
  85. else:
  86. self.number = str(number)
  87. class TimeTracker(list):
  88. def __init__(self, time=None):
  89. self.timerecord = {"P": [], "F": []}
  90. self.open = {}
  91. if time is not None:
  92. self.append(time)
  93. self.current=0
  94. self.addRecord(time)
  95. self.open[time] = False
  96. else:
  97. self.current=-1
  98. def addTime(self, timed):
  99. try:
  100. i = self.index(timed)
  101. self.current = i
  102. return True
  103. except ValueError:
  104. self.current = len(self)
  105. self.append(timed)
  106. self.open[timed] = False
  107. self.addRecord(timed)
  108. return False
  109. def prevTime(self):
  110. i = self.current
  111. i = (i - 1) % len(self)
  112. return self[i]
  113. def nextTime(self):
  114. i = self.current
  115. i = (i + 1) % len(self)
  116. return self[i]
  117. def setCurrent(self, timed):
  118. self.current = self.index(timed)
  119. def addRecord(self, timed):
  120. try:
  121. (temporal, pcf, when) = pcfGrammar(timed - timedelta(0))
  122. except TypeError:
  123. (temporal, pcf, when) = pcfGrammar(mysteryTime())
  124. if pcf == "C" or pcf == "?":
  125. return
  126. if timed in self.timerecord[pcf]:
  127. return
  128. self.timerecord[pcf].append(timed)
  129. def getRecord(self, timed):
  130. try:
  131. (temporal, pcf, when) = pcfGrammar(timed - timedelta(0))
  132. except TypeError:
  133. (temporal, pcf, when) = pcfGrammar(mysteryTime())
  134. if pcf == "C" or pcf == "?":
  135. return 0
  136. if len(self.timerecord[pcf]) > 1:
  137. return self.timerecord[pcf].index(timed)+1
  138. else:
  139. return 0
  140. def removeTime(self, timed):
  141. try:
  142. self.pop(self.index(timed))
  143. self.current = len(self)-1
  144. del self.open[timed]
  145. return True
  146. except ValueError:
  147. return None
  148. def openTime(self, time):
  149. if self.open.has_key(time):
  150. self.open[time] = True
  151. def openCurrentTime(self):
  152. timed = self.getTime()
  153. self.openTime(timed)
  154. def isFirstTime(self):
  155. timed = self.getTime()
  156. return not self.open[timed]
  157. def getTime(self):
  158. if self.current >= 0:
  159. return self[self.current]
  160. else:
  161. return None
  162. def getGrammar(self):
  163. timed = self.getTime()
  164. return self.getGrammarTime(timed)
  165. def getGrammarTime(self, timed):
  166. mytime = timedelta(0)
  167. try:
  168. (temporal, pcf, when) = pcfGrammar(timed - mytime)
  169. except TypeError:
  170. (temporal, pcf, when) = pcfGrammar(mysteryTime())
  171. if timed == mytime:
  172. return TimeGrammar(temporal, pcf, when, 0)
  173. return TimeGrammar(temporal, pcf, when, self.getRecord(timed))
  174. class TimeInput(QtGui.QLineEdit):
  175. def __init__(self, timeslider, parent):
  176. QtGui.QLineEdit.__init__(self, parent)
  177. self.timeslider = timeslider
  178. self.setText("+0:00")
  179. self.connect(self.timeslider, QtCore.SIGNAL('valueChanged(int)'),
  180. self, QtCore.SLOT('setTime(int)'))
  181. self.connect(self, QtCore.SIGNAL('editingFinished()'),
  182. self, QtCore.SLOT('setSlider()'))
  183. @QtCore.pyqtSlot(int)
  184. def setTime(self, sliderval):
  185. self.setText(self.timeslider.getTime())
  186. @QtCore.pyqtSlot()
  187. def setSlider(self):
  188. value = unicode(self.text())
  189. timed = txt2delta(value)
  190. if type(timed) is mysteryTime:
  191. self.timeslider.setValue(0)
  192. self.setText("?")
  193. return
  194. sign = 1 if timed >= timedelta(0) else -1
  195. abstimed = abs(txt2delta(value))
  196. index = 50
  197. for i, td in enumerate(timedlist):
  198. if abstimed < td:
  199. index = i-1
  200. break
  201. self.timeslider.setValue(sign*index)
  202. text = delta2txt(timed)
  203. self.setText(text)
  204. class TimeSlider(QtGui.QSlider):
  205. def __init__(self, orientation, parent):
  206. QtGui.QSlider.__init__(self, orientation, parent)
  207. self.setTracking(True)
  208. self.setMinimum(-50)
  209. self.setMaximum(50)
  210. self.setValue(0)
  211. self.setPageStep(1)
  212. def getTime(self):
  213. time = timelist[abs(self.value())]
  214. sign = "+" if self.value() >= 0 else "-"
  215. return sign+time
  216. def mouseDoubleClickEvent(self, event):
  217. self.setValue(0)
  218. class MemoTabWindow(PesterTabWindow):
  219. def __init__(self, mainwindow, parent=None):
  220. PesterTabWindow.__init__(self, mainwindow, parent, "memos")
  221. def addChat(self, convo):
  222. self.convos[convo.channel] = convo
  223. # either addTab or setCurrentIndex will trigger changed()
  224. newindex = self.tabs.addTab(convo.channel)
  225. self.tabIndices[convo.channel] = newindex
  226. self.tabs.setCurrentIndex(newindex)
  227. self.tabs.setTabIcon(newindex, PesterIcon(self.mainwindow.theme["memos/memoicon"]))
  228. def updateBlocked(self):
  229. pass
  230. def updateMood(self):
  231. pass
  232. _ctag_begin = re.compile(r'<c=(.*?)>')
  233. class MemoText(PesterText):
  234. def __init__(self, theme, parent=None):
  235. QtGui.QTextEdit.__init__(self, parent)
  236. if hasattr(self.parent(), 'mainwindow'):
  237. self.mainwindow = self.parent().mainwindow
  238. else:
  239. self.mainwindow = self.parent()
  240. if type(parent.parent()) is PesterTabWindow:
  241. self.tabobject = parent.parent()
  242. self.hasTabs = True
  243. else:
  244. self.hasTabs = False
  245. self.initTheme(theme)
  246. self.setReadOnly(True)
  247. self.setMouseTracking(True)
  248. self.textSelected = False
  249. self.connect(self, QtCore.SIGNAL('copyAvailable(bool)'),
  250. self, QtCore.SLOT('textReady(bool)'))
  251. self.urls = {}
  252. for k in smiledict:
  253. self.addAnimation(QtCore.QUrl("smilies/%s" % (smiledict[k])), "smilies/%s" % (smiledict[k]))
  254. self.connect(self.mainwindow, QtCore.SIGNAL('animationSetting(bool)'),
  255. self, QtCore.SLOT('animateChanged(bool)'))
  256. def initTheme(self, theme):
  257. if theme.has_key("memos/scrollbar"):
  258. self.setStyleSheet("QTextEdit { %s } QScrollBar:vertical { %s } QScrollBar::handle:vertical { %s } QScrollBar::add-line:vertical { %s } QScrollBar::sub-line:vertical { %s } QScrollBar:up-arrow:vertical { %s } QScrollBar:down-arrow:vertical { %s }" % (theme["memos/textarea/style"], theme["memos/scrollbar/style"], theme["memos/scrollbar/handle"], theme["memos/scrollbar/downarrow"], theme["memos/scrollbar/uparrow"], theme["memos/scrollbar/uarrowstyle"], theme["memos/scrollbar/darrowstyle"] ))
  259. else:
  260. self.setStyleSheet("QTextEdit { %s }" % theme["memos/textarea/style"])
  261. def addMessage(self, msg, chum):
  262. if type(msg) in [str, unicode]:
  263. lexmsg = lexMessage(msg)
  264. else:
  265. lexmsg = msg
  266. parent = self.parent()
  267. window = parent.mainwindow
  268. me = window.profile()
  269. if self.mainwindow.config.animations():
  270. for m in self.urls:
  271. if convertTags(lexmsg).find(self.urls[m].toString()) != -1:
  272. if m.state() == QtGui.QMovie.NotRunning:
  273. m.start()
  274. chumdb = window.chumdb
  275. if chum is not me: # SO MUCH WH1T3SP4C3 >:]
  276. if type(lexmsg[0]) is colorBegin: # get color tag
  277. colortag = lexmsg[0]
  278. try:
  279. color = QtGui.QColor(*[int(c) for c in colortag.color.split(",")])
  280. except ValueError:
  281. color = QtGui.QColor("black")
  282. else:
  283. chumdb.setColor(chum.handle, color)
  284. parent.updateColor(chum.handle, color)
  285. else:
  286. color = chumdb.getColor(chum.handle)
  287. else:
  288. color = me.color
  289. chum.color = color
  290. systemColor = QtGui.QColor(window.theme["memos/systemMsgColor"])
  291. if chum is not me:
  292. if parent.times.has_key(chum.handle):
  293. time = parent.times[chum.handle]
  294. if time.getTime() is None:
  295. # MY WAY OR THE HIGHWAY
  296. time.addTime(timedelta(0))
  297. else:
  298. # new chum! time current
  299. newtime = timedelta(0)
  300. time = TimeTracker(newtime)
  301. parent.times[handle] = time
  302. else:
  303. time = parent.time
  304. if time.isFirstTime():
  305. grammar = time.getGrammar()
  306. joinmsg = chum.memojoinmsg(systemColor, time.getTime(), grammar, window.theme["convo/text/joinmemo"])
  307. self.append(convertTags(joinmsg))
  308. parent.mainwindow.chatlog.log(parent.channel, joinmsg)
  309. time.openCurrentTime()
  310. def makeSafe(msg):
  311. if msg.count("<c") > msg.count("</c>"):
  312. for i in range(msg.count("<c") - msg.count("</c>")):
  313. msg = msg + "</c>"
  314. return "<span style=\"color:#000000\">" + msg + "</span>"
  315. if type(lexmsg[0]) is mecmd:
  316. memsg = chum.memsg(systemColor, lexmsg, time=time.getGrammar())
  317. window.chatlog.log(parent.channel, memsg)
  318. self.append(convertTags(memsg))
  319. else:
  320. self.append(makeSafe(convertTags(lexmsg)))
  321. window.chatlog.log(parent.channel, lexmsg)
  322. def changeTheme(self, theme):
  323. self.initTheme(theme)
  324. def submitLogTitle(self):
  325. return "[%s]" % (self.parent().title())
  326. class MemoInput(PesterInput):
  327. def __init__(self, theme, parent=None):
  328. QtGui.QLineEdit.__init__(self, parent)
  329. self.setStyleSheet(theme["memos/input/style"])
  330. def changeTheme(self, theme):
  331. self.setStyleSheet(theme["memos/input/style"])
  332. class PesterMemo(PesterConvo):
  333. def __init__(self, channel, timestr, mainwindow, parent=None):
  334. QtGui.QFrame.__init__(self, parent)
  335. self.setAttribute(QtCore.Qt.WA_QuitOnClose, False)
  336. self.channel = channel
  337. self.setObjectName(self.channel)
  338. self.mainwindow = mainwindow
  339. self.time = TimeTracker(txt2delta(timestr))
  340. self.setWindowTitle(channel)
  341. self.channelLabel = QtGui.QLabel(self)
  342. self.channelLabel.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding))
  343. self.textArea = MemoText(self.mainwindow.theme, self)
  344. self.textInput = MemoInput(self.mainwindow.theme, self)
  345. self.textInput.setFocus()
  346. self.miniUserlist = QtGui.QPushButton(">\n>", self)
  347. #self.miniUserlist.setStyleSheet("border:1px solid #a68168; border-width: 2px 0px 2px 2px; height: 90px; width: 10px; color: #cd8f9d; font-family: 'Arial'; background: white; margin-left: 2px;")
  348. self.connect(self.miniUserlist, QtCore.SIGNAL('clicked()'),
  349. self, QtCore.SLOT('toggleUserlist()'))
  350. self.userlist = RightClickList(self)
  351. self.userlist.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Expanding))
  352. self.userlist.optionsMenu = QtGui.QMenu(self)
  353. self.addchumAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/addchum"], self)
  354. self.connect(self.addchumAction, QtCore.SIGNAL('triggered()'),
  355. self, QtCore.SLOT('addChumSlot()'))
  356. self.banuserAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/banuser"], self)
  357. self.connect(self.banuserAction, QtCore.SIGNAL('triggered()'),
  358. self, QtCore.SLOT('banSelectedUser()'))
  359. self.opAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/opuser"], self)
  360. self.connect(self.opAction, QtCore.SIGNAL('triggered()'),
  361. self, QtCore.SLOT('opSelectedUser()'))
  362. self.voiceAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/voiceuser"], self)
  363. self.connect(self.voiceAction, QtCore.SIGNAL('triggered()'),
  364. self, QtCore.SLOT('voiceSelectedUser()'))
  365. self.quirkDisableAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/quirkkill"], self)
  366. self.connect(self.quirkDisableAction, QtCore.SIGNAL('triggered()'),
  367. self, QtCore.SLOT('killQuirkUser()'))
  368. self.userlist.optionsMenu.addAction(self.addchumAction)
  369. # ban & op list added if we are op
  370. self.optionsMenu = QtGui.QMenu(self)
  371. self.oocToggle = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/ooc"], self)
  372. self.oocToggle.setCheckable(True)
  373. self.connect(self.oocToggle, QtCore.SIGNAL('toggled(bool)'),
  374. self, QtCore.SLOT('toggleOOC(bool)'))
  375. self.quirksOff = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/quirksoff"], self)
  376. self.quirksOff.setCheckable(True)
  377. self.connect(self.quirksOff, QtCore.SIGNAL('toggled(bool)'),
  378. self, QtCore.SLOT('toggleQuirks(bool)'))
  379. self.logchum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/viewlog"], self)
  380. self.connect(self.logchum, QtCore.SIGNAL('triggered()'),
  381. self, QtCore.SLOT('openChumLogs()'))
  382. self.invitechum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/invitechum"], self)
  383. self.connect(self.invitechum, QtCore.SIGNAL('triggered()'),
  384. self, QtCore.SLOT('inviteChums()'))
  385. self.optionsMenu.addAction(self.quirksOff)
  386. self.optionsMenu.addAction(self.oocToggle)
  387. self.optionsMenu.addAction(self.logchum)
  388. self.optionsMenu.addAction(self.invitechum)
  389. self.chanModeMenu = QtGui.QMenu(self.mainwindow.theme["main/menus/rclickchumlist/memosetting"], self)
  390. self.chanNoquirks = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/memonoquirk"], self)
  391. self.chanNoquirks.setCheckable(True)
  392. self.connect(self.chanNoquirks, QtCore.SIGNAL('toggled(bool)'),
  393. self, QtCore.SLOT('noquirksChan(bool)'))
  394. self.chanHide = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/memohidden"], self)
  395. self.chanHide.setCheckable(True)
  396. self.connect(self.chanHide, QtCore.SIGNAL('toggled(bool)'),
  397. self, QtCore.SLOT('hideChan(bool)'))
  398. self.chanInvite = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/memoinvite"], self)
  399. self.chanInvite.setCheckable(True)
  400. self.connect(self.chanInvite, QtCore.SIGNAL('toggled(bool)'),
  401. self, QtCore.SLOT('inviteChan(bool)'))
  402. self.chanMod = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/memomute"], self)
  403. self.chanMod.setCheckable(True)
  404. self.connect(self.chanMod, QtCore.SIGNAL('toggled(bool)'),
  405. self, QtCore.SLOT('modChan(bool)'))
  406. self.chanModeMenu.addAction(self.chanNoquirks)
  407. self.chanModeMenu.addAction(self.chanHide)
  408. self.chanModeMenu.addAction(self.chanInvite)
  409. self.chanModeMenu.addAction(self.chanMod)
  410. self.timeslider = TimeSlider(QtCore.Qt.Horizontal, self)
  411. self.timeinput = TimeInput(self.timeslider, self)
  412. self.timeinput.setText(timestr)
  413. self.timeinput.setSlider()
  414. self.timetravel = QtGui.QPushButton("GO", self)
  415. self.timeclose = QtGui.QPushButton("CLOSE", self)
  416. self.timeswitchl = QtGui.QPushButton(self)
  417. self.timeswitchr = QtGui.QPushButton(self)
  418. self.connect(self.timetravel, QtCore.SIGNAL('clicked()'),
  419. self, QtCore.SLOT('sendtime()'))
  420. self.connect(self.timeclose, QtCore.SIGNAL('clicked()'),
  421. self, QtCore.SLOT('smashclock()'))
  422. self.connect(self.timeswitchl, QtCore.SIGNAL('clicked()'),
  423. self, QtCore.SLOT('prevtime()'))
  424. self.connect(self.timeswitchr, QtCore.SIGNAL('clicked()'),
  425. self, QtCore.SLOT('nexttime()'))
  426. self.times = {}
  427. self.initTheme(self.mainwindow.theme)
  428. # connect
  429. self.connect(self.textInput, QtCore.SIGNAL('returnPressed()'),
  430. self, QtCore.SLOT('sentMessage()'))
  431. layout_0 = QtGui.QVBoxLayout()
  432. layout_0.addWidget(self.textArea)
  433. layout_0.addWidget(self.textInput)
  434. layout_1 = QtGui.QHBoxLayout()
  435. layout_1.addLayout(layout_0)
  436. layout_1.addWidget(self.miniUserlist)
  437. layout_1.addWidget(self.userlist)
  438. # layout_1 = QtGui.QGridLayout()
  439. # layout_1.addWidget(self.timeslider, 0, 1, QtCore.Qt.AlignHCenter)
  440. # layout_1.addWidget(self.timeinput, 1, 0, 1, 3)
  441. layout_2 = QtGui.QHBoxLayout()
  442. layout_2.addWidget(self.timeslider)
  443. layout_2.addWidget(self.timeinput)
  444. layout_2.addWidget(self.timetravel)
  445. layout_2.addWidget(self.timeclose)
  446. layout_2.addWidget(self.timeswitchl)
  447. layout_2.addWidget(self.timeswitchr)
  448. self.layout = QtGui.QVBoxLayout()
  449. self.layout.addWidget(self.channelLabel)
  450. self.layout.addLayout(layout_1)
  451. self.layout.addLayout(layout_2)
  452. self.layout.setSpacing(0)
  453. margins = self.mainwindow.theme["memos/margins"]
  454. self.layout.setContentsMargins(margins["left"], margins["top"],
  455. margins["right"], margins["bottom"])
  456. self.setLayout(self.layout)
  457. if parent:
  458. parent.addChat(self)
  459. p = self.mainwindow.profile()
  460. timeGrammar = self.time.getGrammar()
  461. systemColor = QtGui.QColor(self.mainwindow.theme["memos/systemMsgColor"])
  462. msg = p.memoopenmsg(systemColor, self.time.getTime(), timeGrammar, self.mainwindow.theme["convo/text/openmemo"], self.channel)
  463. self.time.openCurrentTime()
  464. self.textArea.append(convertTags(msg))
  465. self.mainwindow.chatlog.log(self.channel, msg)
  466. self.op = False
  467. self.newmessage = False
  468. self.history = PesterHistory()
  469. self.applyquirks = True
  470. self.ooc = False
  471. @QtCore.pyqtSlot()
  472. def toggleUserlist(self):
  473. if self.userlist.isHidden():
  474. self.userlist.show()
  475. self.miniUserlist.setText(">\n>")
  476. self.miniUserlist.setStyleSheet("%s border-width: 2px 0px 2px 2px;" % self.miniUserlist.styleSheet())
  477. else:
  478. self.userlist.hide()
  479. self.miniUserlist.setText("<\n<")
  480. self.miniUserlist.setStyleSheet("%s border-width: 2px;" % self.miniUserlist.styleSheet())
  481. def title(self):
  482. return self.channel
  483. def icon(self):
  484. return PesterIcon(self.mainwindow.theme["memos/memoicon"])
  485. def sendTimeInfo(self, newChum=False):
  486. if newChum:
  487. self.messageSent.emit("PESTERCHUM:TIME>%s" % (delta2txt(self.time.getTime(), "server")+"i"),
  488. self.title())
  489. else:
  490. self.messageSent.emit("PESTERCHUM:TIME>%s" % (delta2txt(self.time.getTime(), "server")),
  491. self.title())
  492. def updateMood(self):
  493. pass
  494. def updateBlocked(self):
  495. pass
  496. def updateColor(self, handle, color):
  497. chums = self.userlist.findItems(handle, QtCore.Qt.MatchFlags(0))
  498. for c in chums:
  499. c.setTextColor(color)
  500. def addMessage(self, text, handle):
  501. if type(handle) is bool:
  502. chum = self.mainwindow.profile()
  503. else:
  504. chum = PesterProfile(handle)
  505. self.notifyNewMessage()
  506. self.textArea.addMessage(text, chum)
  507. def initTheme(self, theme):
  508. self.resize(*theme["memos/size"])
  509. self.setStyleSheet("QFrame#%s { %s }" % (self.channel, theme["memos/style"]))
  510. self.setWindowIcon(PesterIcon(theme["memos/memoicon"]))
  511. t = Template(theme["memos/label/text"])
  512. if self.mainwindow.advanced and hasattr(self, 'modes'):
  513. self.channelLabel.setText(t.safe_substitute(channel=self.channel) + "(%s)" % (self.modes))
  514. else:
  515. self.channelLabel.setText(t.safe_substitute(channel=self.channel))
  516. self.channelLabel.setStyleSheet(theme["memos/label/style"])
  517. self.channelLabel.setAlignment(self.aligndict["h"][theme["memos/label/align/h"]] | self.aligndict["v"][theme["memos/label/align/v"]])
  518. self.channelLabel.setMaximumHeight(theme["memos/label/maxheight"])
  519. self.channelLabel.setMinimumHeight(theme["memos/label/minheight"])
  520. self.userlist.optionsMenu.setStyleSheet(theme["main/defaultwindow/style"])
  521. scrolls = "width: 12px; height: 12px; border: 0; padding: 0;"
  522. if theme.has_key("main/chums/scrollbar"):
  523. self.userlist.setStyleSheet("QListWidget { %s } QScrollBar { %s } QScrollBar::handle { %s } QScrollBar::add-line { %s } QScrollBar::sub-line { %s } QScrollBar:up-arrow { %s } QScrollBar:down-arrow { %s }" % (theme["memos/userlist/style"], theme["main/chums/scrollbar/style"] + scrolls, theme["main/chums/scrollbar/handle"], theme["main/chums/scrollbar/downarrow"], theme["main/chums/scrollbar/uparrow"], theme["main/chums/scrollbar/uarrowstyle"], theme["main/chums/scrollbar/darrowstyle"] ))
  524. elif theme.has_key("convo/scrollbar"):
  525. self.userlist.setStyleSheet("QListWidget { %s } QScrollBar { %s } QScrollBar::handle { %s } QScrollBar::add-line { %s } QScrollBar::sub-line { %s } QScrollBar:up-arrow { %s } QScrollBar:down-arrow { %s }" % (theme["memos/userlist/style"], theme["convo/scrollbar/style"] + scrolls, theme["convo/scrollbar/handle"], "display:none;", "display:none;", "display:none;", "display:none;" ))
  526. else:
  527. self.userlist.setStyleSheet("QListWidget { %s } QScrollBar { %s } QScrollBar::handle { %s }" % (theme["memos/userlist/style"], scrolls, "background-color: black;"))
  528. self.userlist.setFixedWidth(theme["memos/userlist/width"])
  529. if self.userlist.isHidden():
  530. borders = "border-width: 2px;"
  531. else:
  532. borders = "border-width: 2px 0px 2px 2px;"
  533. self.miniUserlist.setStyleSheet("%s padding: 0px; margin: 0px; margin-left: 5px; width: 10px; height: 90px; %s" % (theme["memos/userlist/style"], borders))
  534. self.addchumAction.setText(theme["main/menus/rclickchumlist/addchum"])
  535. self.banuserAction.setText(theme["main/menus/rclickchumlist/banuser"])
  536. self.opAction.setText(theme["main/menus/rclickchumlist/opuser"])
  537. self.voiceAction.setText(theme["main/menus/rclickchumlist/voiceuser"])
  538. self.quirkDisableAction.setText(theme["main/menus/rclickchumlist/quirkkill"])
  539. self.quirksOff.setText(theme["main/menus/rclickchumlist/quirksoff"])
  540. self.logchum.setText(theme["main/menus/rclickchumlist/viewlog"])
  541. self.invitechum.setText(theme["main/menus/rclickchumlist/invitechum"])
  542. self.chanModeMenu.setTitle(theme["main/menus/rclickchumlist/memosetting"])
  543. self.chanNoquirks.setText(theme["main/menus/rclickchumlist/memonoquirk"])
  544. self.chanHide.setText(theme["main/menus/rclickchumlist/memohidden"])
  545. self.chanInvite.setText(theme["main/menus/rclickchumlist/memoinvite"])
  546. self.chanMod.setText(theme["main/menus/rclickchumlist/memomute"])
  547. self.timeinput.setFixedWidth(theme["memos/time/text/width"])
  548. self.timeinput.setStyleSheet(theme["memos/time/text/style"])
  549. slidercss = "QSlider { %s } QSlider::groove { %s } QSlider::handle { %s }" % (theme["memos/time/slider/style"], theme["memos/time/slider/groove"], theme["memos/time/slider/handle"])
  550. self.timeslider.setStyleSheet(slidercss)
  551. larrow = PesterIcon(self.mainwindow.theme["memos/time/arrows/left"])
  552. self.timeswitchl.setIcon(larrow)
  553. self.timeswitchl.setIconSize(larrow.realsize())
  554. self.timeswitchl.setStyleSheet(self.mainwindow.theme["memos/time/arrows/style"])
  555. self.timetravel.setStyleSheet(self.mainwindow.theme["memos/time/buttons/style"])
  556. self.timeclose.setStyleSheet(self.mainwindow.theme["memos/time/buttons/style"])
  557. rarrow = PesterIcon(self.mainwindow.theme["memos/time/arrows/right"])
  558. self.timeswitchr.setIcon(rarrow)
  559. self.timeswitchr.setIconSize(rarrow.realsize())
  560. self.timeswitchr.setStyleSheet(self.mainwindow.theme["memos/time/arrows/style"])
  561. def changeTheme(self, theme):
  562. self.initTheme(theme)
  563. self.textArea.changeTheme(theme)
  564. self.textInput.changeTheme(theme)
  565. margins = theme["memos/margins"]
  566. self.layout.setContentsMargins(margins["left"], margins["top"],
  567. margins["right"], margins["bottom"])
  568. for item in [self.userlist.item(i) for i in range(0,self.userlist.count())]:
  569. self.iconCrap(item)
  570. def addUser(self, handle):
  571. chumdb = self.mainwindow.chumdb
  572. defaultcolor = QtGui.QColor("black")
  573. founder = False
  574. op = False
  575. halfop = False
  576. admin = False
  577. voice = False
  578. if handle[0] == '@':
  579. op = True
  580. handle = handle[1:]
  581. if handle == self.mainwindow.profile().handle:
  582. self.userlist.optionsMenu.addAction(self.opAction)
  583. self.userlist.optionsMenu.addAction(self.banuserAction)
  584. self.optionsMenu.addMenu(self.chanModeMenu)
  585. self.op = True
  586. elif handle[0] == '%':
  587. halfop = True
  588. handle = handle[1:]
  589. if handle == self.mainwindow.profile().handle:
  590. self.userlist.optionsMenu.addAction(self.opAction)
  591. self.userlist.optionsMenu.addAction(self.banuserAction)
  592. self.optionsMenu.addMenu(self.chanModeMenu)
  593. self.halfop = True
  594. elif handle[0] == '+':
  595. voice = True
  596. handle = handle[1:]
  597. elif handle[0] == '~':
  598. founder = True
  599. handle = handle[1:]
  600. elif handle[0] == '&':
  601. admin = True
  602. handle = handle[1:]
  603. item = QtGui.QListWidgetItem(handle)
  604. if handle == self.mainwindow.profile().handle:
  605. color = self.mainwindow.profile().color
  606. else:
  607. color = chumdb.getColor(handle, defaultcolor)
  608. item.box = (handle == "evacipatedBox")
  609. item.setTextColor(color)
  610. item.founder = founder
  611. item.op = op
  612. item.halfop = halfop
  613. item.admin = admin
  614. item.voice = voice
  615. self.umodes = ["box", "founder", "admin", "op", "halfop", "voice"]
  616. self.iconCrap(item)
  617. self.userlist.addItem(item)
  618. self.sortUsers()
  619. def sortUsers(self):
  620. users = []
  621. listing = self.userlist.item(0)
  622. while listing is not None:
  623. users.append(self.userlist.takeItem(0))
  624. listing = self.userlist.item(0)
  625. users.sort(key=lambda x: ((-1 if x.box else (0 if x.founder else (1 if x.admin else (2 if x.op else (3 if x.halfop else (4 if x.voice else 5)))))), x.text()))
  626. for u in users:
  627. self.userlist.addItem(u)
  628. def updateChanModes(self, modes, op):
  629. if not hasattr(self, 'modes'): self.modes = ""
  630. chanmodes = list(str(self.modes))
  631. if chanmodes and chanmodes[0] == "+": chanmodes = chanmodes[1:]
  632. modes = str(modes)
  633. if op:
  634. systemColor = QtGui.QColor(self.mainwindow.theme["memos/systemMsgColor"])
  635. chum = self.mainwindow.profile()
  636. opchum = PesterProfile(op)
  637. if self.times.has_key(op):
  638. opgrammar = self.times[op].getGrammar()
  639. elif op == self.mainwindow.profile().handle:
  640. opgrammar = self.time.getGrammar()
  641. else:
  642. opgrammar = TimeGrammar("CURRENT", "C", "RIGHT NOW")
  643. if modes[0] == "+":
  644. for m in modes[1:]:
  645. if m not in chanmodes:
  646. chanmodes.extend(m)
  647. # Make +c (disable ANSI colours) disable quirks.
  648. if modes.find("c") >= 0:
  649. self.chanNoquirks.setChecked(True)
  650. self.quirksOff.setChecked(True)
  651. self.applyquirks = False
  652. if op:
  653. msg = chum.memomodemsg(opchum, opgrammar, systemColor, "A No-Quirk zone", True)
  654. self.textArea.append(convertTags(msg))
  655. self.mainwindow.chatlog.log(self.channel, msg)
  656. if modes.find("s") >= 0:
  657. self.chanHide.setChecked(True)
  658. if op:
  659. msg = chum.memomodemsg(opchum, opgrammar, systemColor, "Secret", True)
  660. self.textArea.append(convertTags(msg))
  661. self.mainwindow.chatlog.log(self.channel, msg)
  662. if modes.find("i") >= 0:
  663. self.chanInvite.setChecked(True)
  664. if op:
  665. msg = chum.memomodemsg(opchum, opgrammar, systemColor, "Invite-Only", True)
  666. self.textArea.append(convertTags(msg))
  667. self.mainwindow.chatlog.log(self.channel, msg)
  668. if modes.find("m") >= 0:
  669. self.chanMod.setChecked(True)
  670. if op:
  671. msg = chum.memomodemsg(opchum, opgrammar, systemColor, "Muted", True)
  672. self.textArea.append(convertTags(msg))
  673. self.mainwindow.chatlog.log(self.channel, msg)
  674. elif modes[0] == "-":
  675. for i in modes[1:]:
  676. try:
  677. chanmodes.remove(i)
  678. except ValueError:
  679. pass
  680. if modes.find("c") >= 0:
  681. self.chanNoquirks.setChecked(False)
  682. if op:
  683. msg = chum.memomodemsg(opchum, opgrammar, systemColor, "A No-Quirk zone", False)
  684. self.textArea.append(convertTags(msg))
  685. self.mainwindow.chatlog.log(self.channel, msg)
  686. if modes.find("s") >= 0:
  687. self.chanHide.setChecked(False)
  688. if op:
  689. msg = chum.memomodemsg(opchum, opgrammar, systemColor, "Secret", False)
  690. self.textArea.append(convertTags(msg))
  691. self.mainwindow.chatlog.log(self.channel, msg)
  692. if modes.find("i") >= 0:
  693. self.chanInvite.setChecked(False)
  694. if op:
  695. msg = chum.memomodemsg(opchum, opgrammar, systemColor, "Invite-Only", False)
  696. self.textArea.append(convertTags(msg))
  697. self.mainwindow.chatlog.log(self.channel, msg)
  698. if modes.find("m") >= 0:
  699. self.chanMod.setChecked(False)
  700. if op:
  701. msg = chum.memomodemsg(opchum, opgrammar, systemColor, "Muted", False)
  702. self.textArea.append(convertTags(msg))
  703. self.mainwindow.chatlog.log(self.channel, msg)
  704. chanmodes.sort()
  705. self.modes = "+" + "".join(chanmodes)
  706. if self.mainwindow.advanced:
  707. t = Template(self.mainwindow.theme["memos/label/text"])
  708. self.channelLabel.setText(t.safe_substitute(channel=self.channel) + "(%s)" % (self.modes))
  709. def timeUpdate(self, handle, cmd):
  710. window = self.mainwindow
  711. chum = PesterProfile(handle)
  712. systemColor = QtGui.QColor(window.theme["memos/systemMsgColor"])
  713. close = None
  714. # old TC command?
  715. try:
  716. secs = int(cmd)
  717. time = datetime.fromtimestamp(secs)
  718. timed = time - datetime.now()
  719. s = (timed.seconds // 60)*60
  720. timed = timedelta(timed.days, s)
  721. except ValueError:
  722. if cmd == "i":
  723. timed = timedelta(0)
  724. else:
  725. if cmd[len(cmd)-1] == 'c':
  726. close = timeProtocol(cmd)
  727. timed = None
  728. else:
  729. timed = timeProtocol(cmd)
  730. if self.times.has_key(handle):
  731. if close is not None:
  732. if close in self.times[handle]:
  733. self.times[handle].setCurrent(close)
  734. grammar = self.times[handle].getGrammar()
  735. self.times[handle].removeTime(close)
  736. msg = chum.memoclosemsg(systemColor, grammar, window.theme["convo/text/closememo"])
  737. self.textArea.append(convertTags(msg))
  738. self.mainwindow.chatlog.log(self.channel, msg)
  739. elif timed not in self.times[handle]:
  740. self.times[handle].addTime(timed)
  741. else:
  742. self.times[handle].setCurrent(timed)
  743. else:
  744. if timed is not None:
  745. ttracker = TimeTracker(timed)
  746. self.times[handle] = ttracker
  747. @QtCore.pyqtSlot()
  748. def sentMessage(self):
  749. text = unicode(self.textInput.text())
  750. if text == "" or text[0:11] == "PESTERCHUM:":
  751. return
  752. oocDetected = oocre.match(text.strip())
  753. if self.ooc and not oocDetected:
  754. text = "(( %s ))" % (text)
  755. self.history.add(text)
  756. if self.time.getTime() == None:
  757. self.sendtime()
  758. grammar = self.time.getGrammar()
  759. quirks = self.mainwindow.userprofile.quirks
  760. lexmsg = lexMessage(text)
  761. if type(lexmsg[0]) is not mecmd:
  762. if self.applyquirks and not (self.ooc or oocDetected):
  763. lexmsg = quirks.apply(lexmsg)
  764. initials = self.mainwindow.profile().initials()
  765. colorcmd = self.mainwindow.profile().colorcmd()
  766. clientMsg = [colorBegin("<c=%s>" % (colorcmd), colorcmd),
  767. "%s%s%s: " % (grammar.pcf, initials, grammar.number)] + lexmsg + [colorEnd("</c>")]
  768. # account for TC's parsing error
  769. serverMsg = [colorBegin("<c=%s>" % (colorcmd), colorcmd),
  770. "%s: " % (initials)] + lexmsg + [colorEnd("</c>"), " "]
  771. else:
  772. clientMsg = copy(lexmsg)
  773. serverMsg = copy(lexmsg)
  774. self.addMessage(clientMsg, True)
  775. serverText = convertTags(serverMsg, "ctag")
  776. self.messageSent.emit(serverText, self.title())
  777. self.textInput.setText("")
  778. @QtCore.pyqtSlot(QtCore.QString)
  779. def namesUpdated(self, channel):
  780. c = unicode(channel)
  781. if c.lower() != self.channel.lower(): return
  782. # get namesdb
  783. namesdb = self.mainwindow.namesdb
  784. # reload names
  785. self.userlist.clear()
  786. for n in self.mainwindow.namesdb[self.channel]:
  787. self.addUser(n)
  788. @QtCore.pyqtSlot(QtCore.QString, QtCore.QString)
  789. def modesUpdated(self, channel, modes):
  790. c = unicode(channel)
  791. if c.lower() == self.channel.lower():
  792. self.updateChanModes(modes, None)
  793. @QtCore.pyqtSlot(QtCore.QString)
  794. def closeInviteOnly(self, channel):
  795. c = unicode(channel)
  796. if c.lower() == self.channel.lower():
  797. self.disconnect(self.mainwindow, QtCore.SIGNAL('inviteOnlyChan(QString)'),
  798. self, QtCore.SLOT('closeInviteOnly(QString)'))
  799. if self.parent():
  800. print self.channel
  801. i = self.parent().tabIndices[self.channel]
  802. self.parent().tabClose(i)
  803. else:
  804. self.close()
  805. msgbox = QtGui.QMessageBox()
  806. msgbox.setText("%s: Invites only!" % (c))
  807. msgbox.setInformativeText("This channel is invite-only. You must get an invitation from someone on the inside before entering.")
  808. msgbox.setStandardButtons(QtGui.QMessageBox.Ok)
  809. ret = msgbox.exec_()
  810. def quirkDisable(self, op, msg):
  811. chums = self.userlist.findItems(op, QtCore.Qt.MatchFlags(0))
  812. for c in chums:
  813. if c.op:
  814. if msg == self.mainwindow.profile().handle:
  815. self.quirksOff.setChecked(True)
  816. self.applyquirks = False
  817. systemColor = QtGui.QColor(self.mainwindow.theme["memos/systemMsgColor"])
  818. chum = self.mainwindow.profile()
  819. opchum = PesterProfile(op)
  820. if self.times.has_key(op):
  821. opgrammar = self.times[op].getGrammar()
  822. elif op == self.mainwindow.profile().handle:
  823. opgrammar = self.time.getGrammar()
  824. else:
  825. opgrammar = TimeGrammar("CURRENT", "C", "RIGHT NOW")
  826. msg = chum.memoquirkkillmsg(opchum, opgrammar, systemColor)
  827. self.textArea.append(convertTags(msg))
  828. self.mainwindow.chatlog.log(self.channel, msg)
  829. def chumOPstuff(self, h, op):
  830. chum = PesterProfile(h)
  831. if h == self.mainwindow.profile().handle:
  832. chum = self.mainwindow.profile()
  833. ttracker = self.time
  834. curtime = self.time.getTime()
  835. elif self.times.has_key(h):
  836. ttracker = self.times[h]
  837. else:
  838. ttracker = TimeTracker(timedelta(0))
  839. opchum = PesterProfile(op)
  840. if self.times.has_key(op):
  841. opgrammar = self.times[op].getGrammar()
  842. elif op == self.mainwindow.profile().handle:
  843. opgrammar = self.time.getGrammar()
  844. else:
  845. opgrammar = TimeGrammar("CURRENT", "C", "RIGHT NOW")
  846. return (chum, opchum, opgrammar)
  847. def iconCrap(self, c, down=True):
  848. for m in (self.umodes if down else reversed(self.umodes)):
  849. if eval("c."+m):
  850. if m == "box":
  851. icon = PesterIcon("smilies/box.png")
  852. else:
  853. icon = PesterIcon(self.mainwindow.theme["memos/"+m+"/icon"])
  854. c.setIcon(icon)
  855. return
  856. icon = QtGui.QIcon()
  857. c.setIcon(icon)
  858. @QtCore.pyqtSlot()
  859. def dumpNetsplit(self):
  860. if (len(self.netsplit) > 0):
  861. chum = self.mainwindow.profile()
  862. systemColor = QtGui.QColor(self.mainwindow.theme["memos/systemMsgColor"])
  863. msg = chum.memonetsplitmsg(systemColor, self.netsplit)
  864. self.textArea.append(convertTags(msg))
  865. self.mainwindow.chatlog.log(self.channel, msg)
  866. del self.netsplit
  867. @QtCore.pyqtSlot(QtCore.QString, QtCore.QString, QtCore.QString)
  868. def userPresentChange(self, handle, channel, update):
  869. h = unicode(handle)
  870. c = unicode(channel)
  871. update = unicode(update)
  872. if update[0:4] == "kick": # yeah, i'm lazy.
  873. l = update.split(":")
  874. update = l[0]
  875. op = l[1]
  876. reason = ":".join(l[2:])
  877. if update == "nick":
  878. l = h.split(":")
  879. oldnick = l[0]
  880. newnick = l[1]
  881. h = oldnick
  882. if update[0:1] in ["+", "-"]:
  883. l = update.split(":")
  884. update = l[0]
  885. op = l[1]
  886. if (update in ["join","left", "kick", \
  887. "+q", "-q", "+o", "-o", "+h", "-h", \
  888. "+a", "-a", "+v", "-v"]) \
  889. and c.lower() != self.channel.lower():
  890. return
  891. chums = self.userlist.findItems(h, QtCore.Qt.MatchFlags(0))
  892. systemColor = QtGui.QColor(self.mainwindow.theme["memos/systemMsgColor"])
  893. # print exit
  894. if update in ("quit", "left", "nick", "netsplit"):
  895. if update == "netsplit":
  896. if not hasattr(self, "netsplit"):
  897. self.netsplit = []
  898. QtCore.QTimer.singleShot(1500, self, QtCore.SLOT('dumpNetsplit()'))
  899. for c in chums:
  900. chum = PesterProfile(h)
  901. self.userlist.takeItem(self.userlist.row(c))
  902. if not self.times.has_key(h):
  903. self.times[h] = TimeTracker(timedelta(0))
  904. allinitials = []
  905. while self.times[h].getTime() is not None:
  906. t = self.times[h]
  907. grammar = t.getGrammar()
  908. allinitials.append("%s%s%s" % (grammar.pcf, chum.initials(), grammar.number))
  909. self.times[h].removeTime(t.getTime())
  910. if update == "netsplit":
  911. self.netsplit.extend(allinitials)
  912. else:
  913. msg = chum.memoclosemsg(systemColor, allinitials, self.mainwindow.theme["convo/text/closememo"])
  914. self.textArea.append(convertTags(msg))
  915. self.mainwindow.chatlog.log(self.channel, msg)
  916. if update == "nick":
  917. self.addUser(newnick)
  918. newchums = self.userlist.findItems(newnick, QtCore.Qt.MatchFlags(0))
  919. for nc in newchums:
  920. for c in chums:
  921. nc.founder = c.founder
  922. nc.op = c.op
  923. nc.halfop = c.halfop
  924. nc.admin = c.admin
  925. self.iconCrap(nc)
  926. self.sortUsers()
  927. elif update == "kick":
  928. if len(chums) == 0:
  929. return
  930. c = chums[0]
  931. chum = PesterProfile(h)
  932. if h == self.mainwindow.profile().handle:
  933. chum = self.mainwindow.profile()
  934. ttracker = self.time
  935. curtime = self.time.getTime()
  936. elif self.times.has_key(h):
  937. ttracker = self.times[h]
  938. else:
  939. ttracker = TimeTracker(timedelta(0))
  940. allinitials = []
  941. opchum = PesterProfile(op)
  942. if self.times.has_key(op):
  943. opgrammar = self.times[op].getGrammar()
  944. elif op == self.mainwindow.profile().handle:
  945. opgrammar = self.time.getGrammar()
  946. else:
  947. opgrammar = TimeGrammar("CURRENT", "C", "RIGHT NOW")
  948. while ttracker.getTime() is not None:
  949. grammar = ttracker.getGrammar()
  950. allinitials.append("%s%s%s" % (grammar.pcf, chum.initials(), grammar.number))
  951. ttracker.removeTime(ttracker.getTime())
  952. msg = chum.memobanmsg(opchum, opgrammar, systemColor, allinitials, reason)
  953. self.textArea.append(convertTags(msg))
  954. self.mainwindow.chatlog.log(self.channel, msg)
  955. if chum is self.mainwindow.profile():
  956. # are you next?
  957. msgbox = QtGui.QMessageBox()
  958. msgbox.setText(self.mainwindow.theme["convo/text/kickedmemo"])
  959. msgbox.setInformativeText("press 0k to rec0nnect or cancel to absc0nd")
  960. msgbox.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel)
  961. ret = msgbox.exec_()
  962. if ret == QtGui.QMessageBox.Ok:
  963. self.userlist.clear()
  964. self.time = TimeTracker(curtime)
  965. self.resetSlider(curtime)
  966. self.mainwindow.joinChannel.emit(self.channel)
  967. me = self.mainwindow.profile()
  968. self.time.openCurrentTime()
  969. msg = me.memoopenmsg(systemColor, self.time.getTime(), self.time.getGrammar(), self.mainwindow.theme["convo/text/openmemo"], self.channel)
  970. self.textArea.append(convertTags(msg))
  971. self.mainwindow.chatlog.log(self.channel, msg)
  972. elif ret == QtGui.QMessageBox.Cancel:
  973. if self.parent():
  974. i = self.parent().tabIndices[self.channel]
  975. self.parent().tabClose(i)
  976. else:
  977. self.close()
  978. else:
  979. # i warned you about those stairs bro
  980. self.userlist.takeItem(self.userlist.row(c))
  981. elif update == "join":
  982. self.addUser(h)
  983. time = self.time.getTime()
  984. serverText = "PESTERCHUM:TIME>"+delta2txt(time, "server")
  985. self.messageSent.emit(serverText, self.title())
  986. elif update == "+q":
  987. for c in chums:
  988. c.founder = True
  989. self.iconCrap(c)
  990. self.sortUsers()
  991. elif update == "-q":
  992. for c in chums:
  993. c.founder = False
  994. self.iconCrap(c)
  995. self.sortUsers()
  996. elif update == "+o":
  997. if self.mainwindow.config.opvoiceMessages():
  998. (chum, opchum, opgrammar) = self.chumOPstuff(h, op)
  999. msg = chum.memoopmsg(opchum, opgrammar, systemColor)
  1000. self.textArea.append(convertTags(msg))
  1001. self.mainwindow.chatlog.log(self.channel, msg)
  1002. for c in chums:
  1003. c.op = True
  1004. self.iconCrap(c)
  1005. if unicode(c.text()) == self.mainwindow.profile().handle:
  1006. self.userlist.optionsMenu.addAction(self.opAction)
  1007. self.userlist.optionsMenu.addAction(self.voiceAction)
  1008. self.userlist.optionsMenu.addAction(self.banuserAction)
  1009. self.userlist.optionsMenu.addAction(self.quirkDisableAction)
  1010. self.optionsMenu.addMenu(self.chanModeMenu)
  1011. self.sortUsers()
  1012. elif update == "-o":
  1013. self.mainwindow.channelNames.emit(self.channel)
  1014. if self.mainwindow.config.opvoiceMessages():
  1015. (chum, opchum, opgrammar) = self.chumOPstuff(h, op)
  1016. msg = chum.memodeopmsg(opchum, opgrammar, systemColor)
  1017. self.textArea.append(convertTags(msg))
  1018. self.mainwindow.chatlog.log(self.channel, msg)
  1019. for c in chums:
  1020. c.op = False
  1021. self.iconCrap(c)
  1022. if unicode(c.text()) == self.mainwindow.profile().handle:
  1023. self.userlist.optionsMenu.removeAction(self.opAction)
  1024. self.userlist.optionsMenu.removeAction(self.voiceAction)
  1025. self.userlist.optionsMenu.removeAction(self.banuserAction)
  1026. self.userlist.optionsMenu.removeAction(self.quirkDisableAction)
  1027. self.optionsMenu.removeAction(self.chanModeMenu.menuAction())
  1028. self.sortUsers()
  1029. elif update == "+h":
  1030. if self.mainwindow.config.opvoiceMessages():
  1031. (chum, opchum, opgrammar) = self.chumOPstuff(h, op)
  1032. msg = chum.memoopmsg(opchum, opgrammar, systemColor)
  1033. self.textArea.append(convertTags(msg))
  1034. self.mainwindow.chatlog.log(self.channel, msg)
  1035. for c in chums:
  1036. c.halfop = True
  1037. self.iconCrap(c)
  1038. if unicode(c.text()) == self.mainwindow.profile().handle:
  1039. self.userlist.optionsMenu.addAction(self.opAction)
  1040. self.userlist.optionsMenu.addAction(self.voiceAction)
  1041. self.userlist.optionsMenu.addAction(self.banuserAction)
  1042. self.userlist.optionsMenu.addAction(self.quirkDisableAction)
  1043. self.optionsMenu.addMenu(self.chanModeMenu)
  1044. self.sortUsers()
  1045. elif update == "-h":
  1046. self.mainwindow.channelNames.emit(self.channel)
  1047. if self.mainwindow.config.opvoiceMessages():
  1048. (chum, opchum, opgrammar) = self.chumOPstuff(h, op)
  1049. msg = chum.memodeopmsg(opchum, opgrammar, systemColor)
  1050. self.textArea.ap

Large files files are truncated, but you can click here to view the full file