/
main.py
316 lines (235 loc) · 9.89 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
#!/usr/bin/python3
import sys
import re
import datetime
from PySide import QtCore
from PySide import QtGui
from Timeslots import Timeslots
from Schedule import Schedule
class Worker(QtCore.QThread):
''' Creating a QThread class to run the time intensive webscrape of
timeslots. '''
signal = QtCore.Signal(bool)
def __init__(self, timeslotObjects, parent = None):
super(Worker, self).__init__(parent)
self.firstRun = True
self.timeslotObjects = timeslotObjects
def run(self):
for room in self.timeslotObjects:
try:
self.timeslotObjects[room].update()
except:
pass
self.signal.emit(self.firstRun)
self.firstRun = False
class Window(QtGui.QDialog):
''' '''
def __init__(self):
super(Window, self).__init__()
self.INTERVAL = 300000 # update interval in milliseconds
# Container lists for shift widgets and timeslots.
self.shiftWidgets = []
self.timeslotObjects = {}
self.viewport = Viewport(self)
self.scrollArea = ScrollArea(self.viewport)
self.progressbar = Progressbar(self)
# Regex for grabbing room names from shift summaries.
self.pattern = re.compile("(\D*) \d*")
# Initialize a schedule object and related timeslot objects.
self.getSchedule()
self.getTimeslots()
# Create a QThread object for the webscrape.
self.worker = Worker(self.timeslotObjects)
# Connect QThread objects signals.
self.worker.started.connect(self.starting)
self.worker.finished.connect(self.finished)
self.worker.signal.connect(self.updateDisplay)
self.worker.start()
self.timeslotTimer()
self.mainLayout()
self.createActions()
self.createTrayIcon()
self.setIcon()
self.trayIcon.show()
self.setWindowTitle("RoomWhen")
self.setFixedHeight(500)
def starting(self):
self.progressbar.show()
print("Starting thread!")
def finished(self):
self.progressbar.hide()
print("Finished thread!")
def updateDisplay(self, data):
''' If first run create widgets and layout, else update widgets
information. '''
if data:
self.createShiftWidgets()
else:
self.updateTimeslotStatus()
def getSchedule(self):
''' Pull the current schedule, requires .icalURL file in same directory '''
url = ''
try:
with open('.icalURL', 'r') as icalURL:
url = icalURL.readline().replace('\n', '')
except IOError:
pass # No pre made url file, so create dialogue for creating one.
self.schedule = Schedule(url)
self.schedule.events = self.schedule.sortEventsByDatetime()
def getTimeslots(self):
''' Initiate timeslot objects, requires an already initialized schedule object. '''
# Schedule.listRooms() returns a dict of room:week for us to
# create a timeslot for each room and only fetch important weeks.
roomList = self.schedule.listRooms()
for room in roomList:
self.timeslotObjects[room] = Timeslots(room, roomList[room])
def timeslotTimer(self):
''' Method to start the worker thread at given interval. '''
self.timer = QtCore.QTimer()
self.timer.setSingleShot(False)
self.timer.timeout.connect(self.worker.start)
self.timer.start(self.INTERVAL)
def setIcon(self):
''' '''
icon = QtGui.QIcon('images/drink.png')
self.trayIcon.setIcon(icon)
self.setWindowIcon(icon)
self.trayIcon.setToolTip("Placeholder")
def mainLayout(self):
''' Create the main layout '''
self.layout = QtGui.QVBoxLayout(self)
self.layout.addWidget(self.scrollArea)
self.layout.addWidget(self.progressbar)
self.setLayout(self.layout)
def createShiftLayout(self):
''' Create a layout for a single shift. '''
for widget in self.shiftsWidgets:
self.viewport.layout.addWidget(widget)
def createActions(self):
self.minimizeAction = QtGui.QAction("Mi&nimize", self,
triggered=self.hide)
self.restoreAction = QtGui.QAction("&Restore", self,
triggered=self.showNormal)
self.quitAction = QtGui.QAction("&Quit", self,
triggered=QtGui.qApp.quit)
def createTrayIcon(self):
''' '''
self.trayIconMenu = QtGui.QMenu(self)
self.trayIconMenu.addAction(self.minimizeAction)
self.trayIconMenu.addAction(self.restoreAction)
self.trayIconMenu.addAction(self.quitAction)
self.trayIcon = QtGui.QSystemTrayIcon(self)
self.trayIcon.setContextMenu(self.trayIconMenu)
def showMessage(self, titel, body):
''' '''
icon = QtGui.QSystemTrayIcon.MessageIcon(1)
self.trayIcon.showMessage(
titel,
body,
icon,
5000
)
def createShiftWidgets(self):
''' Create a widget with shift information for each shift. Requires
already initialized schedule and timeslot objects.'''
# For each shift create QWidget and set it's layout.
for shift in self.schedule.events:
# Use regex to get nice room name for our widget.
patternMatch = re.match(self.pattern, shift['summary'])
roomNiceName = patternMatch.group(1)
start = shift['timeStart']
end = shift['timeEnd'] + datetime.timedelta(minutes=5)
room = self.schedule.getRoom(shift)
shiftWidget = ShiftWidget(
roomNiceName,
start.strftime("%Y-%m-%d"),
self.timeslotObjects[room].findGames(start, end),
room,
start,
end,
parent = self.viewport
)
self.shiftWidgets.append(shiftWidget)
self.viewport.layout.addWidget(shiftWidget)
def updateTimeslotStatus(self):
''' Iterate through all widgets and update any changes. '''
for widget in self.shiftWidgets:
# Query timeslot for given widget room, about all games during it.
timeslots = self.timeslotObjects[widget.room].findGames(widget.start,
widget.end)
for timeslot in timeslots:
# Check if there has been any change
if timeslot['Status'] != widget.statuses[timeslot['Timestamp']].text():
# Compose notification message.
titel = widget.titel + ' ' + widget.date + " status changed"
body = "The " + widget.titel + " at the " + widget.date + \
" had it's status change from " + \
widget.statuses[timeslot['Timestamp']].text() + \
" to " + timeslot['Status']
self.showMessage(titel, body)
# Update widget with the change.
widget.statuses[timeslot['Timestamp']].setText(timeslot['Status'])
else:
pass
class Viewport(QtGui.QWidget):
def __init__(self, parent = None):
super(Viewport, self).__init__(parent)
self.createLayout()
def createLayout(self):
self.layout = QtGui.QVBoxLayout(self)
self.layout.setSizeConstraint(QtGui.QLayout.SetFixedSize)
self.setLayout(self.layout)
class ScrollArea(QtGui.QScrollArea):
def __init__(self, widget):
super(ScrollArea, self).__init__()
self.setVisible(True)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.setWidgetResizable(True)
self.setMinimumWidth(widget.sizeHint().width())
self.setWidget(widget)
class ShiftWidget(QtGui.QWidget):
def __init__(self, titel, date, timeslots, room, start, end, parent = None):
super(ShiftWidget, self).__init__(parent)
self.titel = titel
self.date = date
self.timeslots = timeslots
self.room = room
self.start = start
self.end = end
# Container dict for out changeable widgets.
self.statuses = {}
# Create labels for out 'header' and set the layout.
self.dateLabel = QtGui.QLabel(date, parent = self)
self.titelLabel = QtGui.QLabel(titel, parent = self)
self.headerLayout = QtGui.QHBoxLayout()
self.headerLayout.addWidget(self.dateLabel)
self.headerLayout.addWidget(self.titelLabel)
# Create the widget layout
self.layout = QtGui.QVBoxLayout(self)
self.layout.addLayout(self.headerLayout)
self.addTimeslots()
self.setLayout(self.layout)
self.layout.setSizeConstraint(QtGui.QLayout.SetFixedSize)
def addTimeslots(self):
for timeslot in self.timeslots:
timeslotLayout = QtGui.QHBoxLayout()
timeslotTimestampLabel = QtGui.QLabel(timeslot['Timestamp'], parent = self)
timeslotStatusLabel = QtGui.QLabel(timeslot['Status'], parent = self)
# Add status widget to our dict for ease of access.
self.statuses.update({timeslot['Timestamp']:timeslotStatusLabel})
timeslotLayout.addWidget(timeslotTimestampLabel)
timeslotLayout.addWidget(timeslotStatusLabel)
self.layout.addLayout(timeslotLayout)
class Progressbar(QtGui.QProgressBar):
def __init__(self, parent = None):
super(Progressbar,self).__init__(parent)
self.setObjectName("status")
self.setMinimum(0)
self.setMaximum(0)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
app.setQuitOnLastWindowClosed(False)
window = Window()
window.show()
sys.exit(app.exec_())