tizmee.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. #
  4. # Copyright (C) 2012 Mike Sheldon <elleo@gnu.org>
  5. #
  6. # Licensed under the Apache License, Version 2.0 (the "License");
  7. # you may not use this file except in compliance with the License.
  8. # You may obtain a copy of the License at
  9. #
  10. # http://www.apache.org/licenses/LICENSE-2.0
  11. #
  12. # Unless required by applicable law or agreed to in writing, software
  13. # distributed under the License is distributed on an "AS IS" BASIS,
  14. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. # See the License for the specific language governing permissions and
  16. # limitations under the License.
  17. from PySide import QtCore, QtGui, QtDeclarative
  18. import xml.etree.cElementTree as etree
  19. import sys, os, os.path, signal, shutil
  20. import subprocess, zipfile
  21. class Tizmee:
  22. def __init__(self):
  23. self.app = QtGui.QApplication(sys.argv)
  24. self.app.setApplicationName("Tizmee")
  25. signal.signal(signal.SIGINT, signal.SIG_DFL)
  26. self.cacheDir = QtGui.QDesktopServices.storageLocation(QtGui.QDesktopServices.CacheLocation)
  27. if not os.path.exists(self.cacheDir):
  28. os.mkdir(self.cacheDir)
  29. if os.path.exists("/home/user/MyDocs/"):
  30. # Maemo/Harmattan
  31. self.appDir = "/home/user/MyDocs/TizenApps"
  32. else:
  33. self.appDir = os.path.join(os.path.expanduser("~"), 'TizenApps')
  34. if not os.path.exists(self.appDir):
  35. os.mkdir(self.appDir)
  36. self.appsModel = AppsModel()
  37. self.view = QtDeclarative.QDeclarativeView()
  38. self.view.setSource("/opt/tizmee/qml/Tizmee.qml")
  39. self.rootObject = self.view.rootObject()
  40. self.context = self.view.rootContext()
  41. self.context.setContextProperty('appsModel', self.appsModel)
  42. self.rootObject.openFile("Launcher.qml")
  43. self.rootObject.quit.connect(sys.exit)
  44. self.rootObject.launch.connect(self.launch)
  45. self.view.showFullScreen()
  46. self.populate_apps()
  47. sys.exit(self.app.exec_())
  48. def populate_apps(self):
  49. for filename in os.listdir(self.appDir):
  50. wgtPath = os.path.join(self.appDir, filename)
  51. if zipfile.is_zipfile(wgtPath):
  52. appPath = os.path.join(self.cacheDir, filename)
  53. if not os.path.exists(appPath):
  54. os.mkdir(appPath)
  55. zapp = zipfile.ZipFile(wgtPath)
  56. config = zapp.open("config.xml")
  57. tree = etree.parse(config)
  58. root = tree.getroot()
  59. name = root.findtext("{http://www.w3.org/ns/widgets}name")
  60. icon = root.find("{http://www.w3.org/ns/widgets}icon").get("src")
  61. if icon:
  62. iconPath = os.path.join(appPath, icon)
  63. zapp.extract(icon, appPath)
  64. icon = iconPath
  65. try:
  66. startfile = root.find("{http://www.w3.org/ns/widgets}content").get("src")
  67. except:
  68. startfile = "index.html"
  69. app = App(name, wgtPath, appPath, startfile, icon)
  70. self.appsModel.add(app)
  71. if self.appsModel.rowCount() == 0:
  72. self.rootObject.showExitMessage("No Tizen apps installed", "You don't currently have any Tizen apps installed. To install an app place its .wgt file in %s." % self.appDir)
  73. def launch(self, wgtPath, path, startfile):
  74. zapp = zipfile.ZipFile(wgtPath)
  75. zapp.extractall(path)
  76. tjspath = os.path.join(path, "tizenjs")
  77. if os.path.exists(tjspath):
  78. shutil.rmtree(tjspath)
  79. shutil.copytree("/opt/tizmee/www/js/", tjspath)
  80. # HACK: Inject our JavaScript for implementing the Tizen API
  81. # TODO: Find a way to automatically do this on file load
  82. for filename in os.listdir(path):
  83. if filename[-4:].lower() == 'html' or filename[-3:].lower() == 'htm':
  84. htmlfile = open(os.path.join(path, filename), 'r')
  85. html = htmlfile.read()
  86. htmlfile.close()
  87. htmlfile = open(os.path.join(path, filename), 'w')
  88. html = html.replace("<head>", """<head>
  89. <script language='javascript' type='text/javascript' src='tizenjs/cordova.js'></script>
  90. <script language='javascript' type='text/javascript' src='tizenjs/cordova.qt.js'></script>
  91. <script language='javascript' type='text/javascript' src='tizenjs/tizensysteminfo.js'></script>
  92. """)
  93. if 'data-framework-viewport-scale="true"' not in html and "data-framework-viewport-scale='true'" not in html:
  94. # Handle scaling if the Tizen libs aren't doing it for us
  95. html = html.replace("<head>", """<head>
  96. <meta name="viewport" content="width=720; height=1280; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/>
  97. <style>
  98. body {
  99. zoom: 0.74;
  100. }
  101. </style>
  102. """)
  103. htmlfile.write(html)
  104. htmlfile.close()
  105. subprocess.Popen(["/usr/bin/invoker", "-S", "/opt/tizmee/tizmee-splash.png", "--type=e", "/opt/tizmee/bin/cordovaqt", path, startfile])
  106. class App(QtCore.QObject):
  107. def __init__(self, name, wgtPath, path, startfile, icon):
  108. self.name = name
  109. self.wgtPath = wgtPath
  110. self.path = path
  111. self.startfile = startfile
  112. self.icon = icon
  113. class AppsModel(QtCore.QAbstractListModel):
  114. NAME_ROLE = QtCore.Qt.UserRole + 1
  115. WGTPATH_ROLE = QtCore.Qt.UserRole + 2
  116. PATH_ROLE = QtCore.Qt.UserRole + 3
  117. STARTFILE_ROLE = QtCore.Qt.UserRole + 4
  118. ICON_ROLE = QtCore.Qt.UserRole + 5
  119. def __init__(self, parent=None):
  120. super(AppsModel, self).__init__(parent)
  121. self._data = []
  122. keys = {}
  123. keys[AppsModel.NAME_ROLE] = 'name'
  124. keys[AppsModel.WGTPATH_ROLE] = 'wgtpath'
  125. keys[AppsModel.PATH_ROLE] = 'path'
  126. keys[AppsModel.STARTFILE_ROLE] = 'startfile'
  127. keys[AppsModel.ICON_ROLE] = 'icon'
  128. self.setRoleNames(keys)
  129. def rowCount(self, index=0):
  130. return len(self._data)
  131. def data(self, index, role):
  132. app = self._data[index.row()]
  133. if role == AppsModel.NAME_ROLE:
  134. return app.name
  135. elif role == AppsModel.WGTPATH_ROLE:
  136. return app.wgtPath
  137. elif role == AppsModel.PATH_ROLE:
  138. return app.path
  139. elif role == AppsModel.STARTFILE_ROLE:
  140. return app.startfile
  141. elif role == AppsModel.ICON_ROLE:
  142. return app.icon
  143. else:
  144. return None
  145. def add(self, app):
  146. self.beginInsertRows(QtCore.QModelIndex(), 0, 0) #notify view about upcoming change
  147. self._data.insert(0, app)
  148. self.endInsertRows() #notify view that change happened
  149. def addToEnd(self, app):
  150. count = len(self._data)
  151. self.beginInsertRows(QtCore.QModelIndex(), count, count)
  152. self._data.insert(count, app)
  153. self.endInsertRows()
  154. if __name__ == "__main__":
  155. Tizmee()