Completed Toast Notifications. Includes all options, working custom toast

This commit is contained in:
Kiooeht 2011-08-27 10:51:50 -07:00
parent 26f6b2a2f4
commit d9a742d90c
7 changed files with 342 additions and 76 deletions

View file

@ -28,6 +28,8 @@ CHANGELOG
* Customizable name alerts - Kiooeht [evacipatedBox]
* Update bug reporter - Kiooeht [evacipatedBox]
* Explain why a chumhandle is invalid - Kiooeht [evacipatedBox] (Idea: Lexi [lexicalNuance])
* Netsplit notification in memos - Kiooeht [evacipatedBox]
* Toast Notifications - Kiooeht [evacipatedBox]
* Bug fixes
* Don't delete random chum when blocking someone not on chumroll - Kiooeht [evacipatedBox]
* Openning global userlist doesn't reset OP status of memo users - Kiooeht [evacipatedBox]

View file

@ -18,6 +18,7 @@ Features
* Fully working Toasts
* Auto download/install updates via Windows installer
* Turn memo notifications on/off from right-click menu on memos (Idea: lostGash)
* Gray out random encounter option when RE is offline
Bugs
----

View file

@ -996,7 +996,7 @@ class PesterOptions(QtGui.QDialog):
self.tabs = QtGui.QButtonGroup(self)
self.connect(self.tabs, QtCore.SIGNAL('buttonClicked(int)'),
self, QtCore.SLOT('changePage(int)'))
tabNames = ["Chum List", "Conversations", "Interface", "Sound", "Logging", "Idle/Updates", "Theme"]
tabNames = ["Chum List", "Conversations", "Interface", "Sound", "Notifications", "Logging", "Idle/Updates", "Theme"]
if parent.advanced: tabNames.append("Advanced")
for t in tabNames:
button = QtGui.QPushButton(t)
@ -1038,6 +1038,9 @@ class PesterOptions(QtGui.QDialog):
self.editMentions = QtGui.QPushButton("Edit Mentions", self)
self.connect(self.editMentions, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('openMentions()'))
self.editMentions2 = QtGui.QPushButton("Edit Mentions", self)
self.connect(self.editMentions2, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('openMentions()'))
self.volume = QtGui.QSlider(QtCore.Qt.Horizontal, self)
self.volume.setMinimum(0)
@ -1186,6 +1189,21 @@ class PesterOptions(QtGui.QDialog):
layout_type = QtGui.QHBoxLayout()
layout_type.addWidget(self.notifyTypeLabel)
layout_type.addWidget(self.notifyOptions)
self.notifySigninCheck = QtGui.QCheckBox("Chum signs in", self)
if self.config.notifyOptions() & self.config.SIGNIN:
self.notifySigninCheck.setChecked(True)
self.notifySignoutCheck = QtGui.QCheckBox("Chum signs out", self)
if self.config.notifyOptions() & self.config.SIGNOUT:
self.notifySignoutCheck.setChecked(True)
self.notifyNewMsgCheck = QtGui.QCheckBox("New messages", self)
if self.config.notifyOptions() & self.config.NEWMSG:
self.notifyNewMsgCheck.setChecked(True)
self.notifyNewConvoCheck = QtGui.QCheckBox("Only new conversations", self)
if self.config.notifyOptions() & self.config.NEWCONVO:
self.notifyNewConvoCheck.setChecked(True)
self.notifyMentionsCheck = QtGui.QCheckBox("Memo Mentions (initials)", self)
if self.config.notifyOptions() & self.config.INITIALS:
self.notifyMentionsCheck.setChecked(True)
self.notifyChange(self.notifycheck.checkState())
if parent.advanced:
@ -1245,13 +1263,6 @@ class PesterOptions(QtGui.QDialog):
layout_interface.addLayout(layout_close)
layout_interface.addWidget(self.pesterBlink)
layout_interface.addWidget(self.memoBlink)
layout_interface.addSpacing(16)
layout_interface.addWidget(QtGui.QLabel("NOT FULLY COMPLETE YET:"))
layout_interface.addWidget(self.notifycheck)
layout_indent = QtGui.QVBoxLayout()
layout_indent.addLayout(layout_type)
layout_indent.setContentsMargins(22,0,0,0)
layout_interface.addLayout(layout_indent)
self.pages.addWidget(widget)
# Sound
@ -1276,6 +1287,26 @@ class PesterOptions(QtGui.QDialog):
layout_sound.addWidget(self.currentVol)
self.pages.addWidget(widget)
# Notifications
widget = QtGui.QWidget()
layout_notify = QtGui.QVBoxLayout(widget)
layout_notify.setAlignment(QtCore.Qt.AlignTop)
layout_notify.addWidget(self.notifycheck)
layout_indent = QtGui.QVBoxLayout()
layout_indent.addLayout(layout_type)
layout_indent.setContentsMargins(22,0,0,0)
layout_indent.addWidget(self.notifySigninCheck)
layout_indent.addWidget(self.notifySignoutCheck)
layout_indent.addWidget(self.notifyNewMsgCheck)
layout_doubleindent = QtGui.QVBoxLayout()
layout_doubleindent.addWidget(self.notifyNewConvoCheck)
layout_doubleindent.setContentsMargins(22,0,0,0)
layout_indent.addLayout(layout_doubleindent)
layout_indent.addWidget(self.notifyMentionsCheck)
layout_indent.addWidget(self.editMentions2)
layout_notify.addLayout(layout_indent)
self.pages.addWidget(widget)
# Logging
widget = QtGui.QWidget()
layout_logs = QtGui.QVBoxLayout(widget)
@ -1335,9 +1366,19 @@ class PesterOptions(QtGui.QDialog):
if state == 0:
self.notifyTypeLabel.setEnabled(False)
self.notifyOptions.setEnabled(False)
self.notifySigninCheck.setEnabled(False)
self.notifySignoutCheck.setEnabled(False)
self.notifyNewMsgCheck.setEnabled(False)
self.notifyNewConvoCheck.setEnabled(False)
self.notifyMentionsCheck.setEnabled(False)
else:
self.notifyTypeLabel.setEnabled(True)
self.notifyOptions.setEnabled(True)
self.notifySigninCheck.setEnabled(True)
self.notifySignoutCheck.setEnabled(True)
self.notifyNewMsgCheck.setEnabled(True)
self.notifyNewConvoCheck.setEnabled(True)
self.notifyMentionsCheck.setEnabled(True)
@QtCore.pyqtSlot(int)
def soundChange(self, state):

View file

@ -328,6 +328,12 @@ class userConfig(object):
# Use for bit flag blink
self.PBLINK = 1
self.MBLINK = 2
# Use for bit flag notfications
self.SIGNIN = 1
self.SIGNOUT = 2
self.NEWMSG = 4
self.NEWCONVO = 8
self.INITIALS = 16
self.filename = _datadir+"pesterchum.js"
fp = open(self.filename)
self.config = json.load(fp)
@ -435,6 +441,8 @@ class userConfig(object):
return self.config.get('notify', True)
def notifyType(self):
return self.config.get('notifyType', "default")
def notifyOptions(self):
return self.config.get('notifyOptions', self.SIGNIN | self.NEWMSG | self.NEWCONVO | self.INITIALS)
def addChum(self, chum):
if chum.handle not in self.chums():
fp = open(self.filename) # what if we have two clients open??
@ -689,18 +697,20 @@ class chumListing(QtGui.QTreeWidgetItem):
def setMood(self, mood):
if hasattr(self.mainwindow, "chumList") and self.mainwindow.chumList.notify:
#print "%s -> %s" % (self.chum.mood.name(), mood.name())
if mood.name() == "offline" and self.chum.mood.name() != "offline":
if self.mainwindow.config.notifyOptions() & self.mainwindow.config.SIGNOUT and \
mood.name() == "offline" and self.chum.mood.name() != "offline":
#print "OFFLINE NOTIFY: " + self.handle
uri = "file://" + os.path.abspath(os.path.curdir) + "/themes/enamel/distraught2.gif"
uri = self.mainwindow.theme["toasts/icon/signout"]
n = self.mainwindow.tm.Toast(self.mainwindow.tm.appName,
"%s is Offline" % (self.handle), uri)
#n.show()
elif mood.name() != "offline" and self.chum.mood.name() == "offline":
n.show()
elif self.mainwindow.config.notifyOptions() & self.mainwindow.config.SIGNIN and \
mood.name() != "offline" and self.chum.mood.name() == "offline":
#print "ONLINE NOTIFY: " + self.handle
uri = "file://" + os.path.abspath(os.path.curdir) + "/themes/enamel/chummy2.gif"
uri = self.mainwindow.theme["toasts/icon/signin"]
n = self.mainwindow.tm.Toast(self.mainwindow.tm.appName,
"%s is Online" % (self.handle), uri)
#n.show()
n.show()
login = False
logout = False
if mood.name() == "offline" and self.chum.mood.name() != "offline":
@ -1596,11 +1606,12 @@ class PesterWindow(MovingWindow):
themeWarning.exec_()
self.theme = pesterTheme("pesterchum")
extraToasts = {'default': PesterToast}
if pytwmn.confExists():
extraToasts['twmn'] = pytwmn.Notification
self.tm = PesterToastMachine(self, lambda: self.theme["main/windowtitle"], on=self.config.notify(),
type=self.config.notifyType(), extras={'pester': PesterToast, 'twmn': pytwmn.Notification})
type=self.config.notifyType(), extras=extraToasts)
self.tm.run()
t = self.tm.Toast(self.tm.appName, "!!---Started up ToastMachine---!!")
t.show()
self.chatlog = PesterLog(self.profile().handle, self)
@ -1856,6 +1867,25 @@ class PesterWindow(MovingWindow):
#yeah suck on this
self.sendMessage.emit("PESTERCHUM:BLOCKED", handle)
return
# notify
if self.config.notifyOptions() & self.config.NEWMSG:
if not self.convos.has_key(handle):
t = self.tm.Toast("New Conversation", "From: %s" % handle)
t.show()
elif not self.config.notifyOptions() & self.config.NEWCONVO:
if msg[:11] != "PESTERCHUM:":
t = self.tm.Toast("From: %s" % handle, re.sub("</?c(=.*?)?>", "", msg))
t.show()
else:
if msg == "PESTERCHUM:CEASE":
t = self.tm.Toast("Closed Conversation", handle)
t.show()
elif msg == "PESTERCHUM:BLOCK":
t = self.tm.Toast("Blocked", handle)
t.show()
elif msg == "PESTERCHUM:UNBLOCK":
t = self.tm.Toast("Unblocked", handle)
t.show()
if not self.convos.has_key(handle):
if msg == "PESTERCHUM:CEASE": # ignore cease after we hang up
return
@ -1902,6 +1932,9 @@ class PesterWindow(MovingWindow):
m = m[m.find(":"):]
for search in self.userprofile.getMentions():
if re.search(search, m):
if self.config.notifyOptions() & self.config.INITIALS:
t = self.tm.Toast(chan, re.sub("</?c(=.*?)?>", "", msg))
t.show()
self.namesound.play()
return
if self.honk and re.search(r"\bhonk\b", convertTags(msg, "text"), re.I):
@ -2869,15 +2902,29 @@ class PesterWindow(MovingWindow):
# Taskbar blink
blinksetting = 0
if self.optionmenu.pesterBlink.isChecked():
blinksetting = blinksetting | self.config.PBLINK
blinksetting |= self.config.PBLINK
if self.optionmenu.memoBlink.isChecked():
blinksetting = blinksetting | self.config.MBLINK
blinksetting |= self.config.MBLINK
curblink = self.config.blink()
if blinksetting != curblink:
self.config.set('blink', blinksetting)
# toast notifications
self.tm.setEnabled(self.optionmenu.notifycheck.isChecked())
self.tm.setCurrentType(str(self.optionmenu.notifyOptions.currentText()))
notifysetting = 0
if self.optionmenu.notifySigninCheck.isChecked():
notifysetting |= self.config.SIGNIN
if self.optionmenu.notifySignoutCheck.isChecked():
notifysetting |= self.config.SIGNOUT
if self.optionmenu.notifyNewMsgCheck.isChecked():
notifysetting |= self.config.NEWMSG
if self.optionmenu.notifyNewConvoCheck.isChecked():
notifysetting |= self.config.NEWCONVO
if self.optionmenu.notifyMentionsCheck.isChecked():
notifysetting |= self.config.INITIALS
curnotify = self.config.notifyOptions()
if notifysetting != curnotify:
self.config.set('notifyOptions', notifysetting)
# advanced
## user mode
if self.advanced:

View file

@ -319,5 +319,18 @@
"voice": { "icon": "$path/voice.png" },
"founder": { "icon": "$path/founder.png" },
"admin": { "icon": "$path/admin.png" }
},
"toasts":
{
"width": 210,
"height": 100,
"style": "background: white;",
"icon": { "signin": "$path/../enamel/chummy2.gif",
"signout": "$path/../enamel/distraught2.gif",
"style": "border: 2px solid black; border-width: 2px 0px 0px 2px;" },
"title": { "minimumheight": 50,
"style": "border: 2px solid black; border-width: 2px 2px 0px 0px; padding: 5px; font-weight:bold;"
},
"content": { "style": "background: black; color: white; padding: 5px;" }
}
}

View file

@ -349,5 +349,18 @@
"op": { "icon": "$path/op.png" },
"halfop": { "icon": "$path/halfop.png" },
"voice": { "icon": "$path/voice.png" }
},
"toasts":
{
"width": 210,
"height": 100,
"style": "background: white;",
"icon": { "signin": "$path/../enamel/ecstatic2.gif",
"signout": "$path/../enamel/discontent2.gif",
"style": "border: 2px solid black; border-width: 2px 0px 0px 2px;" },
"title": { "minimumheight": 50,
"style": "border: 2px solid black; border-width: 2px 2px 0px 0px; padding: 5px; font-weight:bold;"
},
"content": { "style": "background: black; color: white; padding: 5px;" }
}
}

253
toast.py
View file

@ -1,6 +1,6 @@
import inspect
import threading
import time
import time, os
from PyQt4 import QtGui, QtCore
try:
@ -9,12 +9,20 @@ except:
pynotify = None
class DefaultToast(object):
def __init__(self, title, msg, icon):
def __init__(self, machine, title, msg, icon):
self.machine = machine
self.title = title
self.msg = msg
self.icon = icon
def show(self):
print self.title, self.msg, self.icon
self.done()
def done(self):
t = self.machine.toasts[0]
if t.title == self.title and t.msg == self.msg and t.icon == self.icon:
self.machine.toasts.pop(0)
self.machine.displaying = False
print "Done"
class ToastMachine(object):
class __Toast__(object):
@ -23,6 +31,8 @@ class ToastMachine(object):
self.title = title
self.msg = msg
self.time = time
if icon:
icon = os.path.abspath(icon)
self.icon = icon
self.importance = importance
if inspect.ismethod(self.title) or inspect.isfunction(self.title):
@ -59,10 +69,20 @@ class ToastMachine(object):
self.realShow()
def realShow(self):
self.machine.displaying = True
t = None
for (k,v) in self.machine.types.iteritems():
if self.machine.type == k:
t = v(self.title, self.msg, self.icon)
args = inspect.getargspec(v.__init__).args
extras = {}
if 'parent' in args:
extras['parent'] = self.machine.parent
if 'time' in args:
extras['time'] = self.time
if k == "libnotify" or k == "twmn":
t = v(self.title, self.msg, self.icon, **extras)
else:
t = v(self.machine, self.title, self.msg, self.icon, **extras)
# Use libnotify's urgency setting
if k == "libnotify":
if self.importance < 0:
@ -74,17 +94,13 @@ class ToastMachine(object):
break
if not t:
if 'default' in self.machine.types:
if 'parent' in inspect.getargspec(self.machine.types['default']).args:
t = self.machine.types['default'](self.title, self.msg, self.icon, self.machine.parent)
if 'parent' in inspect.getargspec(self.machine.types['default'].__init__).args:
t = self.machine.types['default'](self.machine, self.title, self.msg, self.icon, self.machine.parent)
else:
t = self.machine.types['default'](self.title, self.msg, self.icon)
t = self.machine.types['default'](self.machine, self.title, self.msg, self.icon)
else:
t = DefaultToast(self.title, self.msg, self.icon)
t.show()
print "SLEEPING"
#time.sleep(self.time/1000)
if self in self.machine.toasts:
self.machine.toasts.remove(self)
def __init__(self, parent, name, on=True, type="default",
types=({'default' : DefaultToast,
@ -99,13 +115,14 @@ class ToastMachine(object):
self.types = types
self.type = "default"
self.quit = False
self.displaying = False
self.setCurrentType(type)
self.toasts = []
def Toast(self, title, msg, icon=""):
return self.__Toast__(self, title, msg, time=0, icon=icon)
def Toast(self, title, msg, icon="", time=3000):
return self.__Toast__(self, title, msg, time=time, icon=icon)
def setEnabled(self, on):
self.on = (on is True)
@ -140,18 +157,9 @@ class ToastMachine(object):
return self.name
def showNext(self):
high = filter(lambda x: x.importance < 0, self.toasts)
normal = filter(lambda x: x.importance == 0, self.toasts)
low = filter(lambda x: x.importance > 0, self.toasts)
if high:
high.sort(key=lambda x: x.importance)
high[0].realShow()
elif normal:
normal[0].realShow()
elif low:
low.sort(key=lambda x: x.importance)
low[0].realShow()
if not self.displaying and self.toasts:
self.toasts.sort(key=lambda x: x.importance)
self.toasts[0].realShow()
def showAll(self):
while self.toasts:
@ -163,40 +171,180 @@ class ToastMachine(object):
self.showNext()
class PesterToast(QtGui.QFrame, DefaultToast):
def __init__(self, title, msg, icon, parent=None):
QtGui.QFrame.__init__(self, parent,
(QtCore.Qt.CustomizeWindowHint |
QtCore.Qt.FramelessWindowHint))
#self.setAttribute(QtCore.Qt.WA_QuitOnClose, False)
#self.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
#self.setAttribute(QtCore.Qt.WA_NoSystemBackground, True)
self.setObjectName("toast")
self.setWindowTitle("toast")
#self.setFocusPolicy(QtCore.Qt.ClickFocus)
class PesterToast(QtGui.QWidget, DefaultToast):
def __init__(self, machine, title, msg, icon, time=3000, parent=None):
QtGui.QWidget.__init__(self, parent)
self.machine = machine
self.time = time
self.setWindowFlags(QtCore.Qt.ToolTip)
self.m_animation = QtCore.QParallelAnimationGroup()
anim = QtCore.QPropertyAnimation(self)
anim.setTargetObject(self)
self.m_animation.addAnimation(anim)
anim.setEasingCurve(QtCore.QEasingCurve.OutBounce)
anim.setDuration(1000)
self.connect(anim, QtCore.SIGNAL('finished()'),
self, QtCore.SLOT('reverseTrigger()'))
self.m_animation.setDirection(QtCore.QAnimationGroup.Forward)
self.title = QtGui.QLabel(title, self)
self.msg = QtGui.QLabel(msg, self)
self.btn = QtGui.QPushButton("Push Me", self)
self.connect(self.btn, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('close()'))
self.content = msg
if icon:
self.icon = QtGui.QLabel("")
self.icon.setPixmap(QtGui.QPixmap(icon).scaledToWidth(30))
else:
self.icon = QtGui.QLabel("")
self.icon.setPixmap(QtGui.QPixmap(30, 30))
self.icon.pixmap().fill(QtGui.QColor(0,0,0,0))
layout_0 = QtGui.QVBoxLayout()
layout_0.setMargin(0)
layout_0.setContentsMargins(0, 0, 0, 0)
if self.icon:
layout_1 = QtGui.QGridLayout()
layout_1.addWidget(self.icon, 0,0, 1,1)
layout_1.addWidget(self.title, 0,1, 1,7)
layout_1.setAlignment(self.msg, QtCore.Qt.AlignTop)
layout_0.addLayout(layout_1)
else:
layout_0.addWidget(self.title)
layout_0.addWidget(self.btn)
layout_0.addWidget(self.msg)
self.setMaximumWidth(self.parent().theme["toasts/width"])
self.msg.setMaximumWidth(self.parent().theme["toasts/width"])
self.title.setMinimumHeight(self.parent().theme["toasts/title/minimumheight"])
self.setLayout(layout_0)
print self.isWindow()
self.setGeometry(0,0, self.parent().theme["toasts/width"], self.parent().theme["toasts/height"])
self.setStyleSheet(self.parent().theme["toasts/style"])
self.title.setStyleSheet(self.parent().theme["toasts/title/style"])
if self.icon:
self.icon.setStyleSheet(self.parent().theme["toasts/icon/style"])
self.msg.setStyleSheet(self.parent().theme["toasts/content/style"])
self.layout().setSpacing(0)
self.msg.setText(PesterToast.wrapText(self.msg.font(), str(self.msg.text()), self.parent().theme["toasts/width"], self.parent().theme["toasts/content/style"]))
anim.setStartValue(0)
anim.setEndValue(100)
self.connect(anim, QtCore.SIGNAL('valueChanged(QVariant)'),
self, QtCore.SLOT('updateBottomLeftAnimation(QVariant)'))
self.byebye = False
@QtCore.pyqtSlot()
def show(self):
QtGui.QFrame.setVisible(self, True)
print "SHOWING"
#~ themeWarning = QtGui.QMessageBox(self)
#~ themeWarning.setText("ASDFASD")
#~ themeWarning.exec_()
self.m_animation.start()
@QtCore.pyqtSlot()
def done(self):
QtGui.QWidget.hide(self)
t = self.machine.toasts[0]
if t.title == str(self.title.text()) and \
t.msg == str(self.content):
self.machine.toasts.pop(0)
self.machine.displaying = False
if self.machine.on:
self.machine.showNext()
del self
@QtCore.pyqtSlot()
def reverseTrigger(self):
if self.time >= 0:
QtCore.QTimer.singleShot(self.time, self, QtCore.SLOT('reverseStart()'))
@QtCore.pyqtSlot()
def reverseStart(self):
if not self.byebye:
self.byebye = True
anim = self.m_animation.animationAt(0)
self.m_animation.setDirection(QtCore.QAnimationGroup.Backward)
anim.setEasingCurve(QtCore.QEasingCurve.InCubic)
self.disconnect(anim, QtCore.SIGNAL('finished()'),
self, QtCore.SLOT('reverseTrigger()'))
self.connect(anim, QtCore.SIGNAL('finished()'),
self, QtCore.SLOT('done()'))
self.m_animation.start()
@QtCore.pyqtSlot(QtCore.QVariant)
def updateBottomLeftAnimation(self, value):
p = QtGui.QApplication.desktop().availableGeometry(self).bottomRight()
val = float(self.height())/100
self.move(p.x()-self.width(), p.y() - (value.toInt()[0] * val) +1)
self.layout().setSpacing(0)
self.raise_()
QtGui.QWidget.show(self)
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.RightButton:
self.reverseStart()
elif event.button() == QtCore.Qt.LeftButton:
pass
@staticmethod
def wrapText(font, text, maxwidth, css=""):
ret = []
metric = QtGui.QFontMetrics(font)
if "padding" in css:
if css[css.find("padding")+7] != "-":
colon = css.find(":", css.find("padding"))
semicolon = css.find(";", css.find("padding"))
if semicolon < 0:
stuff = css[colon+1:]
else:
stuff = css[colon+1:semicolon]
stuff = stuff.replace("px", "").lstrip().rstrip()
stuff = stuff.split(" ")
if len(stuff) == 1:
maxwidth -= int(stuff[0])*2
elif len(stuff) == 2:
maxwidth -= int(stuff[1])*2
elif len(stuff) == 3:
maxwidth -= int(stuff[1])*2
elif len(stuff) == 4:
maxwidth -= int(stuff[1]) + int(stuff[3])
else:
if "padding-left" in css:
colon = css.find(":", css.find("padding-left"))
semicolon = css.find(";", css.find("padding-left"))
if semicolon < 0:
stuff = css[colon+1:]
else:
stuff = css[colon+1:semicolon]
stuff = stuff.replace("px", "").lstrip().rstrip()
if stuff.isdigit():
maxwidth -= int(stuff)
if "padding-right" in css:
colon = css.find(":", css.find("padding-right"))
semicolon = css.find(";", css.find("padding-right"))
if semicolon < 0:
stuff = css[colon+1:]
else:
stuff = css[colon+1:semicolon]
stuff = stuff.replace("px", "").lstrip().rstrip()
if stuff.isdigit():
maxwidth -= int(stuff)
if metric.width(text) < maxwidth:
return text
while metric.width(text) > maxwidth:
lastspace = text.find(" ")
curspace = lastspace
while metric.width(text, curspace) < maxwidth:
lastspace = curspace
curspace = text.find(" ", lastspace+1)
ret.append(text[:lastspace])
text = text[lastspace+1:]
ret.append(text)
return "\n".join(ret)
class PesterToastMachine(ToastMachine, QtCore.QObject):
def __init__(self, parent, name, on=True, type="default",
@ -229,9 +377,10 @@ class PesterToastMachine(ToastMachine, QtCore.QObject):
ToastMachine.showNext(self)
def run(self):
self.timer = QtCore.QTimer(self)
self.timer.setInterval(1000)
self.connect(self.timer, QtCore.SIGNAL('timeout()'),
self, QtCore.SLOT('showNext()'))
if self.on:
pass#self.timer.start()
pass
#~ self.timer = QtCore.QTimer(self)
#~ self.timer.setInterval(1000)
#~ self.connect(self.timer, QtCore.SIGNAL('timeout()'),
#~ self, QtCore.SLOT('showNext()'))
#~ if self.on:
#~ self.timer.start()