pilas.asistente

Package pilas :: Module asistente |
[hide private]
[frames] | no frames]

# Source Code for Module pilas.asistente

      1  # -*- encoding: utf-8 -*-
      2  # pilas engine - a video game framework.
      3  #
      4  # copyright 2010 - hugo ruscitti
      5  # license: lgplv3 (see http://www.gnu.org/licenses/lgpl.html)
      6  #
      7  # website - http://www.pilas-engine.com.ar
      8
      9  import sys
     10  import os
     11  from PyQt4 import QtCore, QtGui, QtWebKit, QtNetwork
     12  import json
     13
     14  from asistente_base import Ui_AsistenteWindow
     15  import pilas
     16  import utils
     17
     18 -class VentanaAsistente(Ui_AsistenteWindow):
     19
     20 -    def setupUi(self, main):
     21          self.main = main
     22          Ui_AsistenteWindow.setupUi(self, main)
     23
     24          self.webView.setAcceptDrops(False)
     25          self.webView.page().setLinkDelegationPolicy(QtWebKit.QWebPage.DelegateExternalLinks)
     26          self.webView.connect(self.webView, QtCore.SIGNAL("linkClicked(const QUrl&)"), self.cuando_pulsa_link)
     27          self._cargar_pagina_principal()
     28          self._deshabilitar_barras_de_scroll()
     29          pilas.utils.centrar_ventana(main)
     30          self.statusbar.showMessage(u"Versión " + pilas.version())
     31          self._habilitar_inspector_web()
     32          self.salir_action.connect(self.salir_action, QtCore.SIGNAL("triggered()"), self.salir)
     33          self._consultar_ultima_version_del_servidor()
     34
     35 -    def _consultar_ultima_version_del_servidor(self):
     36          direccion = QtCore.QUrl("http://www.pilas-engine.com.ar/version.json")
     37          self.manager = QtNetwork.QNetworkAccessManager(self.main)
     38          self.manager.get(QtNetwork.QNetworkRequest(direccion))
     39
     40          self.manager.connect(self.manager, QtCore.SIGNAL("finished(QNetworkReply*)"),
     41                  self._cuando_termina_de_consultar_version)
     42
     43 -    def _cuando_termina_de_consultar_version(self, respuesta):
     44          respuesta_como_texto = respuesta.readAll().data()
     45          try:
     46              respuesta_como_json = json.loads(str(respuesta_como_texto))
     47
     48              version_en_el_servidor = float(respuesta_como_json['version'])
     49              version_instalada = float(pilas.pilasversion.VERSION)
     50
     51              if version_en_el_servidor == version_instalada:
     52                  mensaje = "- actualizada"
     53              elif version_en_el_servidor < version_instalada:
     54                  mensaje = u"- desarrollo (versión estable en la web: %.2f)" %(version_en_el_servidor)
     55              else:
     56                  mensaje = u"- desactualizada: la version %.2f ya está disponible en la web!)" %(version_en_el_servidor)
     57          except ValueError:
     58              mensaje = u"(sin conexión a internet)"
     59
     60          self.statusbar.showMessage(u"Versión " + pilas.version() + " " + mensaje)
     61
     62
     63 -    def _habilitar_inspector_web(self):
     64          QtWebKit.QWebSettings.globalSettings()
     65          settings = QtWebKit.QWebSettings.globalSettings()
     66          settings.setAttribute(QtWebKit.QWebSettings.DeveloperExtrasEnabled, True)
     67          settings.setAttribute(QtWebKit.QWebSettings.LocalContentCanAccessFileUrls, True)
     68
     69 -    def _deshabilitar_barras_de_scroll(self):
     70          self.webView.page().mainFrame().setScrollBarPolicy(QtCore.Qt.Horizontal, QtCore.Qt.ScrollBarAlwaysOff)
     71          self.webView.page().mainFrame().setScrollBarPolicy(QtCore.Qt.Vertical, QtCore.Qt.ScrollBarAsNeeded)
     72
     73 -    def _cargar_pagina_principal(self):
     74          file_path = utils.obtener_ruta_al_recurso('asistente/index.html')
     75          # TODO: convierto la ruta en absoluta para que mac desde py2app
     76          #       pueda interpretar correctamente las imagenes.
     77          file_path = os.path.abspath(file_path)
     78
     79          contenido = self._obtener_html(file_path)
     80          base_dir =  QtCore.QUrl.fromLocalFile(file_path)
     81          self.webView.setHtml(contenido, base_dir)
     82
     83 -    def _obtener_html(self, file_path):
     84          archivo = open(file_path, "rt")
     85          contenido = archivo.read()
     86          contenido = contenido.replace("{{VERSION_FRAME}}", """<iframe src='http://www.pilas-engine.com.ar/estadistica'></iframe>""")
     87          archivo.close()
     88          return contenido.decode('utf8')
     89
     90 -    def cuando_pulsa_link(self, url):
     91          seccion = str(url.path()).split('/')[-1]
     92
     93          if seccion == "interprete":
     94              self._cuando_selecciona_interprete()
     95          elif seccion == "manual":
     96              self._cuando_selecciona_abrir_manual()
     97          elif seccion == "web":
     98              import webbrowser
     99              webbrowser.open("http://www.pilas-engine.com.ar")
    100          else:
    101              partes = url.path().split('/')
    102
    103              if len(partes) == 4:
    104                  accion = partes[1]
    105                  categoria = partes[2]
    106                  ejemplo = partes[3]
    107
    108                  if accion == "ejecutar":
    109                      self._ejecutar_ejemplo(str(categoria), str(ejemplo))
    110                  elif accion == "codigo":
    111                      self._mostrar_codigo(str(categoria), str(ejemplo))
    112                  else:
    113                      print accion, "sobre el ejemplo", ejemplo
    114              else:
    115                  raise Exception(seccion + "es una opcion desconocida")
    116
    117 -    def _ejecutar_ejemplo(self, categoria, nombre):
    118          """Intenta ejecutar un programa de ejemplo en base a la categoria y nombre.
    119
    120          Internamente, esta funcion intenta buscar un archivo dentro de la
    121          ruta "../ejemplos/ejemplos/{categoria}/{nombre}.py".
    122          """
    123          try:
    124              ruta = self._obtener_ruta_al_ejemplo(categoria, nombre)
    125
    126              self.process = QtCore.QProcess(self.main)
    127              self.process.setProcessChannelMode(QtCore.QProcess.MergedChannels)
    128              self.process.finished.connect(self._cuando_termina_la_ejecucion_del_ejemplo)
    129              self.process.start(sys.executable, [ruta])
    130          except Exception, name:
    131              QtGui.QMessageBox.critical(self.main, "Error", str(name))
    132
    133 -    def _mostrar_codigo(self, categoria, nombre):
    134          try:
    135              ruta = self._obtener_ruta_al_ejemplo(categoria, nombre)
    136              file_path = utils.obtener_ruta_al_recurso('asistente/codigo.html')
    137              # TODO: convierto la ruta en absoluta para que mac desde py2app
    138              #       pueda interpretar correctamente las imagenes.
    139              file_path = os.path.abspath(file_path)
    140
    141              contenido = self._obtener_html(file_path)
    142
    143              import codecs
    144              archivo_codigo = codecs.open(ruta, "r", "utf-8")
    145              contenido_codigo = archivo_codigo.read()
    146              archivo_codigo.close()
    147              contenido = contenido.replace("{codigo}", contenido_codigo)
    148              base_dir =  QtCore.QUrl.fromLocalFile(file_path)
    149              self.webView.setHtml(contenido, base_dir)
    150          except Exception, name:
    151              QtGui.QMessageBox.critical(self.main, "Error", str(name))
    152
    153 -    def _obtener_ruta_al_ejemplo(self, categoria, nombre):
    154          recurso = "../ejemplos/ejemplos/" + categoria + "/" + nombre + ".py"
    155          return pilas.utils.obtener_ruta_al_recurso(recurso)
    156
    157
    158 -    def _cuando_termina_la_ejecucion_del_ejemplo(self, codigo, estado):
    159          "Vuelve a permitir que se usen todos los botone de la interfaz."
    160          salida = str(self.process.readAll())
    161
    162          if codigo:
    163              QtGui.QMessageBox.critical(self.main, "Error al iniciar ejemplo", "Error: \n" + salida)
    164
    165 -    def _cuando_selecciona_interprete(self):
    166          comando = " ".join([sys.executable, sys.argv[0], '-i'])
    167          self._ejecutar_comando(comando)
    168
    169 -    def ejecutar_script(self, nombre_archivo_script):
    170          comando = " ".join([sys.executable, sys.argv[0], '-i', str(nombre_archivo_script)])
    171          self._ejecutar_comando(comando)
    172
    173 -    def _ejecutar_comando(self, comando):
    174          "Ejecuta un comando en segundo plano."
    175          self.proceso = QtCore.QProcess()
    176          self.proceso.startDetached(comando)
    177
    178 -    def _cuando_selecciona_abrir_manual(self):
    179          base_dir = '/usr/share/pilas'
    180          ruta_al_manual = os.path.join(base_dir, 'pilas-%s.pdf' %(pilas.version()))
    181
    182          try:
    183              # BUSCA el archivo: /usr/share/pilas/pilas-VERSION.pdf
    184              ruta = pilas.utils.obtener_ruta_al_recurso(ruta_al_manual)
    185              pilas.utils.abrir_archivo_con_aplicacion_predeterminada(ruta)
    186          except IOError:
    187              try:
    188                  # BUSCA el archivo: /home/mi_usuario/.pilas/pilas-VERSION.pdf
    189                  base_dir = str(QtCore.QDir.homePath())
    190                  ruta_al_manual = os.path.join(base_dir, '.pilas', 'pilas-%s.pdf' %(pilas.version()))
    191                  ruta = pilas.utils.obtener_ruta_al_recurso(ruta_al_manual)
    192                  pilas.utils.abrir_archivo_con_aplicacion_predeterminada(ruta)
    193              except IOError:
    194                  titulo = "Error, no se encuentra el manual"
    195                  mensaje = u"Lo siento, no se encuentra el manual en tu equipo. ¿Quieres descargarlo?"
    196                  respuesta = self._consultar(self.main, titulo, mensaje)
    197
    198                  if respuesta == QtGui.QMessageBox.Yes:
    199                      url = "http://media.readthedocs.org/pdf/pilas/latest/pilas.pdf"
    200                      pilas.utils.descargar_archivo_desde_internet(self.main, url, ruta_al_manual)
    201
    202 -    def _consultar(self, parent, titulo, mensaje):
    203          "Realizar una consulta usando un cuadro de dialogo."
    204          return QtGui.QMessageBox.question(parent, titulo, mensaje,
    205                                      QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
    206
    207 -    def salir(self, *_):
    208          self.main.close()
    209
    210
    211 -class MainWindow(QtGui.QMainWindow):
    212
    213 -    def __init__(self):
    214          QtGui.QMainWindow.__init__(self)
    215          self.setAcceptDrops(True)
    216
    217 -    def definir_receptor_de_comandos(self, ui):
    218          self.ui = ui
    219
    220 -    def dragEnterEvent(self, event):
    221          if event.mimeData().hasUrls():
    222              event.acceptProposedAction()
    223
    224 -    def dragMoveEvent(self, event):
    225          super(MainWindow, self).dragMoveEvent(event)
    226
    227 -    def dropEvent(self, event):
    228          if event.mimeData().hasUrls():
    229              for url in event.mimeData().urls():
    230                  self.ui.ejecutar_script(url.path())
    231              event.acceptProposedAction()
    232          else:
    233              super(MainWindow,self).dropEvent(event)
    234
    235 -def ejecutar():
    236      app = QtGui.QApplication(sys.argv)
    237      app.setApplicationName("pilas-engine")
    238
    239      main = MainWindow()
    240      ui = VentanaAsistente()
    241      main.definir_receptor_de_comandos(ui)
    242      ui.setupUi(main)
    243
    244      main.show()
    245      main.raise_()
    246      app.exec_()
    247