[4] | 1 | ############################################################################
|
---|
| 2 | #
|
---|
| 3 | # DIM - A Direct Interaction Manager for SAGE
|
---|
| 4 | # Copyright (C) 2007 Electronic Visualization Laboratory,
|
---|
| 5 | # University of Illinois at Chicago
|
---|
| 6 | #
|
---|
| 7 | # All rights reserved.
|
---|
| 8 | #
|
---|
| 9 | # Redistribution and use in source and binary forms, with or without
|
---|
| 10 | # modification, are permitted provided that the following conditions are met:
|
---|
| 11 | #
|
---|
| 12 | # * Redistributions of source code must retain the above copyright
|
---|
| 13 | # notice, this list of conditions and the following disclaimer.
|
---|
| 14 | # * Redistributions in binary form must reproduce the above
|
---|
| 15 | # copyright notice, this list of conditions and the following disclaimer
|
---|
| 16 | # in the documentation and/or other materials provided with the distribution.
|
---|
| 17 | # * Neither the name of the University of Illinois at Chicago nor
|
---|
| 18 | # the names of its contributors may be used to endorse or promote
|
---|
| 19 | # products derived from this software without specific prior written permission.
|
---|
| 20 | #
|
---|
| 21 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
---|
| 22 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
---|
| 23 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
---|
| 24 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
---|
| 25 | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
---|
| 26 | # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
---|
| 27 | # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
---|
| 28 | # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
---|
| 29 | # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
---|
| 30 | # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
---|
| 31 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
---|
| 32 | #
|
---|
| 33 | # Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
|
---|
| 34 | #
|
---|
| 35 | # Author: Ratko Jagodic
|
---|
| 36 | #
|
---|
| 37 | ############################################################################
|
---|
| 38 |
|
---|
| 39 |
|
---|
| 40 |
|
---|
| 41 | # python stuff
|
---|
| 42 | import string, sys
|
---|
| 43 |
|
---|
| 44 | # my imports
|
---|
| 45 | from sageApp import SageApp, SageAppInitial
|
---|
| 46 | from sageDisplayInfo import SageDisplayInfo
|
---|
| 47 | from globals import *
|
---|
| 48 | import events
|
---|
| 49 |
|
---|
| 50 |
|
---|
| 51 | ## Main class to store all the messages returned by SAGE
|
---|
| 52 | class SageData:
|
---|
| 53 |
|
---|
| 54 |
|
---|
| 55 | #### constructor initializes member values
|
---|
| 56 | def __init__(self) :
|
---|
| 57 | self.hashApps = {} # all the apps available for running??
|
---|
| 58 | self.hashAppStatusInfo = {} # apps currently running
|
---|
| 59 | self.displayInfo = SageDisplayInfo()
|
---|
| 60 |
|
---|
| 61 | self.sageGate = getSageGate()
|
---|
| 62 | self.sageGate.registerCallbackFunction(40000, self.setSageStatus)
|
---|
| 63 | self.sageGate.registerCallbackFunction(40001, self.setSageAppInfo)
|
---|
| 64 | #self.sageGate.registerCallbackFunction(40002, self.setSagePerfInfo)
|
---|
| 65 | self.sageGate.registerCallbackFunction(40003, self.sageAppShutDown)
|
---|
| 66 | self.sageGate.registerCallbackFunction(40004, self.setDisplayInfo)
|
---|
| 67 | self.sageGate.registerCallbackFunction(40005, self.setSageZValue)
|
---|
| 68 | self.sageGate.registerCallbackFunction(40006, self.setSageAppExecConfig)
|
---|
| 69 | self.sageGate.registerCallbackFunction(40007, self.setDisplayConnections)
|
---|
| 70 | self.sageGate.registerCallbackFunction(40018, self.setSageObjectInfo)
|
---|
| 71 |
|
---|
| 72 |
|
---|
| 73 | ### clears the current state (to be done when reconnecting)
|
---|
| 74 | def clear(self):
|
---|
| 75 | self.hashApps = {} # all the apps available for running??
|
---|
| 76 | self.hashAppStatusInfo = {}
|
---|
| 77 |
|
---|
| 78 |
|
---|
| 79 | #### Set the sage status
|
---|
| 80 | def setSageStatus(self, appHash) :
|
---|
| 81 | for appName, configs in appHash.iteritems():
|
---|
| 82 | self.hashApps[appName] = SageAppInitial(appName, configs)
|
---|
| 83 |
|
---|
| 84 |
|
---|
| 85 | #----------------------------------------------------------------------
|
---|
| 86 |
|
---|
| 87 |
|
---|
| 88 | ### Set the possible execution configurations for each app
|
---|
| 89 | def setSageAppExecConfig(self, data):
|
---|
| 90 | tokens = string.split( data, '\n', 1 )
|
---|
| 91 | appName = tokens[0]
|
---|
| 92 | data = tokens[1] #the rest
|
---|
| 93 | configList = string.split( data, "config ")
|
---|
| 94 |
|
---|
| 95 | del configList[0] #remove the first item in the list
|
---|
| 96 |
|
---|
| 97 | for config in configList:
|
---|
| 98 | if appName in self.hashApps.keys():
|
---|
| 99 | (name, stringConfig) = string.split(config, ":", 1)
|
---|
| 100 | self.hashApps[appName].AddConfig(name, stringConfig)
|
---|
| 101 |
|
---|
| 102 |
|
---|
| 103 | #----------------------------------------------------------------------
|
---|
| 104 |
|
---|
| 105 |
|
---|
| 106 | #### Set the SAGE display information
|
---|
| 107 | ####
|
---|
| 108 | def setDisplayInfo(self, data):
|
---|
| 109 | listTokens = string.split(data, '\n')
|
---|
| 110 |
|
---|
| 111 | for i in range(0, len(listTokens), 3):
|
---|
| 112 | tileNumTokens = string.split(listTokens[i], ' ')
|
---|
| 113 | desktopTokens = string.split(listTokens[i+1], ' ')
|
---|
| 114 | tileConfTokens = string.split(listTokens[i+2], ' ')
|
---|
| 115 |
|
---|
| 116 | # so that we can support the old sage as well
|
---|
| 117 | displayId = 0
|
---|
| 118 | if len(tileConfTokens) > 2:
|
---|
| 119 | displayId = int(tileConfTokens[2])
|
---|
| 120 |
|
---|
| 121 | self.displayInfo.addDisplay(int(tileNumTokens[0]), int(tileNumTokens[1]), int(tileNumTokens[2]),
|
---|
| 122 | int(desktopTokens[0]), int(desktopTokens[1]),
|
---|
| 123 | int(tileConfTokens[0]), int(tileConfTokens[1]), displayId)
|
---|
| 124 |
|
---|
| 125 | # for one display and old SAGE there are no connection messages so just
|
---|
| 126 | # pretend that one came in for drawing everything correctly
|
---|
| 127 | if self.displayInfo.getNumDisplays() == 1:
|
---|
| 128 | self.setDisplayConnections("")
|
---|
| 129 |
|
---|
| 130 |
|
---|
| 131 | #----------------------------------------------------------------------
|
---|
| 132 |
|
---|
| 133 | # returns the SageDisplayInfo object
|
---|
| 134 | def getDisplayInfo(self, displayId=0):
|
---|
| 135 | return self.displayInfo.getDisplay(displayId)
|
---|
| 136 |
|
---|
| 137 | #----------------------------------------------------------------------
|
---|
| 138 |
|
---|
| 139 |
|
---|
| 140 | def setDisplayConnections(self, data):
|
---|
| 141 | if data:
|
---|
| 142 | for connection in data.split('\n'):
|
---|
| 143 | tokens = connection.split()
|
---|
| 144 | displayId = int(tokens[2])
|
---|
| 145 | self.displayInfo.getDisplay(displayId).placement = int(tokens[1])
|
---|
| 146 |
|
---|
| 147 | evt = events.DisplayInfoEvent(self.displayInfo)
|
---|
| 148 | getEvtMgr().postEvent(evt)
|
---|
| 149 |
|
---|
| 150 |
|
---|
| 151 | #----------------------------------------------------------------------
|
---|
| 152 |
|
---|
| 153 |
|
---|
| 154 | #### Get the new list of z values from SAGE
|
---|
| 155 | #### and update local hashes, then call the function to update the UI visually
|
---|
| 156 | def setSageZValue(self, message):
|
---|
| 157 | tokens = string.split(message)
|
---|
| 158 | numZChanges = int(tokens[0]) #the first item that comes in is the number of z changes
|
---|
| 159 | zHash = {} # key=appId, value=new z value
|
---|
| 160 |
|
---|
| 161 | # loop through all the tokens and update the z values of the apps
|
---|
| 162 | for i in range(numZChanges):
|
---|
| 163 | self.setZvalue( int(tokens[i*2+1]), int(tokens[i*2+2]) )
|
---|
| 164 | zHash[int(tokens[i*2+1])] = int(tokens[i*2+2])
|
---|
| 165 |
|
---|
| 166 | evt = events.ZChangeEvent(zHash)
|
---|
| 167 | getEvtMgr().postEvent(evt)
|
---|
| 168 |
|
---|
| 169 |
|
---|
| 170 | #----------------------------------------------------------------------
|
---|
| 171 |
|
---|
| 172 |
|
---|
| 173 | #### Set the SAGE app status
|
---|
| 174 | #### prints Invalid app ID if does not exists
|
---|
| 175 | def setSageAppInfo(self, data):
|
---|
| 176 | listTokens = string.split(data)
|
---|
| 177 |
|
---|
| 178 | # to support old sage as well
|
---|
| 179 | displayId = 0
|
---|
| 180 | orientation = 0
|
---|
| 181 | if len(listTokens) > 8:
|
---|
| 182 | orientation = int(listTokens[8])
|
---|
| 183 | displayId = int(listTokens[9])
|
---|
| 184 |
|
---|
| 185 |
|
---|
| 186 | appId = int( listTokens[ 1 ] )
|
---|
| 187 | if appId in self.hashAppStatusInfo:
|
---|
| 188 | # update the app in the hash
|
---|
| 189 | self.hashAppStatusInfo[ appId ].setAll( listTokens[0], int(listTokens[1]),
|
---|
| 190 | int(listTokens[2]), int(listTokens[3]), int(listTokens[4]), int(listTokens[5]),
|
---|
| 191 | int(listTokens[6]), int(listTokens[7]), orientation, displayId)
|
---|
| 192 |
|
---|
| 193 | # make the event
|
---|
| 194 | evt = events.AppInfoEvent(self.hashAppStatusInfo[appId])
|
---|
| 195 | else:
|
---|
| 196 | # when new app is started it is assigned a z=0 but since previous app on top had z=0,
|
---|
| 197 | # we set this one even higher temporarily (z=-1) so that it gets drawn on top
|
---|
| 198 | # the new z order message comes right after the app is started so this -1 is temporary
|
---|
| 199 | zValue = int(listTokens[7])
|
---|
| 200 | for app in self.hashAppStatusInfo.itervalues():
|
---|
| 201 | if app.getZvalue() == zValue:
|
---|
| 202 | zValue = -1
|
---|
| 203 | self.hashAppStatusInfo[ appId ] = SageApp( listTokens[0], int(listTokens[1]),
|
---|
| 204 | int(listTokens[2]), int(listTokens[3]), int(listTokens[4]), int(listTokens[5]),
|
---|
| 205 | int(listTokens[6]), zValue, orientation, displayId)
|
---|
| 206 |
|
---|
| 207 | # make the event
|
---|
| 208 | evt = events.NewAppEvent(self.hashAppStatusInfo[appId])
|
---|
| 209 |
|
---|
| 210 | # post the event about the state change
|
---|
| 211 | getEvtMgr().postEvent(evt)
|
---|
| 212 |
|
---|
| 213 |
|
---|
| 214 | #----------------------------------------------------------------------
|
---|
| 215 |
|
---|
| 216 |
|
---|
| 217 | ##### ShutDown the sage application
|
---|
| 218 | ##### prints invalid app ID if doesn't exist
|
---|
| 219 | def sageAppShutDown(self, data):
|
---|
| 220 | listTokens = string.split(data)
|
---|
| 221 | appId = int(listTokens[0])
|
---|
| 222 |
|
---|
| 223 | if appId in self.hashAppStatusInfo :
|
---|
| 224 | # do this first and then remove the app from the hash!!
|
---|
| 225 | # make and post the event
|
---|
| 226 | evt = events.AppKilledEvent(self.hashAppStatusInfo[appId])
|
---|
| 227 | getEvtMgr().postEvent(evt)
|
---|
| 228 |
|
---|
| 229 | # delete the app
|
---|
| 230 | del self.hashAppStatusInfo[appId]
|
---|
| 231 |
|
---|
| 232 |
|
---|
| 233 | #----------------------------------------------------------------------
|
---|
| 234 |
|
---|
| 235 |
|
---|
| 236 | def setSageObjectInfo(self, data):
|
---|
| 237 | evt = events.ObjectInfoEvent(data)
|
---|
| 238 | getEvtMgr().postEvent(evt)
|
---|
| 239 |
|
---|
| 240 |
|
---|
| 241 | #----------------------------------------------------------------------
|
---|
| 242 |
|
---|
| 243 |
|
---|
| 244 | # Get the z value of the app
|
---|
| 245 | # @arg appInstID App instance ID of the app
|
---|
| 246 | # @return Returns Z value if appID exists else returns -1
|
---|
| 247 | def getZvalue(self, appId):
|
---|
| 248 | if appId in self.hashAppStatusInfo:
|
---|
| 249 | return self.hashAppStatusInfo[appId].getZvalue()
|
---|
| 250 | else:
|
---|
| 251 | print("getZvalue: Invalid app instance ID")
|
---|
| 252 | return
|
---|
| 253 |
|
---|
| 254 |
|
---|
| 255 | #----------------------------------------------------------------------
|
---|
| 256 |
|
---|
| 257 |
|
---|
| 258 | # Set the Z value of the app
|
---|
| 259 | # @arg appInstId App instance ID of the app
|
---|
| 260 | # @arg value New Z value to be set
|
---|
| 261 | def setZvalue(self, appId, value):
|
---|
| 262 | if (appId in self.hashAppStatusInfo):
|
---|
| 263 | self.hashAppStatusInfo[appId].setZvalue(value)
|
---|
| 264 | else:
|
---|
| 265 | print ('setZvalue: Invalid app instance ID')
|
---|
| 266 | return
|
---|
| 267 |
|
---|
| 268 |
|
---|
| 269 | #----------------------------------------------------------------------
|
---|
| 270 |
|
---|
| 271 |
|
---|
| 272 | # returns the SageApp associated with the given appInstId
|
---|
| 273 | def getApp(self, appInstId):
|
---|
| 274 | return self.hashAppStatusInfo[appInstId]
|
---|
| 275 |
|
---|
| 276 |
|
---|
| 277 | #----------------------------------------------------------------------
|
---|
| 278 |
|
---|
| 279 |
|
---|
| 280 | ### (RJ 2005-01-15)
|
---|
| 281 | ### Returns a list of all the available apps
|
---|
| 282 | def getAvailableApps( self ):
|
---|
| 283 | return self.hashApps
|
---|
| 284 |
|
---|
| 285 | ### (AKS 2004-10-23)
|
---|
| 286 | ### Get all app IDs
|
---|
| 287 | ### currently running on sage
|
---|
| 288 | ### @return list of app ids
|
---|
| 289 | def getAllAppIDs(self) :
|
---|
| 290 | return self.hashAppStatusInfo.keys()
|
---|
| 291 |
|
---|
| 292 |
|
---|
| 293 | #----------------------------------------------------------------------
|
---|
| 294 |
|
---|
| 295 |
|
---|
| 296 | ### Returns a hash of all running apps
|
---|
| 297 | def getRunningApps( self ):
|
---|
| 298 | return self.hashAppStatusInfo
|
---|
| 299 |
|
---|
| 300 |
|
---|
| 301 | #----------------------------------------------------------------------
|
---|
| 302 |
|
---|
| 303 |
|
---|
| 304 | # checks all the apps and reports whether any one of them was
|
---|
| 305 | # hit with a click and which region was hit (corners or shape in general)
|
---|
| 306 | # if more than one shape was hit it returns the one on the top
|
---|
| 307 | def checkHits(self, x, y):
|
---|
| 308 | zHash = {} #key=z value, value=SageApp
|
---|
| 309 |
|
---|
| 310 | try:
|
---|
| 311 | for appId, sageApp in self.hashAppStatusInfo.items():
|
---|
| 312 | zHash[sageApp.getZvalue()] = sageApp
|
---|
| 313 |
|
---|
| 314 | zKeys = zHash.keys()
|
---|
| 315 | zKeys.sort()
|
---|
| 316 |
|
---|
| 317 | for z in zKeys:
|
---|
| 318 | hitResult = zHash[z].hitTest(x,y)
|
---|
| 319 | if hitResult >= 0:
|
---|
| 320 | return (zHash[z], hitResult)
|
---|
| 321 | except:
|
---|
| 322 | pass
|
---|
| 323 | return (None, -1)
|
---|
| 324 |
|
---|
| 325 |
|
---|
| 326 | #----------------------------------------------------------------------
|
---|
| 327 |
|
---|
| 328 |
|
---|
| 329 | # returns (appId, zValue) or (-1,sys.maxint) if no apps
|
---|
| 330 | def getTopApp(self):
|
---|
| 331 | minZ = (-1, sys.maxint)
|
---|
| 332 | try:
|
---|
| 333 | for appId, app in self.hashAppStatusInfo.items():
|
---|
| 334 | if app.getZvalue() < minZ[1]:
|
---|
| 335 | minZ = (appId, app.getZvalue())
|
---|
| 336 | except:
|
---|
| 337 | pass
|
---|
| 338 | return minZ
|
---|
| 339 |
|
---|