|
@@ -16,9 +16,74 @@ import time
|
16
|
16
|
import urllib.parse
|
17
|
17
|
import urllib.request
|
18
|
18
|
from PyQt5 import QtWidgets, QtGui, QtCore, QtNetwork
|
19
|
|
-from PyQt5.QtWidgets import QSystemTrayIcon, QAction, QMenu, QMessageBox, QWidget, QLabel, QVBoxLayout, QHBoxLayout, QDesktopWidget, QSizePolicy, QSlider, QLayout
|
|
19
|
+from PyQt5.QtWidgets import QSystemTrayIcon, QAction, QMenu, QMessageBox, QWidget, QLabel, QVBoxLayout, QHBoxLayout, QDesktopWidget, QSizePolicy, QSlider, QLayout, QTableWidget, QTableWidgetItem, QPushButton
|
20
|
20
|
from PyQt5.QtGui import QIcon, QPixmap, QImageReader, QDesktopServices
|
21
|
|
-from PyQt5.QtCore import QCoreApplication, QSettings, QUrl, QTimer, QSize, Qt
|
|
21
|
+from PyQt5.QtCore import QCoreApplication, QSettings, QUrl, QTimer, QSize, Qt, QSettings
|
|
22
|
+
|
|
23
|
+class SettingsWindow(QWidget):
|
|
24
|
+ def __init__(self, parent, *args, **kwargs):
|
|
25
|
+ super(SettingsWindow, self).__init__(*args, **kwargs)
|
|
26
|
+ self.parent = parent
|
|
27
|
+
|
|
28
|
+ self.setWindowTitle(parent.name + " Settings")
|
|
29
|
+ self.setWindowIcon(parent.icon)
|
|
30
|
+
|
|
31
|
+ box = QVBoxLayout()
|
|
32
|
+ self.setLayout(box)
|
|
33
|
+
|
|
34
|
+ buttons = QHBoxLayout()
|
|
35
|
+ box.addLayout(buttons, 0)
|
|
36
|
+
|
|
37
|
+ self.add = QPushButton("&Add Printer")
|
|
38
|
+ self.add.clicked.connect(self.addPrinter)
|
|
39
|
+ buttons.addWidget(self.add)
|
|
40
|
+
|
|
41
|
+ self.remove = QPushButton("&Remove Printer")
|
|
42
|
+ self.remove.clicked.connect(self.removePrinter)
|
|
43
|
+ buttons.addWidget(self.remove)
|
|
44
|
+
|
|
45
|
+ printers = self.parent.readSettings()
|
|
46
|
+ self.rows = len(printers)
|
|
47
|
+ self.table = QTableWidget(self.rows, 2)
|
|
48
|
+ box.addWidget(self.table, 1)
|
|
49
|
+
|
|
50
|
+ for i in range(0, self.rows):
|
|
51
|
+ p = printers[i]
|
|
52
|
+ for j in range(0, 2):
|
|
53
|
+ item = QTableWidgetItem(p[j])
|
|
54
|
+ self.table.setItem(i, j, item)
|
|
55
|
+
|
|
56
|
+ self.table.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
|
|
57
|
+ self.table.resizeColumnsToContents()
|
|
58
|
+
|
|
59
|
+ def tableToList(self):
|
|
60
|
+ printers = []
|
|
61
|
+ for i in range(0, self.rows):
|
|
62
|
+ p = [self.table.item(i, 0).text(), self.table.item(i, 1).text()]
|
|
63
|
+ printers.append(p)
|
|
64
|
+ return printers
|
|
65
|
+
|
|
66
|
+ def closeEvent(self, event):
|
|
67
|
+ oldPrinters = [item[0:2] for item in self.parent.printers]
|
|
68
|
+ newPrinters = self.tableToList()
|
|
69
|
+ if oldPrinters != newPrinters:
|
|
70
|
+ r = self.parent.showDialog(self.parent.name + " Settings Changed", "Do you want to save the new list of printers?", "This will restart the application!", True, False, False)
|
|
71
|
+ if r == True:
|
|
72
|
+ self.parent.writeSettings(newPrinters)
|
|
73
|
+ QCoreApplication.exit(42)
|
|
74
|
+ self.parent.removeSettingsWindow()
|
|
75
|
+
|
|
76
|
+ def addPrinter(self):
|
|
77
|
+ self.rows += 1
|
|
78
|
+ self.table.setRowCount(self.rows)
|
|
79
|
+ self.table.setItem(self.rows - 1, 0, QTableWidgetItem("HOSTNAME"))
|
|
80
|
+ self.table.setItem(self.rows - 1, 1, QTableWidgetItem("API_KEY"))
|
|
81
|
+
|
|
82
|
+ def removePrinter(self):
|
|
83
|
+ r = self.table.currentRow()
|
|
84
|
+ if (r >= 0) and (r < self.rows):
|
|
85
|
+ self.rows -= 1
|
|
86
|
+ self.table.removeRow(r)
|
22
|
87
|
|
23
|
88
|
class AspectRatioPixmapLabel(QLabel):
|
24
|
89
|
def __init__(self, *args, **kwargs):
|
|
@@ -54,18 +119,18 @@ class CamWindow(QWidget):
|
54
|
119
|
addSize = 100
|
55
|
120
|
reloadOn = True
|
56
|
121
|
|
57
|
|
- def __init__(self, parent, name, icon, app, manager, printer, *args, **kwargs):
|
|
122
|
+ def __init__(self, parent, printer, *args, **kwargs):
|
58
|
123
|
super(CamWindow, self).__init__(*args, **kwargs)
|
59
|
|
- self.app = app
|
60
|
|
- self.manager = manager
|
|
124
|
+ self.app = parent.app
|
|
125
|
+ self.manager = parent.manager
|
61
|
126
|
self.manager.finished.connect(self.handleResponse)
|
62
|
127
|
self.parent = parent
|
63
|
128
|
self.printer = printer
|
64
|
129
|
self.host = self.printer[0]
|
65
|
130
|
self.url = "http://" + self.host + ":8080/?action=snapshot"
|
66
|
131
|
|
67
|
|
- self.setWindowTitle(name + " Webcam Stream")
|
68
|
|
- self.setWindowIcon(icon)
|
|
132
|
+ self.setWindowTitle(parent.name + " Webcam Stream")
|
|
133
|
+ self.setWindowIcon(parent.icon)
|
69
|
134
|
|
70
|
135
|
box = QVBoxLayout()
|
71
|
136
|
self.setLayout(box)
|
|
@@ -173,21 +238,22 @@ class OctoTray():
|
173
|
238
|
iconPath = "/usr/share/pixmaps/"
|
174
|
239
|
iconName = "octotray_icon.png"
|
175
|
240
|
|
176
|
|
- # 0=host, 1=key
|
177
|
|
- # (2=system-commands, 3=menu, 4...=actions)
|
178
|
|
- printers = [
|
179
|
|
- [ "PRINTER_HOST_HERE", "PRINTER_API_KEY_HERE" ]
|
180
|
|
- ]
|
|
241
|
+ networkTimeout = 2.0 # in s
|
|
242
|
+
|
|
243
|
+ # list of lists, inner lists contain printer data:
|
|
244
|
+ # 0=host 1=key (2=system-commands 3=menu 4+=actions)
|
|
245
|
+ printers = []
|
181
|
246
|
|
182
|
247
|
statesWithWarning = [
|
183
|
248
|
"Printing", "Pausing", "Paused"
|
184
|
249
|
]
|
185
|
250
|
|
186
|
251
|
camWindows = []
|
|
252
|
+ settingsWindow = None
|
187
|
253
|
|
188
|
|
- def __init__(self):
|
189
|
|
- self.app = QtWidgets.QApplication(sys.argv)
|
|
254
|
+ def __init__(self, app):
|
190
|
255
|
QCoreApplication.setApplicationName(self.name)
|
|
256
|
+ self.app = app
|
191
|
257
|
|
192
|
258
|
if not QSystemTrayIcon.isSystemTrayAvailable():
|
193
|
259
|
self.showDialog("OctoTray Error", "System Tray is not available on this platform!", "", False, False, True)
|
|
@@ -195,6 +261,7 @@ class OctoTray():
|
195
|
261
|
|
196
|
262
|
self.manager = QtNetwork.QNetworkAccessManager()
|
197
|
263
|
self.menu = QMenu()
|
|
264
|
+ self.printers = self.readSettings()
|
198
|
265
|
|
199
|
266
|
unknownCount = 0
|
200
|
267
|
for p in self.printers:
|
|
@@ -243,34 +310,57 @@ class OctoTray():
|
243
|
310
|
p.append(action)
|
244
|
311
|
menu.addAction(action)
|
245
|
312
|
|
246
|
|
- if (len(self.printers) <= 0) or (unknownCount >= len(self.printers)):
|
247
|
|
- self.showDialog("OctoTray Error", "No printers available!", "", False, False, True)
|
248
|
|
- sys.exit(0)
|
|
313
|
+ self.settingsAction = QAction("&Settings")
|
|
314
|
+ self.settingsAction.triggered.connect(self.showSettingsAction)
|
|
315
|
+ self.menu.addAction(self.settingsAction)
|
249
|
316
|
|
250
|
317
|
self.quitAction = QAction("&Quit")
|
251
|
318
|
self.quitAction.triggered.connect(self.exit)
|
252
|
319
|
self.menu.addAction(self.quitAction)
|
253
|
320
|
|
254
|
|
- iconPathName = ""
|
|
321
|
+ self.iconPathName = ""
|
255
|
322
|
if os.path.isfile(self.iconName):
|
256
|
|
- iconPathName = self.iconName
|
|
323
|
+ self.iconPathName = self.iconName
|
257
|
324
|
elif os.path.isfile(self.iconPath + self.iconName):
|
258
|
|
- iconPathName = self.iconPath + self.iconName
|
|
325
|
+ self.iconPathName = self.iconPath + self.iconName
|
259
|
326
|
else:
|
260
|
327
|
self.showDialog("OctoTray Error", "Icon file has not been found! found", "", False, False, True)
|
261
|
328
|
sys.exit(0)
|
262
|
329
|
|
263
|
330
|
self.icon = QIcon()
|
264
|
|
- pic = QPixmap(32, 32)
|
265
|
|
- pic.load(iconPathName)
|
266
|
|
- self.icon = QIcon(pic)
|
267
|
|
-
|
268
|
|
- trayIcon = QSystemTrayIcon(self.icon)
|
269
|
|
- trayIcon.setToolTip(self.name + " " + self.version)
|
270
|
|
- trayIcon.setContextMenu(self.menu)
|
271
|
|
- trayIcon.setVisible(True)
|
272
|
|
-
|
273
|
|
- sys.exit(self.app.exec_())
|
|
331
|
+ self.pic = QPixmap(32, 32)
|
|
332
|
+ self.pic.load(self.iconPathName)
|
|
333
|
+ self.icon = QIcon(self.pic)
|
|
334
|
+
|
|
335
|
+ self.trayIcon = QSystemTrayIcon(self.icon)
|
|
336
|
+ self.trayIcon.setToolTip(self.name + " " + self.version)
|
|
337
|
+ self.trayIcon.setContextMenu(self.menu)
|
|
338
|
+ self.trayIcon.setVisible(True)
|
|
339
|
+
|
|
340
|
+ def readSettings(self):
|
|
341
|
+ settings = QSettings(self.vendor, self.name)
|
|
342
|
+ printers = []
|
|
343
|
+ l = settings.beginReadArray("printers")
|
|
344
|
+ for i in range(0, l):
|
|
345
|
+ settings.setArrayIndex(i)
|
|
346
|
+ p = []
|
|
347
|
+ p.append(settings.value("host"))
|
|
348
|
+ p.append(settings.value("key"))
|
|
349
|
+ printers.append(p)
|
|
350
|
+ settings.endArray()
|
|
351
|
+ return printers
|
|
352
|
+
|
|
353
|
+ def writeSettings(self, printers):
|
|
354
|
+ settings = QSettings(self.vendor, self.name)
|
|
355
|
+ settings.remove("printers")
|
|
356
|
+ settings.beginWriteArray("printers")
|
|
357
|
+ for i in range(0, len(printers)):
|
|
358
|
+ p = printers[i]
|
|
359
|
+ settings.setArrayIndex(i)
|
|
360
|
+ settings.setValue("host", p[0])
|
|
361
|
+ settings.setValue("key", p[1])
|
|
362
|
+ settings.endArray()
|
|
363
|
+ del settings
|
274
|
364
|
|
275
|
365
|
def openBrowser(self, url):
|
276
|
366
|
QDesktopServices.openUrl(QUrl("http://" + url))
|
|
@@ -312,9 +402,11 @@ class OctoTray():
|
312
|
402
|
data = content.encode('ascii')
|
313
|
403
|
request = urllib.request.Request(url, data, headers)
|
314
|
404
|
try:
|
315
|
|
- with urllib.request.urlopen(request, None, 1.0) as response:
|
|
405
|
+ with urllib.request.urlopen(request, None, self.networkTimeout) as response:
|
316
|
406
|
text = response.read()
|
317
|
407
|
return text
|
|
408
|
+ except urllib.error.URLError:
|
|
409
|
+ pass
|
318
|
410
|
except urllib.error.HTTPError:
|
319
|
411
|
pass
|
320
|
412
|
return ""
|
|
@@ -508,21 +600,60 @@ class OctoTray():
|
508
|
600
|
cw.activateWindow()
|
509
|
601
|
return
|
510
|
602
|
|
511
|
|
- window = CamWindow(self, self.name, self.icon, self.app, self.manager, item)
|
|
603
|
+ window = CamWindow(self, item)
|
512
|
604
|
self.camWindows.append(window)
|
513
|
605
|
|
514
|
|
- screenGeometry = QDesktopWidget().screenGeometry()
|
515
|
|
- width = screenGeometry.width()
|
516
|
|
- height = screenGeometry.height()
|
517
|
|
- x = (width - window.width()) / 2
|
518
|
|
- y = (height - window.height()) / 2
|
519
|
|
- window.setGeometry(int(x), int(y), int(window.width()), int(window.height()))
|
520
|
|
-
|
521
|
606
|
window.show()
|
522
|
607
|
window.activateWindow()
|
523
|
608
|
|
|
609
|
+ screenGeometry = QDesktopWidget().screenGeometry()
|
|
610
|
+ x = (screenGeometry.width() - window.width()) / 2
|
|
611
|
+ y = (screenGeometry.height() - window.height()) / 2
|
|
612
|
+ x += screenGeometry.x()
|
|
613
|
+ y += screenGeometry.y()
|
|
614
|
+ window.setGeometry(int(x), int(y), int(window.width()), int(window.height()))
|
|
615
|
+
|
524
|
616
|
def removeWebcamWindow(self, window):
|
525
|
617
|
self.camWindows.remove(window)
|
526
|
618
|
|
|
619
|
+ def showSettingsAction(self):
|
|
620
|
+ if self.settingsWindow != None:
|
|
621
|
+ self.settingsWindow.show()
|
|
622
|
+ self.settingsWindow.activateWindow()
|
|
623
|
+ return
|
|
624
|
+
|
|
625
|
+ self.settingsWindow = SettingsWindow(self)
|
|
626
|
+ self.settingsWindow.show()
|
|
627
|
+ self.settingsWindow.activateWindow()
|
|
628
|
+
|
|
629
|
+ screenGeometry = QDesktopWidget().screenGeometry()
|
|
630
|
+ x = (screenGeometry.width() - self.settingsWindow.width()) / 2
|
|
631
|
+ y = (screenGeometry.height() - self.settingsWindow.height()) / 2
|
|
632
|
+ x += screenGeometry.x()
|
|
633
|
+ y += screenGeometry.y()
|
|
634
|
+ self.settingsWindow.setGeometry(int(x), int(y), int(self.settingsWindow.width()), int(self.settingsWindow.height()))
|
|
635
|
+
|
|
636
|
+ def removeSettingsWindow(self):
|
|
637
|
+ self.settingsWindow = None
|
|
638
|
+
|
|
639
|
+ def closeAll(self):
|
|
640
|
+ for cw in self.camWindows:
|
|
641
|
+ cw.close()
|
|
642
|
+
|
|
643
|
+ if self.settingsWindow != None:
|
|
644
|
+ self.settingsWindow.close()
|
|
645
|
+
|
|
646
|
+ self.trayIcon.setVisible(False)
|
|
647
|
+
|
527
|
648
|
if __name__ == "__main__":
|
528
|
|
- tray = OctoTray()
|
|
649
|
+ app = QtWidgets.QApplication(sys.argv)
|
|
650
|
+
|
|
651
|
+ tray = OctoTray(app)
|
|
652
|
+ rc = app.exec_()
|
|
653
|
+
|
|
654
|
+ while rc == 42:
|
|
655
|
+ tray.closeAll()
|
|
656
|
+ tray = OctoTray(app)
|
|
657
|
+ rc = app.exec_()
|
|
658
|
+
|
|
659
|
+ sys.exit(rc)
|