#!/usr/bin/env python2.4
#
# -----------------------
# ----- managerComp -----
# -----------------------
# An ICE component manager.
#
# Copyright (C) 2008 Luis J. Manso <luisDOTmanso gmailDOTcom>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
#
#
# TODO list: (robolab: Feel free to add whatever you want.)
# Hacer que xpos e ypos en el fichero de configuracion vayan expresados en escala visible
#
# Changes list:
# - 2007-07-25 - Show timestamps on the status information widget
# - 2007-08-23 - Consecutive clicks over a component switch its state (2 by default).
# - 2007-09-09 - Configuration management has been removed in order to get a clear interface.
# - 2007-09-22 - Docking has been disabled by default (use the check box to enable docking).
# - 2008-07-11 - Graph view
# - 2008-07-16 - Graph view speedup, config file edition
#
# CODE BEGINS
#
import sys, time, traceback, os, math, random
import Ice
from PyQt4 import QtCore, QtGui, Qt
from ui_form import Ui_Form
import managerCompConfig
dict = managerCompConfig.getDefaultValues()
if dict['scale'] == 0.: print 'scale == 0.?? Ok, lets crash...'
configFile = os.path.expanduser('~/managercomp.xml')
initDir = os.getcwd()
sys.path.append('.')
sys.path.append('/opt/managerComp/')
import managerCompEditor
class Bola:
def __init__(self):
self.x = 0
self.y = 0
self.r = 10
class Pregunta(QtGui.QWidget):
def __init__(self, parent, x, y):
QtGui.QWidget.__init__(self)
self.setParent(parent)
self.setGeometry(x, y, 100, 75)
self.button1 = QtGui.QPushButton(self)
self.button1.setGeometry(0, 0, 100, 25)
self.button1.setText('up')
self.button2 = QtGui.QPushButton(self)
self.button2.setGeometry(0, 25, 100, 25)
self.button2.setText('down')
self.button3 = QtGui.QPushButton(self)
self.button3.setGeometry(0, 50, 100, 25)
self.button3.setText('edit config')
self.show()
self.connect(self.button1, QtCore.SIGNAL('clicked()'), self.but1)
self.connect(self.button2, QtCore.SIGNAL('clicked()'), self.but2)
self.connect(self.button3, QtCore.SIGNAL('clicked()'), self.but3)
def but1(self): self.emit(QtCore.SIGNAL("up()"))
def but2(self): self.emit(QtCore.SIGNAL("down()"))
def but3(self): self.emit(QtCore.SIGNAL("config()"))
#
# Class which checks the availability of a given component.
#
class IceChecker:
def __init__(self, ):
self.ic = Ice.initialize(sys.argv)
def check(self, endpoint):
aPrx = None
try:
aPrx = self.ic.stringToProxy(endpoint)
except:
return False
try:
aPrx.ice_ping()
return True
except:
return False
#
# Application main class.
#
class TheThing(QtGui.QDialog):
def __init__(self):
# Gui config
global dict
QtGui.QDialog.__init__(self)
self.root = '/opt/managerComp/'
self.ui = Ui_Form()
self.ui.setupUi(self)
self.canvas = GraphView(self.ui.graphTab)
self.canvas.setGeometry(0, 0, 531, 581)
self.connect(self.canvas, QtCore.SIGNAL("nodeReleased()"), self.setFastState)
self.canvas.show()
self.canvasTimer = QtCore.QTimer()
self.canvasFastTimer = QtCore.QTimer()
self.connect(self.canvasTimer, QtCore.SIGNAL("timeout()"), self.graphUpdate)
self.connect(self.canvasFastTimer, QtCore.SIGNAL("timeout()"), self.graphFastEnds)
# Variables needed to switch the state of components when double-clicking over them.
self.clickTimes = 0
self.lastClickTime = QtCore.QTime()
self.clickNumber = -1
# Component config containter
self.compConfig = []
# Get an Ice Checker
self.checker = IceChecker()
# Init components sets and dictionaries
self.back_comps = {}
self.current_comps = {}
self.requests = set()
# Icon and system's tray stuff
self.iconOK = QtGui.QIcon(QtGui.QPixmap(self.root+'share/drawing_red.png'))
self.iconFULL = QtGui.QIcon(QtGui.QPixmap(self.root+'share/drawing_green.png'))
self.iconChange1 = QtGui.QIcon(QtGui.QPixmap(self.root+'share/drawing_right.png'))
self.iconChange2 = QtGui.QIcon(QtGui.QPixmap(self.root+'share/drawing_left.png'))
self.setWindowIcon(self.iconOK)
self.state = 0
self.doExit = False
self.systray = None
self.blinkTimer = QtCore.QTimer()
self.doDock = False
# Set connections
self.connect(self.ui.checkList, QtCore.SIGNAL("itemClicked(QListWidgetItem *)"), self.selectCheck)
self.connect(self.ui.upButton, QtCore.SIGNAL("clicked()"), self.up)
self.connect(self.ui.downButton, QtCore.SIGNAL("clicked()"), self.down)
self.connect(self.ui.tabWidget, QtCore.SIGNAL("currentChanged(int)"), self.tabChanged)
# Read file configuration
self.readConfig()
# Make a initial check
self.checkAll(initial=True)
# Set a fixed timeout for component checking
self.timer = QtCore.QTimer()
self.timer.start(dict['fixed'])
self.connect(self.timer, QtCore.SIGNAL("timeout()"), self.checkAll)
self.connect(self.canvas, QtCore.SIGNAL('upRequest()'), self.manageGraphUp)
self.connect(self.canvas, QtCore.SIGNAL('downRequest()'), self.manageGraphDown)
self.connect(self.canvas, QtCore.SIGNAL('configRequest()'), self.manageGraphConfig)
if (dict['active'] == "true"):
self.doSimulation = True
else:
self.doSimulation = False
self.menu = QtGui.QMenuBar(self)
self.menuFile = self.menu.addMenu('File')
self.actionOpen = self.menuFile.addAction('Open')
self.connect(self.actionOpen, QtCore.SIGNAL("triggered(bool)"), self.openFile)
self.actionSave = self.menuFile.addAction('Save')
self.connect(self.actionSave, QtCore.SIGNAL("triggered(bool)"), self.saveFile)
self.actionEdit = self.menuFile.addAction('Edit')
self.connect(self.actionEdit, QtCore.SIGNAL("triggered(bool)"), self.runEditor)
self.actionDock = self.menuFile.addAction('Dock')
self.connect(self.actionDock, QtCore.SIGNAL("triggered(bool)"), self.changeDock)
self.actionExit = self.menuFile.addAction('Exit')
self.connect(self.actionExit, QtCore.SIGNAL("triggered(bool)"), self.forceExit)
self.menuSim = self.menu.addMenu('Simulation')
if self.doSimulation == True:
self.actionSS = self.menuSim.addAction('Stop')
else:
self.actionSS = self.menuSim.addAction('Start')
self.connect(self.actionSS, QtCore.SIGNAL("triggered(bool)"), self.sSimulation)
if dict['dock'] == 'true':
self.changeDock()
self.canvas.update()
def openFile(self):
global configFile
configFile = QtGui.QFileDialog.getOpenFileName (self, "Select file", initDir, "*.xml")
self.readConfig()
def saveFile(self):
# XXX
global dict
s = QtGui.QFileDialog.getSaveFileName (self, "dd", "/home", "*.xml")
for c1 in self.compConfig:
for c2 in self.canvas.compList:
if c1.alias == c2.name:
c1.x = c2.x
c1.y = c2.y
c1.r = c2.r
managerCompConfig.writeConfigToFile(dict, self.compConfig, s)
def changeDock(self):
global dict
if self.doDock == False:
self.systray = QtGui.QSystemTrayIcon(self)
self.systray.setIcon(self.iconOK)
self.systray.setVisible(True)
self.connect(self.systray, QtCore.SIGNAL("activated (QSystemTrayIcon::ActivationReason)"), self.toggle)
self.connect(self.blinkTimer, QtCore.SIGNAL("timeout()"), self.changeIcon)
self.iconNumber = 0
self.doDock = True
dict['dock'] = 'true'
self.actionDock.setText('Undock')
else:
self.systray.deleteLater()
self.disconnect(self.blinkTimer, QtCore.SIGNAL("timeout()"), self.changeIcon)
self.iconNumber = 0
self.doDock = False
dict['dock'] = 'false'
self.actionDock.setText('Dock')
def sSimulation(self):
global dict
self.doSimulation = not self.doSimulation
if self.doSimulation == False:
self.actionSS.setText('Start')
if self.fastState == False:
self.canvasTimer.start(dict['focustime'])
dict['active'] = 'false'
else:
self.actionSS.setText('Stop')
self.setFastState()
if self.fastState == False:
self.canvasTimer.start(dict['idletime'])
dict['active'] = 'true'
def setFastState(self, fast=True):
global dict
self.fastState = fast
if fast:
self.canvasTimer.start(dict['fasttime'])
self.canvasFastTimer.start(dict['fastperiod'])
else:
self.canvasFastTimer.stop()
if self.ui.tabWidget.currentIndex() == 1 and self.doSimulation == True:
self.canvasTimer.start(dict['focustime'])
else:
self.canvasTimer.start(dict['idletime'])
def runEditor(self):
global configFile
self.editor = managerCompEditor.managerCompEditorWidget()
self.editor.setModal(True)
self.editor.show()
self.editor.readConfig(configFile)
self.connect(self.editor, QtCore.SIGNAL('finished()'), self.readConfig)
def manageGraphUp(self):
for idx in range(self.ui.checkList.count()):
if self.ui.checkList.item(idx).text() == self.canvas.request:
self.ui.checkList.setCurrentRow(idx)
self.selectCheck()
self.up()
break
def manageGraphDown(self):
for idx in range(self.ui.checkList.count()):
if self.ui.checkList.item(idx).text() == self.canvas.request:
self.ui.checkList.setCurrentRow(idx)
self.selectCheck()
self.down()
break
def manageGraphConfig(self):
for idx in range(self.ui.checkList.count()):
if self.ui.checkList.item(idx).text() == self.canvas.request:
self.ui.checkList.setCurrentRow(idx)
self.selectCheck()
self.config()
break
def graphUpdate(self):
global dict
self.canvas.checkForNewComponents(self)
if self.doSimulation:
self.canvas.step(self)
self.canvas.update()
def graphFastEnds(self):
self.setFastState(False)
#
# Current tab changed
@QtCore.pyqtSignature("int")
def tabChanged(self, num):
if self.fastState == False:
if num == 0: self.canvasTimer.start(dict['idletime'])
elif num == 1 and self.doSimulation == True: self.canvasTimer.start(dict['focustime'])
#
# Retuns True if the component specified is up, otherwise returns False
def itsUp(self, compNumber):
if self.current_comps[self.compConfig[compNumber].alias] == 1: return True
return False
#
# Queues the user's request to change the state of a given component, turning it off if it's on and viceversa.
def switchComponent(self, compNumber):
if self.itsUp(compNumber) == True: self.down()
else: self.up()
#
# Queues the user request to turn on a component
def up(self):
itsconfig = self.compConfig[self.ui.checkList.currentRow()]
self.requests = self.requests | set([itsconfig.alias])
self.clearFocus()
#
# Queues the user request to turn off a component
def down(self):
self.bg_exec(self.ui.downEdit.text(), self.ui.wdEdit.text())
self.clearFocus()
def config(self):
global dict
os.system(dict['path'] + ' ' + self.compConfig[self.ui.checkList.currentRow()].configFile)
#print itsconfig
self.clearFocus()
def readConfig(self):
global configFile
self.canvas.initialize()
self.ui.checkList.clear()
self.compConfig = []
self.back_comps = {}
self.current_comps = {}
self.requests = set()
newList, newDict = managerCompConfig.getConfigFromFile(configFile)
for k, v in newDict.iteritems():
dict[k] = v
for listItem in newList:
item = QtGui.QListWidgetItem()
item.setText(listItem.alias)
self.ui.checkList.insertItem(0, item)
self.compConfig.insert(0, listItem)
self.log('Configuration loaded')
n = managerCompConfig.unconnectedGroups(newList)
if n > 1:
msg = 'WARNING: ' + str(n) + ' unconnected component groups'
self.log(msg)
QtGui.QMessageBox.warning(self, 'Warning', msg)
self.setFastState()
def selectCheck(self):
# Check if it's a consecutive click
notTheLastOneAtTime = 0
if self.clickNumber != self.ui.checkList.currentRow():
notTheLastOneAtTime = 1
if self.lastClickTime.elapsed() > dict['interval']:
notTheLastOneAtTime = 1
if notTheLastOneAtTime == 0: # It's not
self.clickTimes = self.clickTimes + 1
else: # It is
self.clickTimes = 1
self.clickNumber = self.ui.checkList.currentRow()
self.lastClickTime = self.lastClickTime.currentTime()
# If it's a N-ary click: swap its state
if self.clickTimes >= dict['switch']:
self.switchComponent(self.clickNumber)
# Show information of the last clicked component
info = self.compConfig[self.ui.checkList.currentRow()]
self.ui.checkEdit.setText(info.endpoint)
self.ui.wdEdit.setText(info.workingdir)
self.ui.upEdit.setText(info.compup)
self.ui.downEdit.setText(info.compdown)
self.ui.cfgEdit.setText(info.configFile)
def checkAll(self, initial=False):
self.back_comps = {}
self.back_comps.update(self.current_comps)
self.current_comps = {}
items = len(self.compConfig)
allOk = True
for numItem in range(0, items):
ok = True
itemConfig = self.compConfig[numItem]
if self.checker.check(itemConfig.endpoint):
item = self.ui.checkList.item(numItem)
item.setTextColor(QtGui.QColor(0, 255, 0))
self.current_comps[itemConfig.alias] = 1
else:
item = self.ui.checkList.item(numItem)
item.setTextColor(QtGui.QColor(255, 0, 0))
self.current_comps[itemConfig.alias] = 0
allOk = False
intersectionKeys = set(self.current_comps.keys()) & set(self.back_comps.keys())
changes = False
for comp in intersectionKeys:
if self.current_comps[comp] != self.back_comps[comp]:
if changes == False and allOk == False:
self.blinkTimer.start(dict['blink'])
changes = True
if self.current_comps[comp] == 1:
self.log('Now \"' + comp + '\" is up.')
else:
self.log('Now \"' + comp + '\" is down.')
if self.wantsDocking():
if allOk and len(self.compConfig) > 0:
self.systray.setIcon(self.iconFULL)
elif changes == False:
self.systray.setIcon(self.iconOK)
self.upRequests()
def upRequests(self):
future_requests = self.requests
for alias in self.requests:
itsconfig = self.getConfigByAlias(alias)
unavailableDependences = []
for dep in itsconfig.dependences:
if self.current_comps[dep] == 0:
print dep
unavailableDependences.append(dep)
if len(unavailableDependences) == 0:
print 'managerComp: \tExec', alias, '. Removing: ', alias
self.upConfig(itsconfig)
future_requests = future_requests - set([alias])
else:
print 'managerComp: \tImpossible', alias, '. Adding: ', unavailableDependences
future_requests = future_requests | set(unavailableDependences)
self.requests = future_requests
#
# Tries to execute a component
def upConfig(self, conf):
self.bg_exec(conf.compup, conf.workingdir)
#
# Executes a command in the background
def bg_exec(self, command, workDir):
# Get command argument list
argument_list = command.split(' ')
# Set program as argument_list[0]
program = argument_list[0]
# Set args as argument_list[1, -1]
args = argument_list
currentWorkDir = os.getcwd()
os.chdir(workDir)
proc = QtCore.QProcess()
proc.startDetached(program, args)
os.chdir(currentWorkDir)
#
# Changes the icon of the program properly, skipping if docking is not active
def changeIcon(self):
if self.isActiveWindow() == True:
self.blinkTimer.stop()
self.systray.setIcon(self.iconOK)
else:
if self.iconNumber == 0:
self.systray.setIcon(self.iconChange1)
self.iconNumber = 1
elif self.iconNumber == 1:
self.systray.setIcon(self.iconChange2)
self.iconNumber = 2
else:
self.systray.setIcon(self.iconChange1)
self.iconNumber = 1
#
# (Un)hide the main window
def toggle(self):
if self.isVisible(): self.hide()
else: self.show()
#
# Manages close events
def closeEvent(self, closeevent):
if self.doExit != 1 and self.doDock == True:
closeevent.ignore()
self.hide()
elif self.wantsDocking():
closeevent.accept()
#
# Forces the program to exit
def forceExit(self):
self.doExit = 1
self.close()
#
# Clears the interface selection when the user presses 'Esc'
def keyPressEvent(self, keyevent):
if keyevent.key() == 16777216:#0x01000000
self.ui.checkList.clearSelection()
#
# Interface stuff:
def uiChange(self):
self.ui.checkList.setCurrentRow(0)
self.selectCheck()
self.clearFocus()
def clearFocus(self):
self.ui.checkList.clearSelection()
def log(self, text):
self.ui.outputText.append(' * ' + QtCore.QTime.currentTime().toString() + ': ' + text)
def getConfigByAlias(self, alias):
for config in self.compConfig:
if config.alias == alias:
return config
return None
#
# Return 1 if docking is selected, 0 otherwise.
def wantsDocking(self):
if self.doDock == True: return 1
else: return 0
def resizeEvent(self, e):
old = e.oldSize()
new = e.size()
inc = new - old
if (old.width() != -1):
self.ui.tabWidget.resize(self.ui.tabWidget.size()+inc)
self.canvas.resize(self.canvas.size()+inc)
self.ui.groupBox.resize(self.ui.groupBox.size()+inc)
self.ui.checkList.resize(self.ui.checkList.size()+inc)
self.ui.checkEdit.resize(self.ui.checkEdit.size()+inc)
self.ui.wdEdit.resize(self.ui.wdEdit.size()+inc)
self.ui.upEdit.resize(self.ui.upEdit.size()+inc)
self.ui.downEdit.resize(self.ui.downEdit.size()+inc)
self.ui.cfgEdit.resize(self.ui.cfgEdit.size()+inc)
self.ui.outputText.resize(self.ui.outputText.size()+inc)
e.accept()
class GraphNode:
def __init__(self):
self.name = ''
self.deps = []
self.on = False
self.x = 0.
self.y = 0.
self.r = 10.
self.vel_x = 0.
self.vel_y = 0.
def X2V(x):
return (x*dict['scale']) + 265
def Y2V(x):
return (x*dict['scale']) + 280
def X2R(x):
return (x-265) / dict['scale']
def Y2R(x):
return (x-280) / dict['scale']
class GraphView(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.initialize()
def initialize(self):
global dict
self.compList = []
self.bolaCogia = None
self.ox = 0
self.oy = 0
self.ui = None
self.hookes_constant = dict['hookes']
self.spring_length = dict['springlength']
self.roza = 1.-dict['friction']
self.time_elapsed2 = dict['step']**2
self.field_force_multiplier = dict['fieldforce']
def nodes(self):
if self.bolaCogia:
return self.compList + list(self.bolaCogia)
else:
return self.compList
def checkForNewComponents(self, parent):
# Check for components added to the configuration
anyone = False
for parentComp in parent.compConfig:
notFound = True
if self.bolaCogia:
if self.bolaCogia.name == parentComp.alias:
if self.bolaCogia.name in parent.current_comps:
if parent.current_comps[self.bolaCogia.name] == 1: self.bolaCogia.on = True
else: self.bolaCogia.on = False
break
if notFound:
for myComp in self.compList:
if myComp.name == parentComp.alias:
notFound = False
if myComp.name in parent.current_comps:
if parent.current_comps[myComp.name] == 1: myComp.on = True
else: myComp.on = False
break
if notFound:
newOne = GraphNode()
newOne.name = parentComp.alias
newOne.deps = parentComp.dependences
newOne.x = float(parentComp.x)
newOne.y = float(parentComp.y)
newOne.r = float(parentComp.r)
self.compList.append(newOne)
anyone = True
if anyone == True: self.step(self)
def step(self, parent):
#
# Compute velocities
for iterr in self.compList:
force_x = force_y = 0.
for iterr2 in self.compList:
if iterr.name == iterr2.name: continue
ix = iterr.x - iterr2.x
iy = iterr.y - iterr2.y
while ix == 0 and iy == 0:
iterr.x = iterr.x + random.uniform(-0.00000000001, 0.00000000001)/10000.
iterr2.x = iterr2.x + random.uniform(-0.00000000001, 0.00000000001)/10000.
iterr.y = iterr.y + random.uniform(-0.00000000001, 0.00000000001)/10000.
iterr2.y = iterr2.y + random.uniform(-0.00000000001, 0.00000000001)/10000.
ix = iterr.x - iterr2.x
iy = iterr.y - iterr2.y
angle = math.atan2(iy, ix)
dist2 = ((abs((iy*iy) + (ix*ix))) ** 0.5) ** 2.
if dist2 < self.spring_length: dist2 = self.spring_length
force = self.field_force_multiplier / dist2
force_x += force * math.cos(angle)
force_y += force * math.sin(angle)
for iterr2 in self.compList:
if iterr2.name in iterr.deps or iterr.name in iterr2.deps:
ix = iterr.x - iterr2.x
iy = iterr.y - iterr2.y
angle = math.atan2(iy, ix)
force = math.sqrt(abs((iy*iy) + (ix*ix))) # force means distance actually
if force <= self.spring_length: continue # "
force -= self.spring_length # force means spring strain now
force = force * self.hookes_constant # now force means force :-)
force_x -= force*math.cos(angle)
force_y -= force*math.sin(angle)
iterr.vel_x = (iterr.vel_x + (force_x*self.time_elapsed2))*self.roza
iterr.vel_y = (iterr.vel_y + (force_y*self.time_elapsed2))*self.roza
# Update positions
for iterr in self.compList:
iterr.x += iterr.vel_x
iterr.y += iterr.vel_y
def paintNode(self, node):
global dict
if node.on:
self.painter.setBrush(QtGui.QColor(0, 255, 0, dict['alpha']))
self.painter.setPen(QtGui.QColor(0, 255, 0))
else:
self.painter.setBrush(QtGui.QColor(255, 0, 0, dict['alpha']))
self.painter.setPen(QtGui.QColor(255, 0, 0))
self.painter.drawEllipse(X2V(node.x)-node.r, Y2V(node.y)-node.r, node.r*2, node.r*2)
#print(X2V(node.x)-node.r, Y2V(node.y)-node.r, node.r*2, node.r*2)
self.painter.drawText(QtCore.QPoint(X2V(node.x)-node.r, Y2V(node.y)-node.r-3), node.name)
def paintEvent(self, event):
nodosAPintar = [] + self.compList
if self.bolaCogia: nodosAPintar.append(self.bolaCogia)
self.painter = QtGui.QPainter(self)
self.painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
for i in nodosAPintar:
xo = i.x
yo = i.y
for j in nodosAPintar:
if j.name in i.deps:
angle = 180.-(math.atan2(yo-j.y, xo-j.x)*(57.2957795))
xinc = j.x - i.x
yinc = j.y - i.y
mag = ( xinc**2. + yinc**2. )**0.5
xshift = (xinc/mag)
yshift = (yinc/mag)
xinit = X2V(i.x)+xshift*i.r
yinit = Y2V(i.y)+yshift*i.r
xend = xinit+((mag*dict['scale']-i.r-j.r)*math.cos(angle*(math.pi/180.)))
yend = yinit-((mag*dict['scale']-i.r-j.r)*math.sin(angle*(math.pi/180.)))
self.painter.setPen(QtGui.QColor(0, 0, 255, 150))
self.painter.drawLine(xinit, yinit, xend, yend)
self.painter.setBrush(QtGui.QColor(0, 0, 255, 200))
#-j.r-(xshift/i.r)*j.r,
#-j.r-(yshift/i.r)*j.r
px = X2V(j.x)-10-xshift*j.r
py = Y2V(j.y)-10-yshift*j.r
self.painter.drawPie(px, py, 20, 20, abs((angle+180-16)*16), 32*16)
self.painter.setFont(QtGui.QFont("Arial", 13));
for i in self.compList:
self.paintNode(i)
if self.bolaCogia:
self.paintNode(self.bolaCogia)
self.painter = None
def mousePressEvent(self, e):
self.showNodeMenu(e)
def mouseDoubleClickEvent(self, e):
self.showNodeMenu(e, True)
def showNodeMenu(self, e, forceDialog=False):
x = e.x()
y = e.y()
if self.ui: self.ui.close()
bola = None
minDist = -1.
minIndex = 0
for b in self.compList:
bx = X2V(b.x)
by = Y2V(b.y)
dist = ( (bx-x)**2 + (by-y)**2 )**0.5
if dist < b.r:
if dist < minDist or minDist == -1.:
bola = b
minDist = dist
minIndex = self.compList.index(b)
self.ox = x - X2V(b.x)
self.oy = y - Y2V(b.y)
if bola:
if e.button() == 2 or forceDialog:
self.ui = Pregunta(self, X2V(self.compList[minIndex].x), Y2V(self.compList[minIndex].y))
self.ui.idx = minIndex
self.connect(self.ui, QtCore.SIGNAL('up()'), self.up)
self.connect(self.ui, QtCore.SIGNAL('down()'), self.down)
self.connect(self.ui, QtCore.SIGNAL('config()'), self.config)
self.ui.show()
elif e.button() == 1:
self.bolaCogia = self.compList.pop(minIndex)
self.repaint()
def mouseReleaseEvent(self, e):
if self.bolaCogia != None:
self.compList.append(self.bolaCogia)
self.bolaCogia = Bola()
self.bolaCogia = None
self.emit(QtCore.SIGNAL("nodeReleased()"))
def mouseMoveEvent(self, e):
self.repaint()
if self.bolaCogia != None:
self.bolaCogia.x = X2R(e.x()-self.ox)
self.bolaCogia.y = Y2R(e.y()-self.oy)
self.repaint()
def up(self):
self.request = self.compList[self.ui.idx].name
self.ui.close()
self.emit(QtCore.SIGNAL("upRequest()"))
def down(self):
self.request = self.compList[self.ui.idx].name
self.ui.close()
self.emit(QtCore.SIGNAL("downRequest()"))
def config(self):
self.request = self.compList[self.ui.idx].name
self.emit(QtCore.SIGNAL("configRequest()"))
self.ui.close()
#
# Create the Qt application, the class, and runs the program
#
if __name__ == '__main__':
if len(sys.argv) > 1:
configFile = sys.argv[1]
app = QtGui.QApplication(sys.argv)
window = TheThing()
window.show()
ret = -1
try:
ret = app.exec_()
except:
print 'Achu!'
sys.exit()