Пример #1
0
 def __init__(self):
     self.templates = jinja2.Environment(
         loader=jinja2.FileSystemLoader('templates'),
         trim_blocks=True,
         autoescape=True)
     self.templates.filters['get_device_icon'] = self.get_device_icon
     self.device_list = DeviceManager()
     self.unlocked_ports = {}
     self.device_list.register('added', router.add_device)
Пример #2
0
class Client(QtCore.QObject):

    playerChanged = QtCore.Signal()

    def __init__(self, showApp=False):
        QtCore.QObject.__init__(self)
        self.showApp = showApp
        self.player = None
        self.deviceMan = DeviceManager(startWatcher=True)
        self.updatePlayer()
        self.deviceMan.setActiveDeviceCapabilities([devices.Capability.ProvideContent, devices.Capability.PlayMusic])
        self.devicePresenceBroadcaster = DevicePresenceBroadcaster(self.deviceMan.getActiveDevice())

    def init(self):
        try:
            self.app = QtGui.QApplication(sys.argv)
        except RuntimeError:
            self.app = QtCore.QCoreApplication.instance()
        self.app.setApplicationName('yamclient')
        self.mainWin = MainWindow()
        self.bindEvents()
        self.deviceStateChangeWatcher = DeviceWatcher(portToWatch=5556, callback=self.playerStateChanged)
        self.deviceStateChangeWatcher.start()
        #self.devicePresenceBroadcaster.start()


    def bindEvents(self):
        self.app.aboutToQuit.connect(self.stop)

    def updatePlayer(self):
        activeDevice = self.deviceMan.getActiveDevice()

        if activeDevice:
            self.player = players.getPlayerByType(activeDevice)
            self.player.registerToStateChanges(activeDevice.host)
            self.playerChanged.emit()

    def playerStateChanged(self, state):
        self.player.stateChanged.emit(state)

    def start(self):
        try:
            if self.showApp:
                self.mainWin.show_and_raise()
            # Enter Qt application main loop
            self.app.exec_()
        except (KeyboardInterrupt, SystemExit):
            pass

    def close(self):
        #TODO : Remove
        self.deviceMan.dispose()
        self.app.exit()
        self.player.stop()

    def stop(self):
        if self.deviceMan: self.deviceMan.dispose()
        if self.app: self.app.exit()
        if self.player: self.player.stop()
Пример #3
0
    def __init__(self):
        super().__init__()
        self.espState = False
        #self.second_key = str(randint(10000, 99999))
        self.setWindowTitle('IoT Device Manager')
        self.resize(250, 120)
        self.devices = DeviceManager()
        layout = QGridLayout()

        label_key = QLabel('<font size="4"> Device1 </font>')
        layout.addWidget(label_key, 0, 0)

        label_key = QLabel('<font size="4"> Device2 </font>')
        layout.addWidget(label_key, 1, 0)

        ch_bx1 = MySwitch()
        ch_bx1.setChecked(True)
        ch_bx1.clicked.connect(self.changeStateOne)
        layout.addWidget(ch_bx1, 0, 1, 1, 2)

        ch_bx3 = MySwitch()
        ch_bx3.setChecked(True)
        ch_bx3.clicked.connect(self.changeStateTwo)
        layout.addWidget(ch_bx3, 1, 1, 1, 2)

        self.setLayout(layout)
Пример #4
0
def main(port=DEFAULT_PORT_NUMBER):
	''' Performs the main operations of the server program on a given port.
	'''
	try:
		# Create a global thread manager for all our devices
		thread_mgr = ThreadManager()
		# Create a global state manager for handling device queues
		state_mgr = StateManager()
		# Initialise the device manager
		dev_mgr = DeviceManager(thread_mgr, state_mgr)

		def handler(*args):
			''' Initialise our custom handler with the device manager.
			'''
			RequestHandler(dev_mgr, *args)

		# Create a web server and define the handler to manage the incoming 
		# requests on separate threads.
		server = ThreadedHTTPServer(('', port), handler)
		print "Started ThreadedHTTPServer on port %d" % port

		# Wait forever for incoming HTTP requests
		server.serve_forever()

	except KeyboardInterrupt:
		print "Shutting down HTTPServer."
		server.socket.close()
Пример #5
0
 def __init__(self, showApp=False):
     QtCore.QObject.__init__(self)
     self.showApp = showApp
     self.player = None
     self.deviceMan = DeviceManager(startWatcher=True)
     self.updatePlayer()
     self.deviceMan.setActiveDeviceCapabilities([devices.Capability.ProvideContent, devices.Capability.PlayMusic])
     self.devicePresenceBroadcaster = DevicePresenceBroadcaster(self.deviceMan.getActiveDevice())
Пример #6
0
 def test_deviceman_default_watcher(self):
     self.deviceManWithBc = DeviceManager(startWatcher=True)
     assert self.deviceManWithBc.isWatching() == True
     
     self.remoteDevice = Device(type="remote", visibleName="remoteDevice", url="localhost:5021", lastSeen=time.localtime())
     presenceBroadcaster = DevicePresenceBroadcaster(self.remoteDevice, delayBetweenBroadcastsInSec=1)
     presenceBroadcaster.start()
     assert presenceBroadcaster.isRunning()
     time.sleep(1)
     presenceBroadcaster.stop()
     assert presenceBroadcaster.isRunning() == False
     self.deviceManWithBc.dispose()
     assert self.deviceManWithBc.isWatching() == False
Пример #7
0
    def test_deviceman_and_watcher_integration(self):
        self.watcher = DeviceWatcher(portToWatch=5555, callback=self.assert_watcher_receive_correct_data)
        self.deviceManWithBc = DeviceManager(startWatcher=True, watcher=self.watcher)

        assert self.deviceManWithBc.isWatching() == True
        
        self.remoteDevice = Device(type="remote", visibleName="remoteDevice", url="localhost:5021", lastSeen=time.localtime())
        presenceBroadcaster = DevicePresenceBroadcaster(self.remoteDevice, delayBetweenBroadcastsInSec=1)
        self.receivedBroadcast == False
        presenceBroadcaster.start()
        assert presenceBroadcaster.isRunning()
        time.sleep(1)
        assert self.receivedBroadcast == True
        presenceBroadcaster.stop()
        assert presenceBroadcaster.isRunning() == False
        self.deviceManWithBc.dispose()
        assert self.watcher.isRunning() == False
Пример #8
0
	def __init__(self):
		self.templates = jinja2.Environment(loader=jinja2.FileSystemLoader('templates'), trim_blocks=True, autoescape=True)
		self.templates.filters['get_device_icon'] = self.get_device_icon
		self.device_list = DeviceManager()
		self.unlocked_ports = {}
		self.device_list.register('added', router.add_device)
Пример #9
0
class UpnpResource(Resource):
	isLeaf = True
	def __init__(self):
		self.templates = jinja2.Environment(loader=jinja2.FileSystemLoader('templates'), trim_blocks=True, autoescape=True)
		self.templates.filters['get_device_icon'] = self.get_device_icon
		self.device_list = DeviceManager()
		self.unlocked_ports = {}
		self.device_list.register('added', router.add_device)

	@ensure_utf8
	def render(self, request):
		try:
			if request.path.startswith('/devices/'):
				return self.devices(request)
		except:
			traceback.print_exc()
			raise

	def _get_device_for_uri(self, uri):
		""" Takes a request uri and returns a device that it corresponds to """
		rest = uri[len('/devices/'):]
		slash_idx = rest.find('/')
		dev_id = urllib.unquote(rest[:slash_idx])
		if dev_id in self.unlocked_ports:
			dev_id = dev_id[:dev_id.rfind(':')]
		device = self.device_list._get_device_by_id(dev_id)
		return device

	def devices(self, request):
		if request.uri == '/devices/':
			return self.format_device_list(request)
		rest = request.uri[len('/devices/'):]
		slash_idx = rest.find('/')
		device = self._get_device_for_uri(request.uri)
		dev_id = urllib.unquote(rest[:slash_idx])
		if device and self.is_device_whitelisted(device):
			dev_url = device.get_location()
			if dev_id in self.unlocked_ports:
				dev_port = dev_id[dev_id.rfind(':')+1:]
				urlparsed = urlparse.urlparse(device.get_location())
				proto, netloc = urlparsed[0:2]
				url_ip = netloc.split(':')[0]
				dev_url = '%s://%s:%s/'%(proto, url_ip, dev_port)
			url = urlparse.urljoin(dev_url, rest[slash_idx:])
			logger.debug(url)
			return router.dispatch_device_request(request, url)
		else:
			logger.info("Could not find device %s"%(dev_id,))
			request.setResponseCode(404)
			return 'Could not find device %s'%(dev_id,)

	def is_device_whitelisted(self, device):
		return any(['X_MS_MediaReceiver' in s.service_type or
		            'ContentDirectory' in s.service_type
		            for s in device.get_services()
		          ])

	def format_device_list(self, request):
		def whitelisted_devices(devices):
			return [
			    d for d in devices if self.is_device_whitelisted(d)
			]
		if 'json' not in request.requestHeaders.getRawHeaders('Accept', [''])[0]:
			template = self.templates.get_template('devices.djhtml')
			return template.render(devices=whitelisted_devices(self.device_list.devices))
		else:
			devices = [{
				"uuid": d.get_id(),
				"usn": d.get_usn(),
				"st": d.get_st(),
				"server": d.server,
				"location": self.get_proxied_url(d, urlparse.urlparse(d.get_location())[2]),
				"subdevices": [{
					"usn": s.get_id()+"::"+s.service_type,
					"st": s.service_type,
					"location": self.get_proxied_url(d, urlparse.urlparse(d.get_location())[2])
					} for s in d.get_services()]
				} for d in whitelisted_devices(self.device_list.devices)]
			request.responseHeaders.setRawHeaders('Content-Type', ['application/json'])
			return json.dumps({"devices":devices})

	def get_proxied_url(self, device, url):
		# given a url on the device's upnp service
		# return a url relative to /devices/ to proxy to it
		# base is devices/
		if '://' in url:
			proto, netloc = urlparse.urlparse(device.get_location())[0:2]
			if ':' in netloc:
				dev_ip, dev_port = netloc.split(':', 1)
			else:
				dev_ip, dev_port = netloc, '443' if proto=='https' else '80'
			urlparsed = urlparse.urlparse(url)
			proto, netloc = urlparsed[0:2]
			if ':' in netloc:
				url_ip, url_port = netloc.split(':', 1)
			else:
				url_ip, url_port = netloc, '443' if proto=='https' else '80'
			prefix = '%s://%s' % (urlparsed[0:2])
			rest = url[len(prefix):]
			logger.debug("Comparing %s:%s to %s:%s"%(dev_ip, dev_port, url_ip, url_port))
			if url_ip == dev_ip and url_port == dev_port:
				result = device.get_id() + rest
				logger.debug('Converting same-device %s to %s'%(url, result))
				return result
			elif url_ip == dev_ip:
				unlocked_port = device.get_id() + ':' + url_port
				self.unlocked_ports[unlocked_port] = True
				result = unlocked_port + rest
				logger.debug('Converting same-device alt port %s to %s'%(url, result))
				return result
			else:
				logger.debug('Not converting external %s'%(url,))
				return url
		if len(url)>1 and url[0] != '/':
			url = '/' + url
		result = device.get_id() + url
		logger.debug('Converting upnp relative %s to %s'%(url, result))
		return result

	def rewrite_base(self, device, base):
		if urlparse.urljoin(device.get_location(), 'sub') == urlparse.urljoin(base, 'sub'):
			# unnecessary base
			return None
		return self.get_proxied_url(device, base)

	def get_device_icon(self, device):
		if len(device.icons) > 0:
			icon = sorted(device.icons, key=lambda i:abs(120-int(i['width'])))[0]
			icon_url = self.get_proxied_url(device, icon['realurl'])
			return icon_url
		else:
			return ''

	def hack_description_response(self, request, response_data):
		request.setResponseCode(response_data['code'])
		request.responseHeaders = response_data['headers']
		if 'xml' not in response_data['headers'].getRawHeaders('Content-Type', [''])[0]:
			request.responseHeaders.setRawHeaders('Content-Length', [len(response_data['content'])])
			request.write(response_data['content'])
			request.finish()
			return
		request.responseHeaders.removeHeader('Content-Length')
		request.responseHeaders.removeHeader('Content-Encoding')
		# get the device that we're talking to, and its ip
		device = self._get_device_for_uri(request.uri)
		# load up the response
		upnp = 'urn:schemas-upnp-org:device-1-0'
		root = ElementTree.fromstring(response_data['content'])
		for urlbase in root.findall("./{%s}URLBase"%(upnp,)):
			newbase = self.rewrite_base(device, urlbase.text)
			if newbase:
				urlbase.text = newbase
			else:
				root.remove(newbase)
		# write out
		doc = ElementTree.ElementTree(root)
		docout = StringIO.StringIO()
		doc.write(docout, encoding='utf-8', xml_declaration=True)
		docoutstr = docout.getvalue()
		request.responseHeaders.setRawHeaders('Content-Length', [len(docoutstr)])
		request.write(docoutstr)
		request.finish()

	def hack_mediaserver_response(self, request, response_data):
		request.setResponseCode(response_data['code'])
		request.responseHeaders = response_data['headers']
		if 'xml' not in response_data['headers'].getRawHeaders('Content-Type', [''])[0]:
			request.responseHeaders.setRawHeaders('Content-Length', [len(response_data['content'])])
			request.write(response_data['content'])
			request.finish()
			return
		request.responseHeaders.removeHeader('Content-Length')
		request.responseHeaders.removeHeader('Content-Encoding')
		# get the device that we're talking to, and its ip
		device = self._get_device_for_uri(request.uri)
		# load up response
		didl = 'urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/'
		upnp = 'urn:schemas-upnp-org:metadata-1-0/upnp/'
		root = ElementTree.fromstring(response_data['content'])
		for result in root.iter('Result'):
			resultdoc = ElementTree.fromstring(result.text.encode('utf-8'))
			for uritag in resultdoc.iter('{%s}albumArtURI'%(upnp,)):
				uritag.text = self.get_proxied_url(device, uritag.text).decode('utf-8')
			for uritag in resultdoc.iter('{%s}res'%(didl,)):
				uritag.text = self.get_proxied_url(device, uritag.text).decode('utf-8')
			result.text = ElementTree.tostring(resultdoc, encoding='utf-8').decode('utf-8')
		# write out
		doc = ElementTree.ElementTree(root)
		docout = StringIO.StringIO()
		doc.write(docout, encoding='utf-8', xml_declaration=True)
		docoutstr = docout.getvalue()
		request.responseHeaders.setRawHeaders('Content-Length', [len(docoutstr)])
		request.write(docoutstr)
		request.finish()
Пример #10
0
 def test_device_watcher_can_start_and_stop(self):
     self.deviceManWithBc = DeviceManager(startWatcher=True)
     assert self.deviceManWithBc.isWatching() == True
     self.deviceManWithBc.dispose()
     assert self.deviceManWithBc.isWatching() == False
Пример #11
0
class TestDeviceMan:

    config.setConfigFolder('tests/config/')
    deviceMan = DeviceManager()
    deviceMan.deleteRegistry()
    receivedBroadcast = False
    device = Device(type="remote", visibleName="testDevice", url="testLocation", lastSeen=time.localtime())

    def test_registry_not_found(self):
        self.deviceMan.deleteRegistry()
        assert self.deviceMan.createRegistry() == True
        assert self.deviceMan.getDevices() == []
        assert self.deviceMan.deleteRegistry()

    def test_delete_registry(self):
        self.deviceMan.deleteRegistry()
        assert self.deviceMan.createRegistry()
        assert os.path.isfile(self.deviceMan.devicesRegistryPath)
        self.deviceMan.deleteRegistry()
        assert len(self.deviceMan.getDevices()) == 0
        
    def test_add_entry_to_registry(self):
        self.deviceMan.deleteRegistry()
        self.deviceMan.registerDevice(self.device)
        assert self.device in self.deviceMan.getDevices()
        assert len(self.deviceMan.getDevices()) == 1
        savedDevice = self.deviceMan.getDevices()[0]
        assert savedDevice.type == self.device.type
        assert savedDevice.visibleName == self.device.visibleName
        assert savedDevice.url == self.device.url
        #assert savedDevice.lastSeen == self.device.lastSeen

    def test_device_watcher_can_start_and_stop(self):
        self.deviceManWithBc = DeviceManager(startWatcher=True)
        assert self.deviceManWithBc.isWatching() == True
        self.deviceManWithBc.dispose()
        assert self.deviceManWithBc.isWatching() == False

    def test_device_watcher_can_receive(self):
        self.watcher = DeviceWatcher(portToWatch=5555, callback=self.assert_watcher_receive_correct_data)
        self.watcher.start()
        assert self.watcher.isRunning() == True
        
        self.remoteDevice = Device(type="remote", visibleName="remoteDevice", url="localhost:5021", lastSeen=time.localtime())
        presenceBroadcaster = DevicePresenceBroadcaster(self.remoteDevice, delayBetweenBroadcastsInSec=1)
        self.receivedBroadcast == False
        presenceBroadcaster.start()
        assert presenceBroadcaster.isRunning()
        time.sleep(1)
        assert self.receivedBroadcast == True
        presenceBroadcaster.stop()
        assert presenceBroadcaster.isRunning() == False
        self.watcher.stop()
        assert self.watcher.isRunning() == False

    def assert_watcher_receive_correct_data(self, device):
        assert device == self.remoteDevice
        self.receivedBroadcast = True

    def test_deviceman_and_watcher_integration(self):
        self.watcher = DeviceWatcher(portToWatch=5555, callback=self.assert_watcher_receive_correct_data)
        self.deviceManWithBc = DeviceManager(startWatcher=True, watcher=self.watcher)

        assert self.deviceManWithBc.isWatching() == True
        
        self.remoteDevice = Device(type="remote", visibleName="remoteDevice", url="localhost:5021", lastSeen=time.localtime())
        presenceBroadcaster = DevicePresenceBroadcaster(self.remoteDevice, delayBetweenBroadcastsInSec=1)
        self.receivedBroadcast == False
        presenceBroadcaster.start()
        assert presenceBroadcaster.isRunning()
        time.sleep(1)
        assert self.receivedBroadcast == True
        presenceBroadcaster.stop()
        assert presenceBroadcaster.isRunning() == False
        self.deviceManWithBc.dispose()
        assert self.watcher.isRunning() == False

    def test_deviceman_default_watcher(self):
        self.deviceManWithBc = DeviceManager(startWatcher=True)
        assert self.deviceManWithBc.isWatching() == True
        
        self.remoteDevice = Device(type="remote", visibleName="remoteDevice", url="localhost:5021", lastSeen=time.localtime())
        presenceBroadcaster = DevicePresenceBroadcaster(self.remoteDevice, delayBetweenBroadcastsInSec=1)
        presenceBroadcaster.start()
        assert presenceBroadcaster.isRunning()
        time.sleep(1)
        presenceBroadcaster.stop()
        assert presenceBroadcaster.isRunning() == False
        self.deviceManWithBc.dispose()
        assert self.deviceManWithBc.isWatching() == False

    def test_set_active_device(self):
        self.deviceMan.setActiveDevice(self.device)
        assert self.deviceMan.getActiveDevice() == self.device

    def test_clear_registry(self):
        pass

    def test_watcher_does_not_leak(self):
        try:
            self.watcher = DeviceWatcher(portToWatch=5555, callback=self.assert_watcher_receive_correct_data)
            self.watcher.start()
            assert self.watcher.isRunning() == True
            self.watcher.stop()
            procName = self.watcher.getProcName()

            isReallyRunning = False
            for proc in psutil.process_iter():
                if proc.name == self.watcher.getProcName():
                    assert proc.status == psutil.STATUS_RUNNING
                    isReallyRunning == True
            assert isReallyRunning
            self.watcher.stop()
            assert self.watcher.isRunning() == False
            
            isReallyClosed = True
            for proc in psutil.process_iter():
                if proc.name == procName:
                    isReallyClosed = False
            assert isReallyClosed

        except Exception as e:
            print e
            #May not work on all platform
            #TODO : Make it work on MAC
            self.watcher.stop()
            pass

    def test_concurrent_watchers(self):
        self.watcher1 = DeviceWatcher(portToWatch=5555, callback=self.assert_watcher_receive_correct_data)
        self.watcher1.start()
        assert self.watcher1.isRunning() == True

        self.watcher2 = DeviceWatcher(portToWatch=5555, callback=self.assert_watcher_receive_correct_data)
        self.watcher2.start()
        assert self.watcher2.isRunning() == True

        presenceBroadcaster = DevicePresenceBroadcaster(self.device, delayBetweenBroadcastsInSec=1)
        presenceBroadcaster.start()

        time.sleep(1)

        self.watcher1.stop()
        self.watcher2.stop()
        presenceBroadcaster.stop()
Пример #12
0
class UpnpResource(Resource):
    isLeaf = True

    def __init__(self):
        self.templates = jinja2.Environment(
            loader=jinja2.FileSystemLoader('templates'),
            trim_blocks=True,
            autoescape=True)
        self.templates.filters['get_device_icon'] = self.get_device_icon
        self.device_list = DeviceManager()
        self.unlocked_ports = {}
        self.device_list.register('added', router.add_device)

    @ensure_utf8
    def render(self, request):
        try:
            if request.path.startswith('/devices/'):
                return self.devices(request)
        except:
            traceback.print_exc()
            raise

    def _get_device_for_uri(self, uri):
        """ Takes a request uri and returns a device that it corresponds to """
        rest = uri[len('/devices/'):]
        slash_idx = rest.find('/')
        dev_id = urllib.unquote(rest[:slash_idx])
        if dev_id in self.unlocked_ports:
            dev_id = dev_id[:dev_id.rfind(':')]
        device = self.device_list._get_device_by_id(dev_id)
        return device

    def devices(self, request):
        if request.uri == '/devices/':
            return self.format_device_list(request)
        rest = request.uri[len('/devices/'):]
        slash_idx = rest.find('/')
        device = self._get_device_for_uri(request.uri)
        dev_id = urllib.unquote(rest[:slash_idx])
        if device and self.is_device_whitelisted(device):
            dev_url = device.get_location()
            if dev_id in self.unlocked_ports:
                dev_port = dev_id[dev_id.rfind(':') + 1:]
                urlparsed = urlparse.urlparse(device.get_location())
                proto, netloc = urlparsed[0:2]
                url_ip = netloc.split(':')[0]
                dev_url = '%s://%s:%s/' % (proto, url_ip, dev_port)
            url = urlparse.urljoin(dev_url, rest[slash_idx:])
            logger.debug(url)
            return router.dispatch_device_request(request, url)
        else:
            logger.info("Could not find device %s" % (dev_id, ))
            request.setResponseCode(404)
            return 'Could not find device %s' % (dev_id, )

    def is_device_whitelisted(self, device):
        return any([
            'X_MS_MediaReceiver' in s.service_type
            or 'ContentDirectory' in s.service_type
            for s in device.get_services()
        ])

    def format_device_list(self, request):
        def whitelisted_devices(devices):
            return [d for d in devices if self.is_device_whitelisted(d)]

        if 'json' not in request.requestHeaders.getRawHeaders('Accept',
                                                              [''])[0]:
            template = self.templates.get_template('devices.djhtml')
            return template.render(
                devices=whitelisted_devices(self.device_list.devices))
        else:
            devices = [{
                "uuid":
                d.get_id(),
                "usn":
                d.get_usn(),
                "st":
                d.get_st(),
                "server":
                d.server,
                "location":
                self.get_proxied_url(d,
                                     urlparse.urlparse(d.get_location())[2]),
                "subdevices": [{
                    "usn":
                    s.get_id() + "::" + s.service_type,
                    "st":
                    s.service_type,
                    "location":
                    self.get_proxied_url(
                        d,
                        urlparse.urlparse(d.get_location())[2])
                } for s in d.get_services()]
            } for d in whitelisted_devices(self.device_list.devices)]
            request.responseHeaders.setRawHeaders('Content-Type',
                                                  ['application/json'])
            return json.dumps({"devices": devices})

    def get_proxied_url(self, device, url):
        # given a url on the device's upnp service
        # return a url relative to /devices/ to proxy to it
        # base is devices/
        if '://' in url:
            proto, netloc = urlparse.urlparse(device.get_location())[0:2]
            if ':' in netloc:
                dev_ip, dev_port = netloc.split(':', 1)
            else:
                dev_ip, dev_port = netloc, '443' if proto == 'https' else '80'
            urlparsed = urlparse.urlparse(url)
            proto, netloc = urlparsed[0:2]
            if ':' in netloc:
                url_ip, url_port = netloc.split(':', 1)
            else:
                url_ip, url_port = netloc, '443' if proto == 'https' else '80'
            prefix = '%s://%s' % (urlparsed[0:2])
            rest = url[len(prefix):]
            logger.debug("Comparing %s:%s to %s:%s" %
                         (dev_ip, dev_port, url_ip, url_port))
            if url_ip == dev_ip and url_port == dev_port:
                result = device.get_id() + rest
                logger.debug('Converting same-device %s to %s' % (url, result))
                return result
            elif url_ip == dev_ip:
                unlocked_port = device.get_id() + ':' + url_port
                self.unlocked_ports[unlocked_port] = True
                result = unlocked_port + rest
                logger.debug('Converting same-device alt port %s to %s' %
                             (url, result))
                return result
            else:
                logger.debug('Not converting external %s' % (url, ))
                return url
        if len(url) > 1 and url[0] != '/':
            url = '/' + url
        result = device.get_id() + url
        logger.debug('Converting upnp relative %s to %s' % (url, result))
        return result

    def rewrite_base(self, device, base):
        if urlparse.urljoin(device.get_location(),
                            'sub') == urlparse.urljoin(base, 'sub'):
            # unnecessary base
            return None
        return self.get_proxied_url(device, base)

    def get_device_icon(self, device):
        if len(device.icons) > 0:
            icon = sorted(device.icons,
                          key=lambda i: abs(120 - int(i['width'])))[0]
            icon_url = self.get_proxied_url(device, icon['realurl'])
            return icon_url
        else:
            return ''

    def hack_description_response(self, request, response_data):
        request.setResponseCode(response_data['code'])
        request.responseHeaders = response_data['headers']
        if 'xml' not in response_data['headers'].getRawHeaders(
                'Content-Type', [''])[0]:
            request.responseHeaders.setRawHeaders(
                'Content-Length', [len(response_data['content'])])
            request.write(response_data['content'])
            request.finish()
            return
        request.responseHeaders.removeHeader('Content-Length')
        request.responseHeaders.removeHeader('Content-Encoding')
        # get the device that we're talking to, and its ip
        device = self._get_device_for_uri(request.uri)
        # load up the response
        upnp = 'urn:schemas-upnp-org:device-1-0'
        root = ElementTree.fromstring(response_data['content'])
        for urlbase in root.findall("./{%s}URLBase" % (upnp, )):
            newbase = self.rewrite_base(device, urlbase.text)
            if newbase:
                urlbase.text = newbase
            else:
                root.remove(newbase)
        # write out
        doc = ElementTree.ElementTree(root)
        docout = StringIO.StringIO()
        doc.write(docout, encoding='utf-8', xml_declaration=True)
        docoutstr = docout.getvalue()
        request.responseHeaders.setRawHeaders('Content-Length',
                                              [len(docoutstr)])
        request.write(docoutstr)
        request.finish()

    def hack_mediaserver_response(self, request, response_data):
        request.setResponseCode(response_data['code'])
        request.responseHeaders = response_data['headers']
        if 'xml' not in response_data['headers'].getRawHeaders(
                'Content-Type', [''])[0]:
            request.responseHeaders.setRawHeaders(
                'Content-Length', [len(response_data['content'])])
            request.write(response_data['content'])
            request.finish()
            return
        request.responseHeaders.removeHeader('Content-Length')
        request.responseHeaders.removeHeader('Content-Encoding')
        # get the device that we're talking to, and its ip
        device = self._get_device_for_uri(request.uri)
        # load up response
        didl = 'urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/'
        upnp = 'urn:schemas-upnp-org:metadata-1-0/upnp/'
        root = ElementTree.fromstring(response_data['content'])
        for result in root.iter('Result'):
            resultdoc = ElementTree.fromstring(result.text.encode('utf-8'))
            for uritag in resultdoc.iter('{%s}albumArtURI' % (upnp, )):
                uritag.text = self.get_proxied_url(device,
                                                   uritag.text).decode('utf-8')
            for uritag in resultdoc.iter('{%s}res' % (didl, )):
                uritag.text = self.get_proxied_url(device,
                                                   uritag.text).decode('utf-8')
            result.text = ElementTree.tostring(
                resultdoc, encoding='utf-8').decode('utf-8')
        # write out
        doc = ElementTree.ElementTree(root)
        docout = StringIO.StringIO()
        doc.write(docout, encoding='utf-8', xml_declaration=True)
        docoutstr = docout.getvalue()
        request.responseHeaders.setRawHeaders('Content-Length',
                                              [len(docoutstr)])
        request.write(docoutstr)
        request.finish()
Пример #13
0
    def __init__(self, *args, **kwargs):
        """
        Constructs a QuarterWidget.
        QuarterWidget(QWidget parent = None, QGLWidget sharewidget = None, Qt.WindowFlags f = 0, scxml = "coin:scxml/navigation/examiner.xml")
        QuarterWidget(QGLContext context, QWidget parent = None, QGLWidget sharewidget = None, Qt.WindowFlags f = 0, scxml = "coin:scxml/navigation/examiner.xml")
        QuarterWidget(QGLFormat format, QWidget parent = None, QGLWidget sharewidget = None, Qt.WindowFlags f = 0, scxml = "coin:scxml/navigation/examiner.xml")
        """

        params = ["parent", "sharewidget"]
        values = {"parent": None, "sharewidget": None, "f": 0, "scxml": "coin:scxml/navigation/examiner.xml"}
        values.update(kwargs)
        
        if len(args) > 0 and isinstance(args[0], QtOpenGL.QGLContext) or "context" in kwargs:
            params.insert(0, "context")
        elif len(args) > 0 and isinstance(args[0], QtOpenGL.QGLFormat) or "format" in kwargs:
            params.insert(0, "format")

        if len(args) > len(params):
            values["f"] = args[len(params)]

        if len(args) > len(params) + 1:
            values["scxml"] = args[len(params) + 1]

        for i in range(len(args), len(params)):
            args += (values[params[i]],)

        QtOpenGL.QGLWidget.__init__(self, *args[:len(params)])
        if values["f"]: self.setWindowFlags(values["f"])

        # initialize Sensormanager and ImageReader instances only once
        if not QuarterWidget._sensormanager:
            QuarterWidget._sensormanager = SensorManager()

        if not QuarterWidget._imagereader:
            QuarterWidget._imagereader = ImageReader()

        self.cachecontext_list = []
        self.cachecontext = self.findCacheContext(self, values["sharewidget"])
        self.statecursormap = {}

        self.scene = None
        self.contextmenu = None
        self.contextmenuenabled = True

        self.sorendermanager = coin.SoRenderManager()
        self.soeventmanager = coin.SoEventManager()

        # Mind the order of initialization as the XML state machine uses
        # callbacks which depends on other state being initialized
        self.eventmanager = EventManager(self)
        self.devicemanager = DeviceManager(self)

        statemachine = coin.ScXML.readFile(values["scxml"])
        if statemachine and statemachine.isOfType(coin.SoScXMLStateMachine.getClassTypeId()):
            sostatemachine = coin.cast(statemachine, "SoScXMLStateMachine")
            statemachine.addStateChangeCallback(statechangeCB, self)
            self.soeventmanager.addSoScXMLStateMachine(sostatemachine)
            sostatemachine.initialize()
        else:
            raise "could not initialize statemachine, given file not found?"

        self.headlight = coin.SoDirectionalLight()

        self.sorendermanager.setAutoClipping(coin.SoRenderManager.VARIABLE_NEAR_PLANE)
        self.sorendermanager.setRenderCallback(renderCB, self)
        self.sorendermanager.setBackgroundColor(coin.SbColor4f(0, 0, 0, 0))
        self.sorendermanager.activate()
        self.sorendermanager.addPreRenderCallback(prerenderCB, self)
        self.sorendermanager.addPostRenderCallback(postrenderCB, self)

        self.soeventmanager.setNavigationState(coin.SoEventManager.MIXED_NAVIGATION)

        self.devicemanager.registerDevice(MouseHandler())
        self.devicemanager.registerDevice(KeyboardHandler())
        self.eventmanager.registerEventHandler(DragDropHandler())

        # set up a cache context for the default SoGLRenderAction
        self.sorendermanager.getGLRenderAction().setCacheContext(self.getCacheContextId())

        self.setStateCursor("interact", QtCore.Qt.ArrowCursor)
        self.setStateCursor("idle", QtCore.Qt.OpenHandCursor)
        self.setStateCursor("rotate", QtCore.Qt.ClosedHandCursor)
        self.setStateCursor("pan", QtCore.Qt.SizeAllCursor)
        self.setStateCursor("zoom", QtCore.Qt.SizeVerCursor)
        self.setStateCursor("seek", QtCore.Qt.CrossCursor)
        self.setStateCursor("spin", QtCore.Qt.OpenHandCursor)

        self.setMouseTracking(True)
        self.setFocusPolicy(QtCore.Qt.StrongFocus);
Пример #14
0
class QuarterWidget(QtOpenGL.QGLWidget):

    _sensormanager = None
    _imagereader = None

    def __init__(self, *args, **kwargs):
        """
        Constructs a QuarterWidget.
        QuarterWidget(QWidget parent = None, QGLWidget sharewidget = None, Qt.WindowFlags f = 0, scxml = "coin:scxml/navigation/examiner.xml")
        QuarterWidget(QGLContext context, QWidget parent = None, QGLWidget sharewidget = None, Qt.WindowFlags f = 0, scxml = "coin:scxml/navigation/examiner.xml")
        QuarterWidget(QGLFormat format, QWidget parent = None, QGLWidget sharewidget = None, Qt.WindowFlags f = 0, scxml = "coin:scxml/navigation/examiner.xml")
        """

        params = ["parent", "sharewidget"]
        values = {"parent": None, "sharewidget": None, "f": 0, "scxml": "coin:scxml/navigation/examiner.xml"}
        values.update(kwargs)
        
        if len(args) > 0 and isinstance(args[0], QtOpenGL.QGLContext) or "context" in kwargs:
            params.insert(0, "context")
        elif len(args) > 0 and isinstance(args[0], QtOpenGL.QGLFormat) or "format" in kwargs:
            params.insert(0, "format")

        if len(args) > len(params):
            values["f"] = args[len(params)]

        if len(args) > len(params) + 1:
            values["scxml"] = args[len(params) + 1]

        for i in range(len(args), len(params)):
            args += (values[params[i]],)

        QtOpenGL.QGLWidget.__init__(self, *args[:len(params)])
        if values["f"]: self.setWindowFlags(values["f"])

        # initialize Sensormanager and ImageReader instances only once
        if not QuarterWidget._sensormanager:
            QuarterWidget._sensormanager = SensorManager()

        if not QuarterWidget._imagereader:
            QuarterWidget._imagereader = ImageReader()

        self.cachecontext_list = []
        self.cachecontext = self.findCacheContext(self, values["sharewidget"])
        self.statecursormap = {}

        self.scene = None
        self.contextmenu = None
        self.contextmenuenabled = True

        self.sorendermanager = coin.SoRenderManager()
        self.soeventmanager = coin.SoEventManager()

        # Mind the order of initialization as the XML state machine uses
        # callbacks which depends on other state being initialized
        self.eventmanager = EventManager(self)
        self.devicemanager = DeviceManager(self)

        statemachine = coin.ScXML.readFile(values["scxml"])
        if statemachine and statemachine.isOfType(coin.SoScXMLStateMachine.getClassTypeId()):
            sostatemachine = coin.cast(statemachine, "SoScXMLStateMachine")
            statemachine.addStateChangeCallback(statechangeCB, self)
            self.soeventmanager.addSoScXMLStateMachine(sostatemachine)
            sostatemachine.initialize()
        else:
            raise "could not initialize statemachine, given file not found?"

        self.headlight = coin.SoDirectionalLight()

        self.sorendermanager.setAutoClipping(coin.SoRenderManager.VARIABLE_NEAR_PLANE)
        self.sorendermanager.setRenderCallback(renderCB, self)
        self.sorendermanager.setBackgroundColor(coin.SbColor4f(0, 0, 0, 0))
        self.sorendermanager.activate()
        self.sorendermanager.addPreRenderCallback(prerenderCB, self)
        self.sorendermanager.addPostRenderCallback(postrenderCB, self)

        self.soeventmanager.setNavigationState(coin.SoEventManager.MIXED_NAVIGATION)

        self.devicemanager.registerDevice(MouseHandler())
        self.devicemanager.registerDevice(KeyboardHandler())
        self.eventmanager.registerEventHandler(DragDropHandler())

        # set up a cache context for the default SoGLRenderAction
        self.sorendermanager.getGLRenderAction().setCacheContext(self.getCacheContextId())

        self.setStateCursor("interact", QtCore.Qt.ArrowCursor)
        self.setStateCursor("idle", QtCore.Qt.OpenHandCursor)
        self.setStateCursor("rotate", QtCore.Qt.ClosedHandCursor)
        self.setStateCursor("pan", QtCore.Qt.SizeAllCursor)
        self.setStateCursor("zoom", QtCore.Qt.SizeVerCursor)
        self.setStateCursor("seek", QtCore.Qt.CrossCursor)
        self.setStateCursor("spin", QtCore.Qt.OpenHandCursor)

        self.setMouseTracking(True)
        self.setFocusPolicy(QtCore.Qt.StrongFocus);

    def setSceneGraph(self, node):
        if node and self.scene==node:
            return

        camera = None
        superscene = None
        viewall = False

        if node:
            self.scene = node
            self.scene.ref()

            superscene = coin.SoSeparator()
            superscene.addChild(coin.SoDepthBuffer())
            superscene.addChild(self.headlight)

            camera = self.searchForCamera(node)
            if not camera:
                camera = coin.SoPerspectiveCamera()
                superscene.addChild(camera)
                viewall = True

            superscene.addChild(node)

        self.soeventmanager.setSceneGraph(superscene)
        self.sorendermanager.setSceneGraph(superscene)
        self.soeventmanager.setCamera(camera)
        self.sorendermanager.setCamera(camera)

        if viewall:
            self.viewAll()

        if superscene:
            superscene.touch()

    def viewAll(self):
        """ Reposition the current camera to display the entire scene"""
        viewallevent = coin.SbName("sim.coin3d.coin.navigation.ViewAll")
        for c in range(self.soeventmanager.getNumSoScXMLStateMachines()):
            sostatemachine = self.soeventmanager.getSoScXMLStateMachine(c)
            if (sostatemachine.isActive()):
                sostatemachine.queueEvent(viewallevent)
                sostatemachine.processEventQueue()

    def resizeGL(self, width, height):
        vp = coin.SbViewportRegion(width, height)
        self.sorendermanager.setViewportRegion(vp)
        self.soeventmanager.setViewportRegion(vp)

    def paintGL(self):
        self.actualRedraw()

    def actualRedraw(self):
        self.sorendermanager.render(True, True)

    def event(self, qevent):
        """Translates Qt Events into Coin events and passes them on to the
          scenemanager for processing. If the event can not be translated or
          processed, it is forwarded to Qt and the method returns false. This
          method could be overridden in a subclass in order to catch events of
          particular interest to the application programmer."""

        if self.eventmanager.handleEvent(qevent):
            return True

        soevent = self.devicemanager.translateEvent(qevent)
        if (soevent and self.soeventmanager.processEvent(soevent)):
            return True

        # NOTE jkg: we must return True or False
        return QtOpenGL.QGLWidget.event(self, qevent)

    def setStateCursor(self, state, cursor):
        self.statecursormap[state] = cursor

    def searchForCamera(self, root):
        sa = coin.SoSearchAction()
        sa.setInterest(coin.SoSearchAction.FIRST)
        sa.setType(coin.SoCamera.getClassTypeId())
        sa.apply(root)

        if sa.getPath():
            node = sa.getPath().getTail()
            if node and node.isOfType(coin.SoCamera.getClassTypeId()):
                return node
        return None

    def getCacheContextId(self):
        return self.cachecontext.id

    def findCacheContext(self, widget, sharewidget):

        class QuarterWidgetP_cachecontext:
            def __init__(self):
                self.widgetlist = []
                self.id = None

        for cachecontext in self.cachecontext_list:
            for widget in cachecontext.widgetlist:
                if (widget == sharewidget):
                    cachecontext.widgetlist.append(widget)
                    return cachecontext;
        cachecontext = QuarterWidgetP_cachecontext()
        cachecontext.id = coin.SoGLCacheContextElement.getUniqueCacheContext()
        cachecontext.widgetlist.append(widget)
        self.cachecontext_list.append(cachecontext)

        return cachecontext

    def getSoRenderManager(self):
        return self.sorendermanager

    def getSoEventManager(self):
        return self.soeventmanager

    def setBackgroundColor(self, color):
        """Set backgroundcolor to a given QColor
          Remember that QColors are given in integers between 0 and 255, as
          opposed to SbColor4f which is in [0 ,1]. The default alpha value for
          a QColor is 255, but you'll probably want to set it to zero before
          using it as an OpenGL clear color."""
        bgcolor = coin.SbColor4f(max(0, min(1, color.red() / 255.0)),
                                 max(0, min(1, color.green() / 255.0)),
                                 max(0, min(1, color.blue() / 255.0)),
                                 max(0, min(1, color.alpha() / 255.0)))
        self.sorendermanager.setBackgroundColor(bgcolor)

    def getBackgroundColor(self):
        """  Returns color used for clearing the rendering area before
          rendering the scene."""

        bg = self.sorendermanager.getBackgroundColor()

        return QtGui.QColor(max(0, min(255, int(bg[0] * 255.0))),
                            max(0, min(255, int(bg[1] * 255.0))),
                            max(0, min(255, int(bg[2] * 255.0))),
                            max(0, min(255, int(bg[3] * 255.0))))

    def getContextMenu(self):
        """Returns the context menu used by the widget."""
        if not self.contextmenu:
            self.contextmenu = ContextMenu(self)
        # NOTE 20080508 jkg: seems like we can drop .getMenu() but I dont see why that works
        return self.contextmenu.getMenu()

    def contextMenuEnabled(self):
        return contextmenuenabled

    def enableContextMenu(self, yesno):
        self.contextmenuenabled = yesno

    def setTransparencyType(self, type):
        """This method sets the transparency type to be used for the scene."""
        assert(self.sorendermanager)
        self.sorendermanager.getGLRenderAction().setTransparencyType(type)
        self.sorendermanager.scheduleRedraw()

    def enableHeadlight(self, onoff):
        """  Enable/disable the headlight. This wille toggle the SoDirectionalLigh::on
          field (returned from getHeadlight())."""
        self.headlight.on = onoff

    def getHeadlight(self):
        """Returns the light used for the headlight."""
        return self.headlight
Пример #15
0
    def __init__(self, *args, **kwargs):
        """
        Constructs a QuarterWidget.
        QuarterWidget(QWidget parent = None, QGLWidget sharewidget = None, Qt.WindowFlags f = 0, scxml = "coin:scxml/navigation/examiner.xml")
        QuarterWidget(QGLContext context, QWidget parent = None, QGLWidget sharewidget = None, Qt.WindowFlags f = 0, scxml = "coin:scxml/navigation/examiner.xml")
        QuarterWidget(QGLFormat format, QWidget parent = None, QGLWidget sharewidget = None, Qt.WindowFlags f = 0, scxml = "coin:scxml/navigation/examiner.xml")
        """

        params = ["parent", "sharewidget"]
        values = {
            "parent": None,
            "sharewidget": None,
            "f": 0,
            "scxml": "coin:scxml/navigation/examiner.xml"
        }
        values.update(kwargs)

        if len(args) > 0 and isinstance(
                args[0], QtOpenGL.QGLContext) or "context" in kwargs:
            params.insert(0, "context")
        elif len(args) > 0 and isinstance(
                args[0], QtOpenGL.QGLFormat) or "format" in kwargs:
            params.insert(0, "format")

        if len(args) > len(params):
            values["f"] = args[len(params)]

        if len(args) > len(params) + 1:
            values["scxml"] = args[len(params) + 1]

        for i in range(len(args), len(params)):
            args += (values[params[i]], )

        QtOpenGL.QGLWidget.__init__(self, *args[:len(params)])
        if values["f"]: self.setWindowFlags(values["f"])

        # initialize Sensormanager and ImageReader instances only once
        if not QuarterWidget._sensormanager:
            QuarterWidget._sensormanager = SensorManager()

        if not QuarterWidget._imagereader:
            QuarterWidget._imagereader = ImageReader()

        self.cachecontext_list = []
        self.cachecontext = self.findCacheContext(self, values["sharewidget"])
        self.statecursormap = {}

        self.scene = None
        self.contextmenu = None
        self.contextmenuenabled = True

        self.sorendermanager = coin.SoRenderManager()
        self.soeventmanager = coin.SoEventManager()

        # Mind the order of initialization as the XML state machine uses
        # callbacks which depends on other state being initialized
        self.eventmanager = EventManager(self)
        self.devicemanager = DeviceManager(self)

        statemachine = coin.ScXML.readFile(values["scxml"])
        if statemachine and statemachine.isOfType(
                coin.SoScXMLStateMachine.getClassTypeId()):
            sostatemachine = coin.cast(statemachine, "SoScXMLStateMachine")
            statemachine.addStateChangeCallback(statechangeCB, self)
            self.soeventmanager.addSoScXMLStateMachine(sostatemachine)
            sostatemachine.initialize()
        else:
            raise "could not initialize statemachine, given file not found?"

        self.headlight = coin.SoDirectionalLight()

        self.sorendermanager.setAutoClipping(
            coin.SoRenderManager.VARIABLE_NEAR_PLANE)
        self.sorendermanager.setRenderCallback(renderCB, self)
        self.sorendermanager.setBackgroundColor(coin.SbColor4f(0, 0, 0, 0))
        self.sorendermanager.activate()
        self.sorendermanager.addPreRenderCallback(prerenderCB, self)
        self.sorendermanager.addPostRenderCallback(postrenderCB, self)

        self.soeventmanager.setNavigationState(
            coin.SoEventManager.MIXED_NAVIGATION)

        self.devicemanager.registerDevice(MouseHandler())
        self.devicemanager.registerDevice(KeyboardHandler())
        self.eventmanager.registerEventHandler(DragDropHandler())

        # set up a cache context for the default SoGLRenderAction
        self.sorendermanager.getGLRenderAction().setCacheContext(
            self.getCacheContextId())

        self.setStateCursor("interact", QtCore.Qt.ArrowCursor)
        self.setStateCursor("idle", QtCore.Qt.OpenHandCursor)
        self.setStateCursor("rotate", QtCore.Qt.ClosedHandCursor)
        self.setStateCursor("pan", QtCore.Qt.SizeAllCursor)
        self.setStateCursor("zoom", QtCore.Qt.SizeVerCursor)
        self.setStateCursor("seek", QtCore.Qt.CrossCursor)
        self.setStateCursor("spin", QtCore.Qt.OpenHandCursor)

        self.setMouseTracking(True)
        self.setFocusPolicy(QtCore.Qt.StrongFocus)
Пример #16
0
class QuarterWidget(QtOpenGL.QGLWidget):

    _sensormanager = None
    _imagereader = None

    def __init__(self, *args, **kwargs):
        """
        Constructs a QuarterWidget.
        QuarterWidget(QWidget parent = None, QGLWidget sharewidget = None, Qt.WindowFlags f = 0, scxml = "coin:scxml/navigation/examiner.xml")
        QuarterWidget(QGLContext context, QWidget parent = None, QGLWidget sharewidget = None, Qt.WindowFlags f = 0, scxml = "coin:scxml/navigation/examiner.xml")
        QuarterWidget(QGLFormat format, QWidget parent = None, QGLWidget sharewidget = None, Qt.WindowFlags f = 0, scxml = "coin:scxml/navigation/examiner.xml")
        """

        params = ["parent", "sharewidget"]
        values = {
            "parent": None,
            "sharewidget": None,
            "f": 0,
            "scxml": "coin:scxml/navigation/examiner.xml"
        }
        values.update(kwargs)

        if len(args) > 0 and isinstance(
                args[0], QtOpenGL.QGLContext) or "context" in kwargs:
            params.insert(0, "context")
        elif len(args) > 0 and isinstance(
                args[0], QtOpenGL.QGLFormat) or "format" in kwargs:
            params.insert(0, "format")

        if len(args) > len(params):
            values["f"] = args[len(params)]

        if len(args) > len(params) + 1:
            values["scxml"] = args[len(params) + 1]

        for i in range(len(args), len(params)):
            args += (values[params[i]], )

        QtOpenGL.QGLWidget.__init__(self, *args[:len(params)])
        if values["f"]: self.setWindowFlags(values["f"])

        # initialize Sensormanager and ImageReader instances only once
        if not QuarterWidget._sensormanager:
            QuarterWidget._sensormanager = SensorManager()

        if not QuarterWidget._imagereader:
            QuarterWidget._imagereader = ImageReader()

        self.cachecontext_list = []
        self.cachecontext = self.findCacheContext(self, values["sharewidget"])
        self.statecursormap = {}

        self.scene = None
        self.contextmenu = None
        self.contextmenuenabled = True

        self.sorendermanager = coin.SoRenderManager()
        self.soeventmanager = coin.SoEventManager()

        # Mind the order of initialization as the XML state machine uses
        # callbacks which depends on other state being initialized
        self.eventmanager = EventManager(self)
        self.devicemanager = DeviceManager(self)

        statemachine = coin.ScXML.readFile(values["scxml"])
        if statemachine and statemachine.isOfType(
                coin.SoScXMLStateMachine.getClassTypeId()):
            sostatemachine = coin.cast(statemachine, "SoScXMLStateMachine")
            statemachine.addStateChangeCallback(statechangeCB, self)
            self.soeventmanager.addSoScXMLStateMachine(sostatemachine)
            sostatemachine.initialize()
        else:
            raise "could not initialize statemachine, given file not found?"

        self.headlight = coin.SoDirectionalLight()

        self.sorendermanager.setAutoClipping(
            coin.SoRenderManager.VARIABLE_NEAR_PLANE)
        self.sorendermanager.setRenderCallback(renderCB, self)
        self.sorendermanager.setBackgroundColor(coin.SbColor4f(0, 0, 0, 0))
        self.sorendermanager.activate()
        self.sorendermanager.addPreRenderCallback(prerenderCB, self)
        self.sorendermanager.addPostRenderCallback(postrenderCB, self)

        self.soeventmanager.setNavigationState(
            coin.SoEventManager.MIXED_NAVIGATION)

        self.devicemanager.registerDevice(MouseHandler())
        self.devicemanager.registerDevice(KeyboardHandler())
        self.eventmanager.registerEventHandler(DragDropHandler())

        # set up a cache context for the default SoGLRenderAction
        self.sorendermanager.getGLRenderAction().setCacheContext(
            self.getCacheContextId())

        self.setStateCursor("interact", QtCore.Qt.ArrowCursor)
        self.setStateCursor("idle", QtCore.Qt.OpenHandCursor)
        self.setStateCursor("rotate", QtCore.Qt.ClosedHandCursor)
        self.setStateCursor("pan", QtCore.Qt.SizeAllCursor)
        self.setStateCursor("zoom", QtCore.Qt.SizeVerCursor)
        self.setStateCursor("seek", QtCore.Qt.CrossCursor)
        self.setStateCursor("spin", QtCore.Qt.OpenHandCursor)

        self.setMouseTracking(True)
        self.setFocusPolicy(QtCore.Qt.StrongFocus)

    def setSceneGraph(self, node):
        if node and self.scene == node:
            return

        camera = None
        superscene = None
        viewall = False

        if node:
            self.scene = node
            self.scene.ref()

            superscene = coin.SoSeparator()
            superscene.addChild(coin.SoDepthBuffer())
            superscene.addChild(self.headlight)

            camera = self.searchForCamera(node)
            if not camera:
                camera = coin.SoPerspectiveCamera()
                superscene.addChild(camera)
                viewall = True

            superscene.addChild(node)

        self.soeventmanager.setSceneGraph(superscene)
        self.sorendermanager.setSceneGraph(superscene)
        self.soeventmanager.setCamera(camera)
        self.sorendermanager.setCamera(camera)

        if viewall:
            self.viewAll()

        if superscene:
            superscene.touch()

    def viewAll(self):
        """ Reposition the current camera to display the entire scene"""
        viewallevent = coin.SbName("sim.coin3d.coin.navigation.ViewAll")
        for c in range(self.soeventmanager.getNumSoScXMLStateMachines()):
            sostatemachine = self.soeventmanager.getSoScXMLStateMachine(c)
            if (sostatemachine.isActive()):
                sostatemachine.queueEvent(viewallevent)
                sostatemachine.processEventQueue()

    def resizeGL(self, width, height):
        vp = coin.SbViewportRegion(width, height)
        self.sorendermanager.setViewportRegion(vp)
        self.soeventmanager.setViewportRegion(vp)

    def paintGL(self):
        self.actualRedraw()

    def actualRedraw(self):
        self.sorendermanager.render(True, True)

    def event(self, qevent):
        """Translates Qt Events into Coin events and passes them on to the
          scenemanager for processing. If the event can not be translated or
          processed, it is forwarded to Qt and the method returns false. This
          method could be overridden in a subclass in order to catch events of
          particular interest to the application programmer."""

        if self.eventmanager.handleEvent(qevent):
            return True

        soevent = self.devicemanager.translateEvent(qevent)
        if (soevent and self.soeventmanager.processEvent(soevent)):
            return True

        # NOTE jkg: we must return True or False
        return QtOpenGL.QGLWidget.event(self, qevent)

    def setStateCursor(self, state, cursor):
        self.statecursormap[state] = cursor

    def searchForCamera(self, root):
        sa = coin.SoSearchAction()
        sa.setInterest(coin.SoSearchAction.FIRST)
        sa.setType(coin.SoCamera.getClassTypeId())
        sa.apply(root)

        if sa.getPath():
            node = sa.getPath().getTail()
            if node and node.isOfType(coin.SoCamera.getClassTypeId()):
                return node
        return None

    def getCacheContextId(self):
        return self.cachecontext.id

    def findCacheContext(self, widget, sharewidget):
        class QuarterWidgetP_cachecontext:
            def __init__(self):
                self.widgetlist = []
                self.id = None

        for cachecontext in self.cachecontext_list:
            for widget in cachecontext.widgetlist:
                if (widget == sharewidget):
                    cachecontext.widgetlist.append(widget)
                    return cachecontext
        cachecontext = QuarterWidgetP_cachecontext()
        cachecontext.id = coin.SoGLCacheContextElement.getUniqueCacheContext()
        cachecontext.widgetlist.append(widget)
        self.cachecontext_list.append(cachecontext)

        return cachecontext

    def getSoRenderManager(self):
        return self.sorendermanager

    def getSoEventManager(self):
        return self.soeventmanager

    def setBackgroundColor(self, color):
        """Set backgroundcolor to a given QColor
          Remember that QColors are given in integers between 0 and 255, as
          opposed to SbColor4f which is in [0 ,1]. The default alpha value for
          a QColor is 255, but you'll probably want to set it to zero before
          using it as an OpenGL clear color."""
        bgcolor = coin.SbColor4f(max(0, min(1,
                                            color.red() / 255.0)),
                                 max(0, min(1,
                                            color.green() / 255.0)),
                                 max(0, min(1,
                                            color.blue() / 255.0)),
                                 max(0, min(1,
                                            color.alpha() / 255.0)))
        self.sorendermanager.setBackgroundColor(bgcolor)

    def getBackgroundColor(self):
        """  Returns color used for clearing the rendering area before
          rendering the scene."""

        bg = self.sorendermanager.getBackgroundColor()

        return QtGui.QColor(max(0, min(255, int(bg[0] * 255.0))),
                            max(0, min(255, int(bg[1] * 255.0))),
                            max(0, min(255, int(bg[2] * 255.0))),
                            max(0, min(255, int(bg[3] * 255.0))))

    def getContextMenu(self):
        """Returns the context menu used by the widget."""
        if not self.contextmenu:
            self.contextmenu = ContextMenu(self)
        # NOTE 20080508 jkg: seems like we can drop .getMenu() but I dont see why that works
        return self.contextmenu.getMenu()

    def contextMenuEnabled(self):
        return contextmenuenabled

    def enableContextMenu(self, yesno):
        self.contextmenuenabled = yesno

    def setTransparencyType(self, type):
        """This method sets the transparency type to be used for the scene."""
        assert (self.sorendermanager)
        self.sorendermanager.getGLRenderAction().setTransparencyType(type)
        self.sorendermanager.scheduleRedraw()

    def enableHeadlight(self, onoff):
        """  Enable/disable the headlight. This wille toggle the SoDirectionalLigh::on
          field (returned from getHeadlight())."""
        self.headlight.on = onoff

    def getHeadlight(self):
        """Returns the light used for the headlight."""
        return self.headlight