Merge branch 'shinyGui'
Conflicts: syncplay/ui/GuiConfiguration.py
BIN
resources/arrow_undo.png
Normal file
|
After Width: | Height: | Size: 631 B |
BIN
resources/clock_go.png
Normal file
|
After Width: | Height: | Size: 959 B |
BIN
resources/control_pause_blue.png
Normal file
|
After Width: | Height: | Size: 721 B |
BIN
resources/cross.png
Normal file
|
After Width: | Height: | Size: 655 B |
BIN
resources/door_in.png
Normal file
|
After Width: | Height: | Size: 693 B |
BIN
resources/table_refresh.png
Normal file
|
After Width: | Height: | Size: 795 B |
BIN
resources/timeline_marker.png
Normal file
|
After Width: | Height: | Size: 327 B |
@ -317,6 +317,9 @@ class SyncplayClient(object):
|
|||||||
if(self._protocol and self._protocol.logged):
|
if(self._protocol and self._protocol.logged):
|
||||||
self._protocol.sendList()
|
self._protocol.sendList()
|
||||||
|
|
||||||
|
def showUserList(self):
|
||||||
|
self.userlist.showUserList()
|
||||||
|
|
||||||
def getPassword(self):
|
def getPassword(self):
|
||||||
return self._serverPassword
|
return self._serverPassword
|
||||||
|
|
||||||
@ -504,7 +507,6 @@ class SyncplayUserlist(object):
|
|||||||
self.ui.showMessage(message)
|
self.ui.showMessage(message)
|
||||||
|
|
||||||
def addUser(self, username, room, file_, position = 0, noMessage = False):
|
def addUser(self, username, room, file_, position = 0, noMessage = False):
|
||||||
self._roomUsersChanged = True
|
|
||||||
if(username == self.currentUser.username):
|
if(username == self.currentUser.username):
|
||||||
self.currentUser.lastPosition = position
|
self.currentUser.lastPosition = position
|
||||||
return
|
return
|
||||||
@ -512,14 +514,15 @@ class SyncplayUserlist(object):
|
|||||||
self._users[username] = user
|
self._users[username] = user
|
||||||
if(not noMessage):
|
if(not noMessage):
|
||||||
self.__showUserChangeMessage(username, room, file_)
|
self.__showUserChangeMessage(username, room, file_)
|
||||||
|
self.userListChange()
|
||||||
|
|
||||||
def removeUser(self, username):
|
def removeUser(self, username):
|
||||||
self._roomUsersChanged = True
|
|
||||||
if(self._users.has_key(username)):
|
if(self._users.has_key(username)):
|
||||||
self._users.pop(username)
|
self._users.pop(username)
|
||||||
message = getMessage("en", "left-notification").format(username)
|
message = getMessage("en", "left-notification").format(username)
|
||||||
self.ui.showMessage(message)
|
self.ui.showMessage(message)
|
||||||
|
self.userListChange()
|
||||||
|
|
||||||
def __displayModUserMessage(self, username, room, file_, user):
|
def __displayModUserMessage(self, username, room, file_, user):
|
||||||
if (file_ and not user.isFileSame(file_)):
|
if (file_ and not user.isFileSame(file_)):
|
||||||
self.__showUserChangeMessage(username, room, file_)
|
self.__showUserChangeMessage(username, room, file_)
|
||||||
@ -527,7 +530,6 @@ class SyncplayUserlist(object):
|
|||||||
self.__showUserChangeMessage(username, room, None)
|
self.__showUserChangeMessage(username, room, None)
|
||||||
|
|
||||||
def modUser(self, username, room, file_):
|
def modUser(self, username, room, file_):
|
||||||
self._roomUsersChanged = True
|
|
||||||
if(self._users.has_key(username)):
|
if(self._users.has_key(username)):
|
||||||
user = self._users[username]
|
user = self._users[username]
|
||||||
self.__displayModUserMessage(username, room, file_, user)
|
self.__displayModUserMessage(username, room, file_, user)
|
||||||
@ -537,7 +539,8 @@ class SyncplayUserlist(object):
|
|||||||
self.__showUserChangeMessage(username, room, file_)
|
self.__showUserChangeMessage(username, room, file_)
|
||||||
else:
|
else:
|
||||||
self.addUser(username, room, file_)
|
self.addUser(username, room, file_)
|
||||||
|
self.userListChange()
|
||||||
|
|
||||||
def __addUserWithFileToList(self, rooms, user):
|
def __addUserWithFileToList(self, rooms, user):
|
||||||
currentPosition = utils.formatTime(user.lastPosition)
|
currentPosition = utils.formatTime(user.lastPosition)
|
||||||
file_key = '\'{}\' ({}/{})'.format(user.file['name'], currentPosition, utils.formatTime(user.file['duration']))
|
file_key = '\'{}\' ({}/{})'.format(user.file['name'], currentPosition, utils.formatTime(user.file['duration']))
|
||||||
@ -575,27 +578,28 @@ class SyncplayUserlist(object):
|
|||||||
return message
|
return message
|
||||||
|
|
||||||
def __displayFileWatchersInRoomList(self, key, users):
|
def __displayFileWatchersInRoomList(self, key, users):
|
||||||
self.ui.showMessage(getMessage("en", "file-played-by-notification").format(key), True, True)
|
self.ui.showListMessage(getMessage("en", "file-played-by-notification").format(key))
|
||||||
for user in sorted(users.itervalues()):
|
for user in sorted(users.itervalues()):
|
||||||
message = "<"+user.username+">"
|
message = "<"+user.username+">"
|
||||||
if(self.currentUser.username == user.username):
|
if(self.currentUser.username == user.username):
|
||||||
message = "*" + message + "*"
|
message = "*" + message + "*"
|
||||||
message = self.__addDifferentFileMessageIfNecessary(user, message)
|
message = self.__addDifferentFileMessageIfNecessary(user, message)
|
||||||
self.ui.showMessage("\t" + message, True, True)
|
self.ui.showListMessage("\t" + message)
|
||||||
|
|
||||||
def __displayPeopleInRoomWithNoFile(self, noFileList):
|
def __displayPeopleInRoomWithNoFile(self, noFileList):
|
||||||
if (noFileList):
|
if (noFileList):
|
||||||
self.ui.showMessage(getMessage("en", "notplaying-notification"), True, True)
|
self.ui.showListMessage(getMessage("en", "notplaying-notification"))
|
||||||
for user in sorted(noFileList.itervalues()):
|
for user in sorted(noFileList.itervalues()):
|
||||||
self.ui.showMessage("\t<" + user.username + ">", True, True)
|
self.ui.showListMessage("\t<" + user.username + ">")
|
||||||
|
|
||||||
def __displayListOfPeople(self, rooms):
|
def __displayListOfPeople(self, rooms):
|
||||||
for roomName in sorted(rooms.iterkeys()):
|
for roomName in sorted(rooms.iterkeys()):
|
||||||
self.ui.showMessage(getMessage("en", "userlist-room-notification").format(roomName), True, False)
|
self.ui.showListMessage(getMessage("en", "userlist-room-notification").format(roomName))
|
||||||
noFileList = rooms[roomName].pop("__noFile__") if (rooms[roomName].has_key("__noFile__")) else None
|
noFileList = rooms[roomName].pop("__noFile__") if (rooms[roomName].has_key("__noFile__")) else None
|
||||||
for key in sorted(rooms[roomName].iterkeys()):
|
for key in sorted(rooms[roomName].iterkeys()):
|
||||||
self.__displayFileWatchersInRoomList(key, rooms[roomName][key])
|
self.__displayFileWatchersInRoomList(key, rooms[roomName][key])
|
||||||
self.__displayPeopleInRoomWithNoFile(noFileList)
|
self.__displayPeopleInRoomWithNoFile(noFileList)
|
||||||
|
self.ui.markEndOfUserlist()
|
||||||
|
|
||||||
def areAllFilesInRoomSame(self):
|
def areAllFilesInRoomSame(self):
|
||||||
for user in self._users.itervalues():
|
for user in self._users.itervalues():
|
||||||
@ -609,6 +613,10 @@ class SyncplayUserlist(object):
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def userListChange(self):
|
||||||
|
self._roomUsersChanged = True
|
||||||
|
self.ui.userListChange()
|
||||||
|
|
||||||
def roomStateConfirmed(self):
|
def roomStateConfirmed(self):
|
||||||
self._roomUsersChanged = False
|
self._roomUsersChanged = False
|
||||||
|
|
||||||
@ -632,6 +640,9 @@ class UiManager(object):
|
|||||||
if(not noPlayer): self.showOSDMessage(message)
|
if(not noPlayer): self.showOSDMessage(message)
|
||||||
self.__ui.showMessage(message, noTimestamp)
|
self.__ui.showMessage(message, noTimestamp)
|
||||||
|
|
||||||
|
def showListMessage(self, message):
|
||||||
|
self.__ui.showListMessage(message)
|
||||||
|
|
||||||
def showOSDMessage(self, message, duration = constants.OSD_DURATION):
|
def showOSDMessage(self, message, duration = constants.OSD_DURATION):
|
||||||
if(self._client._player):
|
if(self._client._player):
|
||||||
self._client._player.displayMessage(message, duration * 1000)
|
self._client._player.displayMessage(message, duration * 1000)
|
||||||
@ -641,5 +652,11 @@ class UiManager(object):
|
|||||||
|
|
||||||
def promptFor(self, prompt):
|
def promptFor(self, prompt):
|
||||||
return self.__ui.promptFor(prompt)
|
return self.__ui.promptFor(prompt)
|
||||||
|
|
||||||
|
def userListChange(self):
|
||||||
|
self.__ui.userListChange()
|
||||||
|
|
||||||
|
def markEndOfUserlist(self):
|
||||||
|
self.__ui.markEndOfUserlist()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
from syncplay.client import SyncplayClient
|
|
||||||
from syncplay.ui.ConfigurationGetter import ConfigurationGetter
|
from syncplay.ui.ConfigurationGetter import ConfigurationGetter
|
||||||
from syncplay import ui
|
from syncplay import ui
|
||||||
from syncplay.messages import getMessage
|
from syncplay.messages import getMessage
|
||||||
@ -6,6 +5,7 @@ from syncplay.messages import getMessage
|
|||||||
class SyncplayClientManager(object):
|
class SyncplayClientManager(object):
|
||||||
def run(self):
|
def run(self):
|
||||||
config = ConfigurationGetter().getConfiguration()
|
config = ConfigurationGetter().getConfiguration()
|
||||||
|
from syncplay.client import SyncplayClient #Imported later, so the proper reactor is installed
|
||||||
interface = ui.getUi(graphical=not config["noGui"])
|
interface = ui.getUi(graphical=not config["noGui"])
|
||||||
syncplayClient = SyncplayClient(config["playerClass"], interface, config)
|
syncplayClient = SyncplayClient(config["playerClass"], interface, config)
|
||||||
if(syncplayClient):
|
if(syncplayClient):
|
||||||
|
|||||||
@ -307,10 +307,12 @@ class MPCHCAPIPlayer(BasePlayer):
|
|||||||
speedSupported = False
|
speedSupported = False
|
||||||
|
|
||||||
def __init__(self, client):
|
def __init__(self, client):
|
||||||
|
from twisted.internet import reactor
|
||||||
|
self.reactor = reactor
|
||||||
self.__client = client
|
self.__client = client
|
||||||
self._mpcApi = MpcHcApi()
|
self._mpcApi = MpcHcApi()
|
||||||
self._mpcApi.callbacks.onUpdateFilename = lambda _: self.__makePing()
|
self._mpcApi.callbacks.onUpdateFilename = lambda _: self.__makePing()
|
||||||
self._mpcApi.callbacks.onMpcClosed = lambda _: self.__client.stop(False)
|
self._mpcApi.callbacks.onMpcClosed = lambda _: self.reactor.callFromThread(self.__client.stop, (False),)
|
||||||
self._mpcApi.callbacks.onFileStateChange = lambda _: self.__lockAsking()
|
self._mpcApi.callbacks.onFileStateChange = lambda _: self.__lockAsking()
|
||||||
self._mpcApi.callbacks.onUpdatePlaystate = lambda _: self.__unlockAsking()
|
self._mpcApi.callbacks.onUpdatePlaystate = lambda _: self.__unlockAsking()
|
||||||
self._mpcApi.callbacks.onGetCurrentPosition = lambda _: self.__onGetPosition()
|
self._mpcApi.callbacks.onGetCurrentPosition = lambda _: self.__onGetPosition()
|
||||||
@ -355,7 +357,7 @@ class MPCHCAPIPlayer(BasePlayer):
|
|||||||
self._mpcApi.askForVersion()
|
self._mpcApi.askForVersion()
|
||||||
if(not self.__versionUpdate.wait(0.1) or not self._mpcApi.version):
|
if(not self.__versionUpdate.wait(0.1) or not self._mpcApi.version):
|
||||||
self.__mpcError(getMessage("en", "mpc-version-insufficient-error").format(constants.MPC_MIN_VER))
|
self.__mpcError(getMessage("en", "mpc-version-insufficient-error").format(constants.MPC_MIN_VER))
|
||||||
self.__client.stop(True)
|
self.reactor.callFromThread(self.__client.stop, (True),)
|
||||||
|
|
||||||
def __testMpcReady(self):
|
def __testMpcReady(self):
|
||||||
if(not self.__preventAsking.wait(10)):
|
if(not self.__preventAsking.wait(10)):
|
||||||
@ -365,12 +367,12 @@ class MPCHCAPIPlayer(BasePlayer):
|
|||||||
try:
|
try:
|
||||||
self.__testMpcReady()
|
self.__testMpcReady()
|
||||||
self._mpcApi.callbacks.onUpdateFilename = lambda _: self.__handleUpdatedFilename()
|
self._mpcApi.callbacks.onUpdateFilename = lambda _: self.__handleUpdatedFilename()
|
||||||
self.__client.initPlayer(self)
|
self.reactor.callFromThread(self.__client.initPlayer, (self))
|
||||||
self.__handleUpdatedFilename()
|
self.__handleUpdatedFilename()
|
||||||
self.askForStatus()
|
self.askForStatus()
|
||||||
except Exception, err:
|
except Exception, err:
|
||||||
self.__client.ui.showErrorMessage(err.message)
|
self.__client.ui.showErrorMessage(err.message)
|
||||||
self.__client.stop()
|
self.reactor.callFromThread(self.__client.stop)
|
||||||
|
|
||||||
def initPlayer(self, filePath):
|
def initPlayer(self, filePath):
|
||||||
self.__dropIfNotSufficientVersion()
|
self.__dropIfNotSufficientVersion()
|
||||||
@ -448,11 +450,12 @@ class MPCHCAPIPlayer(BasePlayer):
|
|||||||
def __handleUpdatedFilename(self):
|
def __handleUpdatedFilename(self):
|
||||||
with self.__fileUpdate:
|
with self.__fileUpdate:
|
||||||
self.__setUpStateForNewlyOpenedFile()
|
self.__setUpStateForNewlyOpenedFile()
|
||||||
self.__client.updateFile(self._mpcApi.filePlaying, self._mpcApi.fileDuration, self._mpcApi.filePath)
|
args = (self._mpcApi.filePlaying, self._mpcApi.fileDuration, self._mpcApi.filePath)
|
||||||
|
self.reactor.callFromThread(self.__client.updateFile, *args)
|
||||||
|
|
||||||
def __mpcError(self, err=""):
|
def __mpcError(self, err=""):
|
||||||
self.__client.ui.showErrorMessage(err)
|
self.__client.ui.showErrorMessage(err)
|
||||||
self.__client.stop()
|
self.reactor.callFromThread(self.__client.stop)
|
||||||
|
|
||||||
def sendCustomCommand(self, cmd, val):
|
def sendCustomCommand(self, cmd, val):
|
||||||
self._mpcApi.sendRawCommand(cmd, val)
|
self._mpcApi.sendRawCommand(cmd, val)
|
||||||
|
|||||||
@ -8,6 +8,8 @@ from syncplay.players.playerFactory import PlayerFactory
|
|||||||
import codecs
|
import codecs
|
||||||
try:
|
try:
|
||||||
from syncplay.ui.GuiConfiguration import GuiConfiguration
|
from syncplay.ui.GuiConfiguration import GuiConfiguration
|
||||||
|
from PySide import QtGui #@UnresolvedImport
|
||||||
|
from PySide.QtCore import Qt, QCoreApplication
|
||||||
except ImportError:
|
except ImportError:
|
||||||
GuiConfiguration = None
|
GuiConfiguration = None
|
||||||
|
|
||||||
@ -205,8 +207,9 @@ class ConfigurationGetter(object):
|
|||||||
except InvalidConfigValue:
|
except InvalidConfigValue:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
for key, value in self._promptForMissingArguments().items():
|
if(self._config['noGui'] == False):
|
||||||
self._config[key] = value
|
for key, value in self._promptForMissingArguments().items():
|
||||||
|
self._config[key] = value
|
||||||
except:
|
except:
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
@ -240,5 +243,10 @@ class ConfigurationGetter(object):
|
|||||||
self._saveConfig(iniPath)
|
self._saveConfig(iniPath)
|
||||||
if(self._config['file']):
|
if(self._config['file']):
|
||||||
self._loadRelativeConfiguration()
|
self._loadRelativeConfiguration()
|
||||||
|
if(not self._config['noGui']):
|
||||||
|
from syncplay.vendor import qt4reactor
|
||||||
|
if QCoreApplication.instance() is None:
|
||||||
|
self.app = QtGui.QApplication(sys.argv)
|
||||||
|
qt4reactor.install()
|
||||||
return self._config
|
return self._config
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
from PySide import QtCore, QtGui
|
from PySide import QtCore, QtGui
|
||||||
from PySide.QtCore import QSettings, Qt
|
from PySide.QtCore import QSettings, Qt, QCoreApplication
|
||||||
from PySide.QtGui import QApplication, QLineEdit, QCursor, QLabel, QCheckBox, QDesktopServices, QIcon
|
from PySide.QtGui import QApplication, QLineEdit, QCursor, QLabel, QCheckBox, QDesktopServices, QIcon
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@ -14,10 +14,8 @@ class GuiConfiguration:
|
|||||||
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
try:
|
if QCoreApplication.instance() is None:
|
||||||
self.app = QtGui.QApplication(sys.argv)
|
self.app = QtGui.QApplication(sys.argv)
|
||||||
except:
|
|
||||||
pass
|
|
||||||
dialog = ConfigDialog(self.config, self._availablePlayerPaths, self.error)
|
dialog = ConfigDialog(self.config, self._availablePlayerPaths, self.error)
|
||||||
dialog.exec_()
|
dialog.exec_()
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
from syncplay.ui.gui import GraphicalUI
|
from syncplay.ui.gui import MainDialog as GraphicalUI
|
||||||
from syncplay.ui.consoleUI import ConsoleUI
|
from syncplay.ui.consoleUI import ConsoleUI
|
||||||
|
|
||||||
def getUi(graphical=True):
|
def getUi(graphical=True):
|
||||||
if(False): #graphical): #TODO: Add graphical ui
|
if(graphical): #TODO: Add graphical ui
|
||||||
ui = GraphicalUI()
|
ui = GraphicalUI()
|
||||||
else:
|
else:
|
||||||
ui = ConsoleUI()
|
ui = ConsoleUI()
|
||||||
ui.setDaemon(True)
|
ui.setDaemon(True)
|
||||||
ui.start()
|
ui.start()
|
||||||
return ui
|
return ui
|
||||||
|
|||||||
@ -40,6 +40,15 @@ class ConsoleUI(threading.Thread):
|
|||||||
self.promptMode.wait()
|
self.promptMode.wait()
|
||||||
return self.PromptResult
|
return self.PromptResult
|
||||||
|
|
||||||
|
def showListMessage(self, message):
|
||||||
|
self.showMessage(message, True)
|
||||||
|
|
||||||
|
def markEndOfUserlist(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def userListChange(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def showMessage(self, message, noTimestamp=False):
|
def showMessage(self, message, noTimestamp=False):
|
||||||
message = message.encode(sys.stdout.encoding, 'replace')
|
message = message.encode(sys.stdout.encoding, 'replace')
|
||||||
if(noTimestamp):
|
if(noTimestamp):
|
||||||
|
|||||||
@ -1,9 +1,264 @@
|
|||||||
'''
|
from PySide import QtGui #@UnresolvedImport
|
||||||
Created on 05-07-2012
|
from PySide.QtCore import Qt #@UnresolvedImport
|
||||||
|
from syncplay import utils, constants
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import re
|
||||||
|
|
||||||
@author: Uriziel
|
class MainDialog(QtGui.QDialog):
|
||||||
'''
|
def addClient(self, client):
|
||||||
|
self._syncplayClient = client
|
||||||
|
|
||||||
|
def promptFor(self, prompt=">", message=""):
|
||||||
|
#TODO: Prompt user
|
||||||
|
return None
|
||||||
|
|
||||||
class GraphicalUI(object):
|
def showMessage(self, message, noTimestamp=False):
|
||||||
|
message = message.encode(sys.stdout.encoding, 'replace')
|
||||||
|
message = message.replace("&", "&").replace('"', """).replace("<", "<").replace(">", ">")
|
||||||
|
message = message.replace("\n", "<br />")
|
||||||
|
if(noTimestamp):
|
||||||
|
self.newMessage(message + "<br />")
|
||||||
|
else:
|
||||||
|
self.newMessage(time.strftime(constants.UI_TIME_FORMAT, time.localtime()) + message + "<br />")
|
||||||
|
|
||||||
|
def showListMessage(self, message):
|
||||||
|
message = message.encode(sys.stdout.encoding, 'replace')
|
||||||
|
message = message.replace("&", "&").replace('"', """).replace("<", "<").replace(">", ">")
|
||||||
|
message = message.replace("\t", " "*4)
|
||||||
|
self._listBuffer += message + "<br />"
|
||||||
|
|
||||||
|
def markEndOfUserlist(self):
|
||||||
|
self.resetList()
|
||||||
|
self.newListItem(self._listBuffer)
|
||||||
|
self._listBuffer = "";
|
||||||
|
|
||||||
|
def userListChange(self):
|
||||||
|
self._syncplayClient.showUserList()
|
||||||
|
|
||||||
|
def showDebugMessage(self, message):
|
||||||
|
print(message)
|
||||||
|
|
||||||
|
def showErrorMessage(self, message):
|
||||||
|
print("ERROR:\t" + message)
|
||||||
|
|
||||||
|
def joinRoom(self):
|
||||||
|
room = self.roomInput.text()
|
||||||
|
if room == "":
|
||||||
|
if self._syncplayClient.userlist.currentUser.file:
|
||||||
|
room = self._syncplayClient.userlist.currentUser.file["name"]
|
||||||
|
else:
|
||||||
|
room = self._syncplayClient.defaultRoom
|
||||||
|
self._syncplayClient.setRoom(room)
|
||||||
|
self._syncplayClient.sendRoom()
|
||||||
|
|
||||||
|
def seekPosition(self):
|
||||||
|
s = re.match(constants.UI_SEEK_REGEX, self.seekInput.text())
|
||||||
|
if(s):
|
||||||
|
sign = self._extractSign(s.group('sign'))
|
||||||
|
t = utils.parseTime(s.group('time'))
|
||||||
|
if(t is None):
|
||||||
|
return
|
||||||
|
if(sign):
|
||||||
|
t = self._syncplayClient.getGlobalPosition() + sign * t
|
||||||
|
self._syncplayClient.setPosition(t)
|
||||||
|
self.seekInput.setText("")
|
||||||
|
else:
|
||||||
|
self.showMessage("Invalid seek value", True)
|
||||||
|
|
||||||
|
def showList(self):
|
||||||
|
self._syncplayClient.getUserList() #TODO: remove?
|
||||||
|
|
||||||
|
def undoSeek(self):
|
||||||
|
tmp_pos = self._syncplayClient.getPlayerPosition()
|
||||||
|
self._syncplayClient.setPosition(self._syncplayClient.playerPositionBeforeLastSeek)
|
||||||
|
self._syncplayClient.playerPositionBeforeLastSeek = tmp_pos
|
||||||
|
|
||||||
|
def togglePause(self):
|
||||||
|
self._syncplayClient.setPaused(not self._syncplayClient.getPlayerPaused())
|
||||||
|
|
||||||
|
def exitSyncplay(self):
|
||||||
|
self._syncplayClient.stop()
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
self.exitSyncplay()
|
||||||
|
event.ignore()
|
||||||
|
|
||||||
|
def _extractSign(self, m):
|
||||||
|
if(m):
|
||||||
|
if(m == "-"):
|
||||||
|
return -1
|
||||||
|
else:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def setOffset(self):
|
||||||
|
newoffset, ok = QtGui.QInputDialog.getText(self,"Set Offset",
|
||||||
|
"Offset (+/-):", QtGui.QLineEdit.Normal,
|
||||||
|
"")
|
||||||
|
if ok and newoffset != '':
|
||||||
|
o = re.match(constants.UI_OFFSET_REGEX, newoffset)
|
||||||
|
if(o):
|
||||||
|
sign = self._extractSign(o.group('sign'))
|
||||||
|
t = utils.parseTime(o.group('time'))
|
||||||
|
if(t is None):
|
||||||
|
return
|
||||||
|
if (o.group('sign') == "/"):
|
||||||
|
t = self._syncplayClient.getPlayerPosition() - t
|
||||||
|
elif(sign):
|
||||||
|
t = self._syncplayClient.getUserOffset() + sign * t
|
||||||
|
self._syncplayClient.setUserOffset(t)
|
||||||
|
else:
|
||||||
|
self.showMessage("Invalid offset value", True)
|
||||||
|
|
||||||
|
def openUserGuide(self):
|
||||||
|
self.QtGui.QDesktopServices.openUrl("http://syncplay.pl/guide/")
|
||||||
|
|
||||||
|
def addTopLayout(self, dialog):
|
||||||
|
dialog.topSplit = QtGui.QSplitter(Qt.Horizontal)
|
||||||
|
|
||||||
|
dialog.outputLayout = QtGui.QVBoxLayout()
|
||||||
|
dialog.outputbox = QtGui.QTextEdit()
|
||||||
|
dialog.outputbox.setReadOnly(True)
|
||||||
|
dialog.outputlabel = QtGui.QLabel("Notifications")
|
||||||
|
dialog.outputFrame = QtGui.QFrame()
|
||||||
|
dialog.outputFrame.setLineWidth(0)
|
||||||
|
dialog.outputFrame.setMidLineWidth(0)
|
||||||
|
dialog.outputLayout.setContentsMargins(0,0,0,0)
|
||||||
|
dialog.outputLayout.addWidget(dialog.outputlabel)
|
||||||
|
dialog.outputLayout.addWidget(dialog.outputbox)
|
||||||
|
dialog.outputFrame.setLayout(dialog.outputLayout)
|
||||||
|
|
||||||
|
dialog.listLayout = QtGui.QVBoxLayout()
|
||||||
|
dialog.listbox = QtGui.QTextEdit()
|
||||||
|
dialog.listbox.setReadOnly(True)
|
||||||
|
dialog.listlabel = QtGui.QLabel("List of who is playing what")
|
||||||
|
dialog.listFrame = QtGui.QFrame()
|
||||||
|
dialog.listFrame.setLineWidth(0)
|
||||||
|
dialog.listFrame.setMidLineWidth(0)
|
||||||
|
dialog.listLayout.setContentsMargins(0,0,0,0)
|
||||||
|
dialog.listLayout.addWidget(dialog.listlabel)
|
||||||
|
dialog.listLayout.addWidget(dialog.listbox)
|
||||||
|
dialog.listFrame.setLayout(dialog.listLayout)
|
||||||
|
|
||||||
|
dialog.topSplit.addWidget(dialog.outputFrame)
|
||||||
|
dialog.topSplit.addWidget(dialog.listFrame)
|
||||||
|
dialog.topSplit.setStretchFactor(0,3)
|
||||||
|
dialog.topSplit.setStretchFactor(1,2)
|
||||||
|
dialog.mainLayout.addWidget(dialog.topSplit)
|
||||||
|
dialog.topSplit.setSizePolicy(QtGui.QSizePolicy.Preferred,QtGui.QSizePolicy.Expanding)
|
||||||
|
|
||||||
|
def addBottomLayout(self, dialog):
|
||||||
|
dialog.bottomLayout = QtGui.QHBoxLayout()
|
||||||
|
|
||||||
|
dialog.addRoomBox(MainDialog)
|
||||||
|
dialog.addSeekBox(MainDialog)
|
||||||
|
dialog.addMiscBox(MainDialog)
|
||||||
|
|
||||||
|
dialog.bottomLayout.addWidget(dialog.roomGroup, Qt.AlignLeft)
|
||||||
|
dialog.bottomLayout.addWidget(dialog.seekGroup, Qt.AlignLeft)
|
||||||
|
dialog.bottomLayout.addWidget(dialog.miscGroup, Qt.AlignLeft)
|
||||||
|
|
||||||
|
dialog.mainLayout.addLayout(dialog.bottomLayout, Qt.AlignLeft)
|
||||||
|
|
||||||
|
def addRoomBox(self, dialog):
|
||||||
|
dialog.roomGroup = QtGui.QGroupBox("Room")
|
||||||
|
|
||||||
|
dialog.roomInput = QtGui.QLineEdit()
|
||||||
|
dialog.roomButton = QtGui.QPushButton(QtGui.QIcon(self.resourcespath + 'door_in.png'), "Join room")
|
||||||
|
dialog.roomButton.pressed.connect(self.joinRoom)
|
||||||
|
dialog.roomLayout = QtGui.QHBoxLayout()
|
||||||
|
dialog.roomInput.setMaximumWidth(150)
|
||||||
|
|
||||||
|
dialog.roomLayout.addWidget(dialog.roomInput)
|
||||||
|
dialog.roomLayout.addWidget(dialog.roomButton)
|
||||||
|
|
||||||
|
dialog.roomGroup.setLayout(dialog.roomLayout)
|
||||||
|
dialog.roomGroup.setFixedSize(dialog.roomGroup.sizeHint())
|
||||||
|
|
||||||
|
def addSeekBox(self, dialog):
|
||||||
|
dialog.seekGroup = QtGui.QGroupBox("Seek")
|
||||||
|
|
||||||
|
dialog.seekInput = QtGui.QLineEdit()
|
||||||
|
dialog.seekButton = QtGui.QPushButton(QtGui.QIcon(self.resourcespath + 'clock_go.png'),"Seek to position")
|
||||||
|
dialog.seekButton.pressed.connect(self.seekPosition)
|
||||||
|
|
||||||
|
dialog.seekLayout = QtGui.QHBoxLayout()
|
||||||
|
dialog.seekInput.setMaximumWidth(100)
|
||||||
|
|
||||||
|
dialog.seekLayout.addWidget(dialog.seekInput)
|
||||||
|
dialog.seekLayout.addWidget(dialog.seekButton)
|
||||||
|
|
||||||
|
dialog.seekGroup.setLayout(dialog.seekLayout)
|
||||||
|
dialog.seekGroup.setFixedSize(dialog.seekGroup.sizeHint())
|
||||||
|
|
||||||
|
def addMiscBox(self, dialog):
|
||||||
|
dialog.miscGroup = QtGui.QGroupBox("Other Commands")
|
||||||
|
|
||||||
|
dialog.unseekButton = QtGui.QPushButton(QtGui.QIcon(self.resourcespath + 'arrow_undo.png'),"Undo last seek")
|
||||||
|
dialog.unseekButton.pressed.connect(self.undoSeek)
|
||||||
|
dialog.pauseButton = QtGui.QPushButton(QtGui.QIcon(self.resourcespath + 'control_pause_blue.png'),"Toggle pause")
|
||||||
|
dialog.pauseButton.pressed.connect(self.togglePause)
|
||||||
|
dialog.showListButton = QtGui.QPushButton(QtGui.QIcon(self.resourcespath + 'table_refresh.png'),"Update list")
|
||||||
|
dialog.showListButton.pressed.connect(self.showList)
|
||||||
|
|
||||||
|
dialog.miscLayout = QtGui.QHBoxLayout()
|
||||||
|
dialog.miscLayout.addWidget(dialog.unseekButton)
|
||||||
|
dialog.miscLayout.addWidget(dialog.pauseButton)
|
||||||
|
dialog.miscLayout.addWidget(dialog.showListButton)
|
||||||
|
|
||||||
|
dialog.miscGroup.setLayout(dialog.miscLayout)
|
||||||
|
dialog.miscGroup.setFixedSize(dialog.miscGroup.sizeHint())
|
||||||
|
|
||||||
|
|
||||||
|
def addMenubar(self, dialog):
|
||||||
|
dialog.menuBar = QtGui.QMenuBar()
|
||||||
|
|
||||||
|
dialog.fileMenu = QtGui.QMenu("&File", self)
|
||||||
|
dialog.exitAction = dialog.fileMenu.addAction(QtGui.QIcon(self.resourcespath + 'cross.png'), "E&xit")
|
||||||
|
dialog.exitAction.triggered.connect(self.exitSyncplay)
|
||||||
|
dialog.menuBar.addMenu(dialog.fileMenu)
|
||||||
|
|
||||||
|
dialog.advancedMenu = QtGui.QMenu("&Advanced", self)
|
||||||
|
dialog.setoffsetAction = dialog.advancedMenu.addAction(QtGui.QIcon(self.resourcespath + 'timeline_marker.png'),"Set &Offset")
|
||||||
|
dialog.setoffsetAction.triggered.connect(self.setOffset)
|
||||||
|
dialog.menuBar.addMenu(dialog.advancedMenu)
|
||||||
|
|
||||||
|
dialog.helpMenu = QtGui.QMenu("&Help", self)
|
||||||
|
dialog.userguideAction = dialog.helpMenu.addAction(QtGui.QIcon(self.resourcespath + 'help.png'), "Open User &Guide")
|
||||||
|
dialog.userguideAction.triggered.connect(self.openUserGuide)
|
||||||
|
|
||||||
|
dialog.menuBar.addMenu(dialog.helpMenu)
|
||||||
|
dialog.mainLayout.setMenuBar(dialog.menuBar)
|
||||||
|
|
||||||
|
def newMessage(self, message):
|
||||||
|
self.outputbox.moveCursor(QtGui.QTextCursor.End)
|
||||||
|
self.outputbox.insertHtml(message)
|
||||||
|
self.outputbox.moveCursor(QtGui.QTextCursor.End)
|
||||||
|
|
||||||
|
def resetList(self):
|
||||||
|
self.listbox.setText("")
|
||||||
|
|
||||||
|
def newListItem(self, item):
|
||||||
|
self.listbox.moveCursor(QtGui.QTextCursor.End)
|
||||||
|
self.listbox.insertHtml(item)
|
||||||
|
self.listbox.moveCursor(QtGui.QTextCursor.End)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
super(MainDialog, self).__init__()
|
||||||
|
self.QtGui = QtGui
|
||||||
|
self._listBuffer = ""
|
||||||
|
if sys.platform.startswith('linux'):
|
||||||
|
self.resourcespath = utils.findWorkingDir() + "/resources/"
|
||||||
|
else:
|
||||||
|
self.resourcespath = utils.findWorkingDir() + "\\resources\\"
|
||||||
|
self.setWindowTitle("Syncplay - Main Window")
|
||||||
|
self.mainLayout = QtGui.QVBoxLayout()
|
||||||
|
self.addTopLayout(self)
|
||||||
|
self.addBottomLayout(self)
|
||||||
|
self.addMenubar(self)
|
||||||
|
self.setLayout(self.mainLayout)
|
||||||
|
self.resize(700,500)
|
||||||
|
self.setWindowIcon(QtGui.QIcon(self.resourcespath + "syncplay.png"))
|
||||||
|
self.show()
|
||||||
|
|||||||
0
syncplay/vendor/__init__.py
vendored
Normal file
359
syncplay/vendor/qt4reactor.py
vendored
Normal file
@ -0,0 +1,359 @@
|
|||||||
|
# Copyright (c) 2001-2011 Twisted Matrix Laboratories.
|
||||||
|
# See LICENSE for details.
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
This module provides support for Twisted to be driven by the Qt mainloop.
|
||||||
|
|
||||||
|
In order to use this support, simply do the following::
|
||||||
|
| app = QApplication(sys.argv) # your code to init Qt
|
||||||
|
| import qt4reactor
|
||||||
|
| qt4reactor.install()
|
||||||
|
|
||||||
|
alternatively:
|
||||||
|
|
||||||
|
| from twisted.application import reactors
|
||||||
|
| reactors.installReactor('qt4')
|
||||||
|
|
||||||
|
Then use twisted.internet APIs as usual. The other methods here are not
|
||||||
|
intended to be called directly.
|
||||||
|
|
||||||
|
If you don't instantiate a QApplication or QCoreApplication prior to
|
||||||
|
installing the reactor, a QCoreApplication will be constructed
|
||||||
|
by the reactor. QCoreApplication does not require a GUI so trial testing
|
||||||
|
can occur normally.
|
||||||
|
|
||||||
|
Twisted can be initialized after QApplication.exec_() with a call to
|
||||||
|
reactor.runReturn(). calling reactor.stop() will unhook twisted but
|
||||||
|
leave your Qt application running
|
||||||
|
|
||||||
|
API Stability: stable
|
||||||
|
|
||||||
|
Maintainer: U{Glenn H Tarbox, PhD<mailto:glenn@tarbox.org>}
|
||||||
|
|
||||||
|
Previous maintainer: U{Itamar Shtull-Trauring<mailto:twisted@itamarst.org>}
|
||||||
|
Original port to QT4: U{Gabe Rudy<mailto:rudy@goldenhelix.com>}
|
||||||
|
Subsequent port by therve
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
from zope.interface import implements
|
||||||
|
from twisted.internet.interfaces import IReactorFDSet
|
||||||
|
from twisted.python import log, runtime
|
||||||
|
from twisted.internet import posixbase
|
||||||
|
from twisted.python.runtime import platformType, platform
|
||||||
|
|
||||||
|
try:
|
||||||
|
from PyQt4.QtCore import QSocketNotifier, QObject, SIGNAL, QTimer, QCoreApplication
|
||||||
|
from PyQt4.QtCore import QEventLoop
|
||||||
|
except ImportError:
|
||||||
|
from PySide.QtCore import QSocketNotifier, QObject, SIGNAL, QTimer, QCoreApplication
|
||||||
|
from PySide.QtCore import QEventLoop
|
||||||
|
|
||||||
|
|
||||||
|
class TwistedSocketNotifier(QObject):
|
||||||
|
"""
|
||||||
|
Connection between an fd event and reader/writer callbacks.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, parent, reactor, watcher, socketType):
|
||||||
|
QObject.__init__(self, parent)
|
||||||
|
self.reactor = reactor
|
||||||
|
self.watcher = watcher
|
||||||
|
fd = watcher.fileno()
|
||||||
|
self.notifier = QSocketNotifier(fd, socketType, parent)
|
||||||
|
self.notifier.setEnabled(True)
|
||||||
|
if socketType == QSocketNotifier.Read:
|
||||||
|
self.fn = self.read
|
||||||
|
else:
|
||||||
|
self.fn = self.write
|
||||||
|
QObject.connect(self.notifier, SIGNAL("activated(int)"), self.fn)
|
||||||
|
|
||||||
|
|
||||||
|
def shutdown(self):
|
||||||
|
self.notifier.setEnabled(False)
|
||||||
|
self.disconnect(self.notifier, SIGNAL("activated(int)"), self.fn)
|
||||||
|
self.fn = self.watcher = None
|
||||||
|
self.notifier.deleteLater()
|
||||||
|
self.deleteLater()
|
||||||
|
|
||||||
|
|
||||||
|
def read(self, fd):
|
||||||
|
if not self.watcher:
|
||||||
|
return
|
||||||
|
w = self.watcher
|
||||||
|
# doRead can cause self.shutdown to be called so keep a reference to self.watcher
|
||||||
|
def _read():
|
||||||
|
#Don't call me again, until the data has been read
|
||||||
|
self.notifier.setEnabled(False)
|
||||||
|
why = None
|
||||||
|
try:
|
||||||
|
why = w.doRead()
|
||||||
|
inRead = True
|
||||||
|
except:
|
||||||
|
inRead = False
|
||||||
|
log.err()
|
||||||
|
why = sys.exc_info()[1]
|
||||||
|
if why:
|
||||||
|
self.reactor._disconnectSelectable(w, why, inRead)
|
||||||
|
elif self.watcher:
|
||||||
|
self.notifier.setEnabled(True) # Re enable notification following sucessfull read
|
||||||
|
self.reactor._iterate(fromqt=True)
|
||||||
|
log.callWithLogger(w, _read)
|
||||||
|
|
||||||
|
def write(self, sock):
|
||||||
|
if not self.watcher:
|
||||||
|
return
|
||||||
|
w = self.watcher
|
||||||
|
def _write():
|
||||||
|
why = None
|
||||||
|
self.notifier.setEnabled(False)
|
||||||
|
|
||||||
|
try:
|
||||||
|
why = w.doWrite()
|
||||||
|
except:
|
||||||
|
log.err()
|
||||||
|
why = sys.exc_info()[1]
|
||||||
|
if why:
|
||||||
|
self.reactor._disconnectSelectable(w, why, False)
|
||||||
|
elif self.watcher:
|
||||||
|
self.notifier.setEnabled(True)
|
||||||
|
self.reactor._iterate(fromqt=True)
|
||||||
|
log.callWithLogger(w, _write)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class QtReactor(posixbase.PosixReactorBase):
|
||||||
|
implements(IReactorFDSet)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._reads = {}
|
||||||
|
self._writes = {}
|
||||||
|
self._notifiers = {}
|
||||||
|
self._timer = QTimer()
|
||||||
|
self._timer.setSingleShot(True)
|
||||||
|
QObject.connect(self._timer, SIGNAL("timeout()"), self.iterate)
|
||||||
|
|
||||||
|
if QCoreApplication.instance() is None:
|
||||||
|
# Application Object has not been started yet
|
||||||
|
self.qApp=QCoreApplication([])
|
||||||
|
self._ownApp=True
|
||||||
|
else:
|
||||||
|
self.qApp = QCoreApplication.instance()
|
||||||
|
self._ownApp=False
|
||||||
|
self._blockApp = None
|
||||||
|
posixbase.PosixReactorBase.__init__(self)
|
||||||
|
|
||||||
|
|
||||||
|
def _add(self, xer, primary, type):
|
||||||
|
"""
|
||||||
|
Private method for adding a descriptor from the event loop.
|
||||||
|
|
||||||
|
It takes care of adding it if new or modifying it if already added
|
||||||
|
for another state (read -> read/write for example).
|
||||||
|
"""
|
||||||
|
if xer not in primary:
|
||||||
|
primary[xer] = TwistedSocketNotifier(None, self, xer, type)
|
||||||
|
|
||||||
|
|
||||||
|
def addReader(self, reader):
|
||||||
|
"""
|
||||||
|
Add a FileDescriptor for notification of data available to read.
|
||||||
|
"""
|
||||||
|
self._add(reader, self._reads, QSocketNotifier.Read)
|
||||||
|
|
||||||
|
|
||||||
|
def addWriter(self, writer):
|
||||||
|
"""
|
||||||
|
Add a FileDescriptor for notification of data available to write.
|
||||||
|
"""
|
||||||
|
self._add(writer, self._writes, QSocketNotifier.Write)
|
||||||
|
|
||||||
|
|
||||||
|
def _remove(self, xer, primary):
|
||||||
|
"""
|
||||||
|
Private method for removing a descriptor from the event loop.
|
||||||
|
|
||||||
|
It does the inverse job of _add, and also add a check in case of the fd
|
||||||
|
has gone away.
|
||||||
|
"""
|
||||||
|
if xer in primary:
|
||||||
|
notifier = primary.pop(xer)
|
||||||
|
notifier.shutdown()
|
||||||
|
|
||||||
|
|
||||||
|
def removeReader(self, reader):
|
||||||
|
"""
|
||||||
|
Remove a Selectable for notification of data available to read.
|
||||||
|
"""
|
||||||
|
self._remove(reader, self._reads)
|
||||||
|
|
||||||
|
|
||||||
|
def removeWriter(self, writer):
|
||||||
|
"""
|
||||||
|
Remove a Selectable for notification of data available to write.
|
||||||
|
"""
|
||||||
|
self._remove(writer, self._writes)
|
||||||
|
|
||||||
|
|
||||||
|
def removeAll(self):
|
||||||
|
"""
|
||||||
|
Remove all selectables, and return a list of them.
|
||||||
|
"""
|
||||||
|
rv = self._removeAll(self._reads, self._writes)
|
||||||
|
return rv
|
||||||
|
|
||||||
|
|
||||||
|
def getReaders(self):
|
||||||
|
return self._reads.keys()
|
||||||
|
|
||||||
|
|
||||||
|
def getWriters(self):
|
||||||
|
return self._writes.keys()
|
||||||
|
|
||||||
|
|
||||||
|
def callLater(self,howlong, *args, **kargs):
|
||||||
|
rval = super(QtReactor,self).callLater(howlong, *args, **kargs)
|
||||||
|
self.reactorInvocation()
|
||||||
|
return rval
|
||||||
|
|
||||||
|
|
||||||
|
def reactorInvocation(self):
|
||||||
|
self._timer.stop()
|
||||||
|
self._timer.setInterval(0)
|
||||||
|
self._timer.start()
|
||||||
|
|
||||||
|
|
||||||
|
def _iterate(self, delay=None, fromqt=False):
|
||||||
|
"""See twisted.internet.interfaces.IReactorCore.iterate.
|
||||||
|
"""
|
||||||
|
self.runUntilCurrent()
|
||||||
|
self.doIteration(delay, fromqt)
|
||||||
|
|
||||||
|
iterate = _iterate
|
||||||
|
|
||||||
|
def doIteration(self, delay=None, fromqt=False):
|
||||||
|
'This method is called by a Qt timer or by network activity on a file descriptor'
|
||||||
|
|
||||||
|
if not self.running and self._blockApp:
|
||||||
|
self._blockApp.quit()
|
||||||
|
self._timer.stop()
|
||||||
|
delay = max(delay, 1)
|
||||||
|
if not fromqt:
|
||||||
|
self.qApp.processEvents(QEventLoop.AllEvents, delay * 1000)
|
||||||
|
if self.timeout() is None:
|
||||||
|
timeout = 0.1
|
||||||
|
elif self.timeout() == 0:
|
||||||
|
timeout = 0
|
||||||
|
else:
|
||||||
|
timeout = self.timeout()
|
||||||
|
self._timer.setInterval(timeout * 1000)
|
||||||
|
self._timer.start()
|
||||||
|
|
||||||
|
|
||||||
|
def runReturn(self, installSignalHandlers=True):
|
||||||
|
self.startRunning(installSignalHandlers=installSignalHandlers)
|
||||||
|
self.reactorInvocation()
|
||||||
|
|
||||||
|
|
||||||
|
def run(self, installSignalHandlers=True):
|
||||||
|
if self._ownApp:
|
||||||
|
self._blockApp = self.qApp
|
||||||
|
else:
|
||||||
|
self._blockApp = QEventLoop()
|
||||||
|
self.runReturn()
|
||||||
|
self._blockApp.exec_()
|
||||||
|
|
||||||
|
|
||||||
|
class QtEventReactor(QtReactor):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self._events = {}
|
||||||
|
super(QtEventReactor, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
|
def addEvent(self, event, fd, action):
|
||||||
|
"""
|
||||||
|
Add a new win32 event to the event loop.
|
||||||
|
"""
|
||||||
|
self._events[event] = (fd, action)
|
||||||
|
|
||||||
|
|
||||||
|
def removeEvent(self, event):
|
||||||
|
"""
|
||||||
|
Remove an event.
|
||||||
|
"""
|
||||||
|
if event in self._events:
|
||||||
|
del self._events[event]
|
||||||
|
|
||||||
|
|
||||||
|
def doEvents(self):
|
||||||
|
handles = self._events.keys()
|
||||||
|
if len(handles) > 0:
|
||||||
|
val = None
|
||||||
|
while val != WAIT_TIMEOUT:
|
||||||
|
val = MsgWaitForMultipleObjects(handles, 0, 0, QS_ALLINPUT | QS_ALLEVENTS)
|
||||||
|
if val >= WAIT_OBJECT_0 and val < WAIT_OBJECT_0 + len(handles):
|
||||||
|
event_id = handles[val - WAIT_OBJECT_0]
|
||||||
|
if event_id in self._events:
|
||||||
|
fd, action = self._events[event_id]
|
||||||
|
log.callWithLogger(fd, self._runAction, action, fd)
|
||||||
|
elif val == WAIT_TIMEOUT:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
#print 'Got an unexpected return of %r' % val
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def _runAction(self, action, fd):
|
||||||
|
try:
|
||||||
|
closed = getattr(fd, action)()
|
||||||
|
except:
|
||||||
|
closed = sys.exc_info()[1]
|
||||||
|
log.deferr()
|
||||||
|
|
||||||
|
if closed:
|
||||||
|
self._disconnectSelectable(fd, closed, action == 'doRead')
|
||||||
|
|
||||||
|
|
||||||
|
def timeout(self):
|
||||||
|
t = super(QtEventReactor, self).timeout()
|
||||||
|
return min(t, 0.01)
|
||||||
|
|
||||||
|
|
||||||
|
def iterate(self, delay=None):
|
||||||
|
"""See twisted.internet.interfaces.IReactorCore.iterate.
|
||||||
|
"""
|
||||||
|
self.runUntilCurrent()
|
||||||
|
self.doEvents()
|
||||||
|
self.doIteration(delay)
|
||||||
|
|
||||||
|
|
||||||
|
def posixinstall():
|
||||||
|
"""
|
||||||
|
Install the Qt reactor.
|
||||||
|
"""
|
||||||
|
p = QtReactor()
|
||||||
|
from twisted.internet.main import installReactor
|
||||||
|
installReactor(p)
|
||||||
|
|
||||||
|
|
||||||
|
def win32install():
|
||||||
|
"""
|
||||||
|
Install the Qt reactor.
|
||||||
|
"""
|
||||||
|
p = QtEventReactor()
|
||||||
|
from twisted.internet.main import installReactor
|
||||||
|
installReactor(p)
|
||||||
|
|
||||||
|
|
||||||
|
if runtime.platform.getType() == 'win32':
|
||||||
|
from win32event import CreateEvent, MsgWaitForMultipleObjects
|
||||||
|
from win32event import WAIT_OBJECT_0, WAIT_TIMEOUT, QS_ALLINPUT, QS_ALLEVENTS
|
||||||
|
install = win32install
|
||||||
|
else:
|
||||||
|
install = posixinstall
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["install"]
|
||||||
|
|
||||||