def CreateTray(self, showTray=False): if self.tray is not None: return iconImage = QtGui.QPixmap("No_Image_Available.png") icon = None if not iconImage.isNull(): icon = QtGui.QIcon(iconImage) self.tray = SystemTray(icon) self.tray.exitAction.triggered.connect(self.close) self.tray.showAction.triggered.connect(self.ShowOnTop) self.tray.activated.connect(self._handle_show_tray) if showTray: self.tray.show()
class MasterControl(QtGui.QWidget): def __init__(self, parent=None): super(MasterControl, self).__init__(parent) self.tray = None self.CreateTray() #---- Styling ----# self.resize(1000, 500) self.Center() self._initial_show() self.mainLayout = QtGui.QGridLayout() self.setLayout(self.mainLayout) #-----------------# #----- Buttons Container (Top of Main Widget) -------# self.topWidget = QtGui.QWidget() self.topWidget.setLayout(QtGui.QHBoxLayout() ) self.addGoalWidgetButton = QtGui.QPushButton("Add Goal Widget") self.addGoalWidgetButton.clicked.connect(self.AppendGoalWidget) self.registryCheckbox = QtGui.QCheckBox("Boot on Windows Start") self.topWidget.layout().addWidget( self.addGoalWidgetButton ) self.topWidget.layout().addWidget( ExtraLCDDisplay() ) self.topWidget.layout().addWidget( self.registryCheckbox ) self.topWidget.layout().addItem(QtGui.QSpacerItem( 1, 1, QtGui.QSizePolicy.Expanding) ) #----- End of Button Container ---# #------------------- Main Area --------------------# #---- Goal Widget Area ------# self.scrollArea = QtGui.QScrollArea() self.scrollArea.setLayout( QtGui.QVBoxLayout() ) self.scrollArea.setWidgetResizable(True) #self.scrollArea.setMaximumWidth(500) #Buffer area, to make the main widget appear on top always self.scrollAreaBuffer = QtGui.QWidget() self.scrollAreaBuffer.setLayout( QtGui.QVBoxLayout() ) #Main Goal Widget Container self.scrollAreaWidget = QtGui.QWidget() self.scrollAreaWidget.setLayout( QtGui.QVBoxLayout() ) self.scrollAreaBuffer.layout().addWidget(self.scrollAreaWidget) self.scrollAreaBuffer.layout().addItem( QtGui.QSpacerItem(1,2000,QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) ) #Set widget to scroll area self.scrollArea.setWidget(self.scrollAreaBuffer) #---- End of Goal Widget Area ----# #---- List Widget Area (Running Goals) ----# self.goalListWidgetScroll = QtGui.QScrollArea() self.goalListWidgetScroll.setWidgetResizable(True) #Buffer area self.goalListWidgetBuffer = QtGui.QWidget() goalListBufferLayout = QtGui.QVBoxLayout() goalListBufferLayout.setSpacing(0) goalListBufferLayout.setMargin(0) self.goalListWidgetBuffer.setLayout(goalListBufferLayout) #List Widget self.goalListWidget = QtGui.QWidget() self.goalListWidgetLayout = QtGui.QVBoxLayout() self.goalListWidgetLayout.setSpacing(0) self.goalListWidgetLayout.setMargin(0) self.goalListWidget.setLayout(self.goalListWidgetLayout) self.goalListWidgetBuffer.layout().addWidget(self.goalListWidget) self.goalListWidgetBuffer.layout().addItem(QtGui.QSpacerItem(1, 2000, QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Expanding)) self.goalListWidgetScroll.setWidget(self.goalListWidgetBuffer) #--------- End of List Widget Area ------------# self.bottomWidget = QtGui.QWidget() self.bottomWidget.setLayout(QtGui.QHBoxLayout() ) self.bottomWidget.layout().addWidget(self.scrollArea) self.bottomWidget.layout().addWidget(self.goalListWidgetScroll) #-------- End of Main Area --------------------# #Add everything to main widget self.mainLayout.addWidget(self.topWidget,0,0) self.mainLayout.addWidget(self.bottomWidget,1,0) #Cache needed or else splash screens will display properly self.splashes = [] #For saving information on startup self.goalWidgets = [] self.runningGoals = [] #Cache needed or else threads just stop running immiediately self.qthreads = [] self.qobjects = [] #Delay loading of saved widgets and goals until container widgets appear first QtCore.QTimer.singleShot(0, self._load) def _load(self): self.LoadRegistrySettings() self.LoadWidgets() self.LoadRunningGoals() def CreateTray(self, showTray=False): if self.tray is not None: return iconImage = QtGui.QPixmap("No_Image_Available.png") icon = None if not iconImage.isNull(): icon = QtGui.QIcon(iconImage) self.tray = SystemTray(icon) self.tray.exitAction.triggered.connect(self.close) self.tray.showAction.triggered.connect(self.ShowOnTop) self.tray.activated.connect(self._handle_show_tray) if showTray: self.tray.show() def LoadRegistrySettings(self): self.registrySettings = QtCore.QSettings(REGISTRY_PATH, QtCore.QSettings.NativeFormat) print "Boot on Windows Startup:", self.registrySettings.contains("Boot_"+PROGRAM_NAME) self.registryCheckbox.setChecked( self.registrySettings.contains("Boot_"+PROGRAM_NAME) ) self.registryCheckbox.stateChanged.connect(self._registry_checkbox_checked) def ShowOnTop(self): self.show() #For Windows OS self.setWindowState(self.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive) self.activateWindow() def AppendGoalWidget(self): gw = GoalWidget(None) gw.removeClicked.connect(self.RemoveGoalWidget) gw.startButton.clicked.connect(lambda : self.StartCreatingGoal(gw) ) gw.saveButton.clicked.connect(self.SaveWidgets) self.scrollAreaWidget.layout().addWidget(gw) self.goalWidgets.append(gw) def RemoveGoalWidget(self, gw=None): if gw is None: return gw.removeClicked.disconnect() gw.deleteLater() self.goalWidgets.remove(gw) self.scrollAreaWidget.layout().removeWidget(gw) def StartCreatingGoal(self, gw=None): if gw is None: return now = self._currentDateTime() dt = now.msecsTo( gw.dateTimeEdit.dateTime() ) if dt < 0: dt = 0 imagePath = gw.selectImageEdit.text() if imagePath == "" : imagePath = QtCore.QString("No_Image_Available.png") title = gw.titleBar.text() if title == "": title = QtCore.QString("(NO NAME)") mp3Path = gw.selectAudioEdit.text() goal = Goal(dt, now, imagePath, mp3Path, title, dt) self.runningGoals.append(goal) gwp = self.CreateGoalWidgetPart(goal) self.AddGoalThread(goal, gwp) print "Started Goal:", title, now.toString(), "DELTA(ms):", dt,"\n" self.SaveRunningGoals() def CreateGoalWidgetPart(self, goal=None): if goal is None: return gwp = GoalListWidgetPart() gwp.titleLabel.setText(goal.title) gwp.dateTimeEdit.setDateTime( goal.registeredTime.addMSecs(goal.initialSeconds) ) self.goalListWidgetLayout.addWidget( gwp ) return gwp def RemoveGoalWidgetPart(self, gwp=None, goal=None): if gwp is None: return if goal: try: self.runningGoals.remove(goal) self.SaveRunningGoals() except Exception as e: print type(e),e self.goalListWidgetLayout.removeWidget(gwp) gwp.deleteLater() def AddGoalThread(self, goal=None, gwp=None): if goal is None or gwp is None: return qthread = QtCore.QThread() qobject = GoalLogic(goal.seconds) qobject.moveToThread(qthread) qobject.completed.connect(lambda : self.RunGoal(goal, gwp) )#, qobject, qthread) ) qobject.completed.connect(qthread.quit) qobject.stopped.connect(qthread.quit) qthread.started.connect(qobject.run) qthread.finished.connect( lambda : self._cleanupQThreads( qthread, qobject) ) gwp.removeButton.clicked.connect( lambda : qobject.StopRunning() ) gwp.removeButton.clicked.connect( lambda : self.RemoveGoalWidgetPart(gwp,goal) ) self.qthreads.append(qthread) self.qobjects.append(qobject) qthread.start() def RunGoal(self, goal=None, gwp=None): if goal is None or gwp is None: return message = "Goal: "+str(goal.title)+"\nFinished: "+str( self._currentDateTime().toString() )+"\nStarted: "+str(goal.registeredTime.toString())+"\nDT: "+str(goal.seconds)+" milliseconds" print "Running Goal",message,"\n" if goal.imagePath != "": splashPix = QtGui.QPixmap(goal.imagePath) else: splashPix = QtGui.QPixmap("No_Image_Available.png") if splashPix.isNull(): print "Null pix, avoiding creating a splashscreen" else: splash = ExtraSplashScreen(splashPix, QtCore.Qt.WindowStaysOnTopHint) splash.setMask( splashPix.mask() ) splash.show() if goal.mp3Path != "": mediaSource = Phonon.MediaSource(goal.mp3Path) mediaObject = Phonon.MediaObject(self) audioOutput = Phonon.AudioOutput(Phonon.MusicCategory, self) Phonon.createPath(mediaObject, audioOutput) mediaObject.setCurrentSource(mediaSource) splash.shown.connect(mediaObject.play) splash.hidden.connect(mediaObject.stop) self.splashes.append(splash) splash.hidden.connect(lambda : self._cleanupSplashScreen(splash) ) self.RemoveGoalWidgetPart(gwp, goal) def SaveRunningGoals(self): #Save File, cleanup file = QtCore.QFile("goals.bin") file.open(QtCore.QIODevice.WriteOnly) stream = QtCore.QDataStream(file) for goal in self.runningGoals: stream << QtCore.QString(str(goal.seconds)) stream << goal.registeredTime stream << goal.imagePath stream << goal.mp3Path stream << goal.title stream << QtCore.QString(str(goal.initialSeconds)) file.close() def LoadRunningGoals(self): #Load Goals file = QtCore.QFile("goals.bin") file.open(QtCore.QIODevice.ReadOnly) stream = QtCore.QDataStream(file) while not stream.atEnd(): timeToGoal = QtCore.QString() registeredTime = QtCore.QDateTime() imagePath = QtCore.QString() mp3Path = QtCore.QString() title = QtCore.QString() initialSeconds = QtCore.QString() stream >> timeToGoal stream >> registeredTime stream >> imagePath stream >> mp3Path stream >> title stream >> initialSeconds self.runningGoals.append( Goal(int(timeToGoal), registeredTime, imagePath, mp3Path, title, int(initialSeconds)) ) file.close() #Reload threads according to the amount of time passed for goal in self.runningGoals: now = self._currentDateTime() print "\nReloaded a goal:", goal.title print "Started:", goal.registeredTime.toString() print "Ending :", goal.registeredTime.addMSecs(goal.seconds).toString(),"\n" passedTime = now.msecsTo(goal.registeredTime) goal.seconds += passedTime if goal.seconds < 0: goal.seconds = 0 gwp = self.CreateGoalWidgetPart(goal) self.AddGoalThread(goal, gwp) print "Goals Loaded" def SaveWidgets(self): #Save File, cleanup file = None success = False #Try saving 3 times for i in range(0,3): if not success: try: file = QtCore.QFile("widgets.bin") if not file.open(QtCore.QIODevice.WriteOnly): raise IOError("Failed to open widgets.bin") stream = QtCore.QDataStream(file) for gw in self.goalWidgets: stream << gw.titleBar.text() stream << gw.selectAudioEdit.text() stream << gw.selectImageEdit.text() stream << QtCore.QString(gw.lastDirectory) stream << QtCore.QString(gw.lastDirectoryAudio) success = True except Exception as e: print type(e), e continue finally: if file is not None: file.close() break if success: print "Widgets saved." if os.path.exists("widgets.bin"): shutil.copy2("widgets.bin","widgets.bin.bkp") else: print "Failed to copy over data." if os.path.exists("widgets.bin.bkp"): print "Restoring from backup." shutil.copy2("widgets.bin.bkp","widgets.bin") def LoadWidgets(self): file = QtCore.QFile("widgets.bin") file.open(QtCore.QIODevice.ReadOnly) stream = QtCore.QDataStream(file) while not stream.atEnd(): titleText = QtCore.QString() audioPathText = QtCore.QString() imagePathText = QtCore.QString() lastDirectory = QtCore.QString() lastDirectoryAudio = QtCore.QString() stream >> titleText stream >> audioPathText stream >> imagePathText stream >> lastDirectory stream >> lastDirectoryAudio if imagePathText == "Select Image": imagePathText = "No_Image_Available.png" if audioPathText == "mp3/avi audio": audioPathText = "" #Load general settings gw = GoalWidget(None) gw.removeClicked.connect(self.RemoveGoalWidget) gw.startClicked.connect(self.StartCreatingGoal) gw.saveButton.clicked.connect(self.SaveWidgets) self.scrollAreaWidget.layout().addWidget(gw) self.goalWidgets.append(gw) #Load specific settings gw.titleBar.setText(titleText) gw.selectAudioEdit.setText(audioPathText) gw.selectImageEdit.setText(imagePathText) pix = QtGui.QPixmap(imagePathText) gw.goalIconLabel.setPixmap( pix ) gw.lastDirectory = lastDirectory gw.lastDirectoryAudio = lastDirectoryAudio file.close() print "Widgets Loaded" def Center(self): qr = self.frameGeometry() cp = QtGui.QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def keyPressEvent(self, e): if e.key() == QtCore.Qt.Key_Escape: for splash in self.splashes: splash.hide() def changeEvent(self, event): super(MasterControl,self).changeEvent(event) if event.type() == QtCore.QEvent.WindowStateChange: if event.oldState() != QtCore.Qt.WindowMinimized and self.isMinimized(): #Defer until after minizmization (allows hiding from taskbar) QtCore.QTimer.singleShot(200, self.hide) event.ignore() def showEvent(self,event): if self.tray: self.tray.hide() def hideEvent(self,event): if self.tray: self.tray.show() def closeEvent(self,event): super(MasterControl,self).closeEvent(event) self.tray = None def _initial_show(self): #Check for minimized Start try: if sys.argv[1] == "-mini": print "SYS.ARGV[1]:",sys.argv[1],"\n","Minimized Start" self.hide() self.tray.show() self.tray.showMessage(PROGRAM_NAME,"Started Minimized",QtGui.QSystemTrayIcon.Information,10000) else: print "SYS.ARGV[1]:",sys.argv[1] self.show() self.tray.hide() except Exception as e: self.show() self.tray.hide() def _handle_show_tray(self, reason): if reason == QtGui.QSystemTrayIcon.Context: self.tray.contextMenu().show() else: self.ShowOnTop() def _registry_checkbox_checked(self,state): if state == QtCore.Qt.Checked: self.registrySettings.setValue("Boot_"+PROGRAM_NAME, '"' + sys.argv[0] + '"' + " -mini") else: self.registrySettings.remove("Boot_"+PROGRAM_NAME) def _cleanupQThreads(self, qthread, qobject): print "Cleaning up qthreads" self.qthreads.remove(qthread) self.qobjects.remove(qobject) def _cleanupSplashScreen(self, splash): #print "Cleaning up splash screen" splash.finish(None) self.splashes.remove(splash) def _currentDateTime(self): return QtCore.QDateTime.currentDateTime() def _save_on_exit(self): try: print "Closing and saving widgets" print "Goal Widgets",len(self.goalWidgets),"Splash Screens",len(self.splashes), print "QThreads",len(self.qthreads),"QObjects",len(self.qobjects),"Running Goals",len(self.runningGoals) self.SaveWidgets() except Exception as e: print type(e),e if self.registryCheckbox.isChecked(): self.registrySettings.setValue("Boot_"+PROGRAM_NAME, '"' + sys.argv[0] + '"' + " -mini") else: self.registrySettings.remove("Boot_"+PROGRAM_NAME)