app.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. # @Author: Bachir Soussi Chiadmi <bach>
  4. # @Date: 23-05-2017
  5. # @Email: bachir@figureslibres.io
  6. # @Last modified by: bach
  7. # @Last modified time: 21-04-2017
  8. # @License: GPL-V3
  9. import sys, os, shutil, tempfile
  10. from PyQt5 import QtCore
  11. from PyQt5.QtCore import QCoreApplication, QUrl, pyqtSlot, QSettings
  12. from PyQt5.QtGui import QIcon, QKeySequence, QFont, QSyntaxHighlighter
  13. from PyQt5.QtWidgets import QMainWindow, QAction, QWidget, QApplication, QShortcut, QGridLayout, QLabel, QTabWidget, QStackedWidget, QHBoxLayout, QVBoxLayout, QSplitter, QSplitterHandle, QPlainTextEdit, QInputDialog, QLineEdit, QFileDialog, QMessageBox, QPushButton
  14. # from PyQt5.QtNetwork import QNetworkProxyFactory, QNetworkRequest
  15. from PyQt5.QtWebKit import QWebSettings
  16. from PyQt5.QtWebKitWidgets import QWebPage, QWebView, QWebInspector
  17. import json
  18. import git
  19. from classes import server, sasscompiler, design, content
  20. class Core():
  21. def __init__(self, parent=None):
  22. # restore previous preferences
  23. self.appcwd = os.getcwd()
  24. self.restorePreferences()
  25. self._mw = False
  26. self.temp = tempfile.mkdtemp()
  27. # print(self.temp)
  28. self.tempcwd = False
  29. # if ther's not current project folder from restorepref
  30. # initaite a new temp project
  31. if(self.cwd == None or not os.path.isdir(self.cwd)):
  32. self.cwd = os.path.join(self.temp, 'cwd')
  33. self.tempcwd = True
  34. self.initnewproject()
  35. self.server = server.Server(self)
  36. self.sasscompiler = sasscompiler.Compiler(self)
  37. @property
  38. def mainwindow(self):
  39. return self.mainwindow
  40. @mainwindow.setter
  41. def mainwindow(self, mw):
  42. if not self._mw:
  43. self._mw = mw
  44. if not self.tempcwd:
  45. self._mw.setWindowTitle("Cascade – "+self.cwd)
  46. def restorePreferences(self):
  47. # print("restorePreferences")
  48. settings = QSettings('FiguresLibres', 'Cascade')
  49. # settings.clear()
  50. # print(settings.allKeys())
  51. self.cwd = settings.value('core/cwd', None)
  52. self.dialog_path = settings.value('core/dialog_path', os.path.expanduser('~'))
  53. self.mw_size = settings.value('mainwindow/size', QtCore.QSize(1024, 768))
  54. self.mw_pos = settings.value('mainwindow/pos', QtCore.QPoint(0, 0))
  55. self.mw_curstack = int(settings.value('mainwindow/curstack', 0))
  56. def savePreferences(self):
  57. # print("savePreferences")
  58. settings = QSettings('FiguresLibres', 'Cascade')
  59. # print(settings.allKeys())
  60. if not self.tempcwd:
  61. settings.setValue('core/cwd', self.cwd)
  62. settings.setValue('core/dialog_path', self.dialog_path)
  63. settings.setValue('mainwindow/size', self._mw.size())
  64. settings.setValue('mainwindow/pos', self._mw.pos())
  65. settings.setValue('mainwindow/curstack', self._mw.mainstack.currentIndex())
  66. def initnewproject(self, cwd = None):
  67. if cwd == None :
  68. cwd = self.cwd
  69. else :
  70. self.changeCWD(cwd)
  71. shutil.copytree('templates/newproject', cwd)
  72. self.prefs = json.loads(open(os.path.join(cwd,'.config/prefs.json')).read())
  73. self.summary = json.loads(open(os.path.join(cwd,'.config/summary.json')).read())
  74. self.repository = git.Repo.init(cwd)
  75. self.repository.index.add(['assets','contents','.config'])
  76. self.repository.index.commit("initial commit")
  77. # TODO: set mdtohtml compiler from project md to app index.html
  78. # TODO: embed project styles.scss to app scss frame work
  79. def saveproject(self, cwd = None):
  80. if not cwd == None:
  81. shutil.copytree(self.cwd, cwd)
  82. self.tempcwd = False
  83. self.changeCWD(cwd)
  84. def changeCWD(self, cwd):
  85. self.cwd = cwd
  86. self.server.reload()
  87. self.sasscompiler.reload()
  88. # if not self.tempcwd:
  89. self._mw.setWindowTitle("Cascade – "+self.cwd)
  90. def quit(self):
  91. self.savePreferences()
  92. shutil.rmtree(self.temp, ignore_errors=True)
  93. QCoreApplication.instance().quit()
  94. class MainWindow(QMainWindow):
  95. def __init__(self, core):
  96. super(MainWindow, self).__init__()
  97. # load core class
  98. self.core = core
  99. self.setWindowTitle("Cascade")
  100. self.setWindowIcon(QIcon(os.path.join(self.core.appcwd,'assets/images/icon.png')))
  101. self.resize(self.core.mw_size)
  102. self.move(self.core.mw_pos)
  103. self.initMenuBar()
  104. self.initMainStack()
  105. self.show()
  106. def initMenuBar(self):
  107. # menu bar
  108. bar = self.menuBar()
  109. file = bar.addMenu("&File")
  110. new = QAction("&New Project",self)
  111. new.setShortcut("Ctrl+n")
  112. file.addAction(new)
  113. open = QAction("&Open",self)
  114. open.setShortcut("Ctrl+o")
  115. file.addAction(open)
  116. self.save_action = QAction("&Save Project as",self)
  117. self.save_action.setShortcut("Ctrl+Shift+s")
  118. file.addAction(self.save_action)
  119. quit = QAction("&Quit",self)
  120. quit.setShortcut("Ctrl+q")
  121. file.addAction(quit)
  122. file.triggered[QAction].connect(self.onfilemenutrigger)
  123. # edit menu
  124. edit = bar.addMenu("&Edit")
  125. # edit.addAction("&copy")
  126. # edit.addAction("&paste")
  127. edit.addAction("&build")
  128. self.reload_action = QAction("&Reload",self)
  129. self.reload_action.setShortcut("Ctrl+r")
  130. edit.addAction(self.reload_action)
  131. edit.addAction("&preferences")
  132. edit.triggered[QAction].connect(self.oneditmenutrigger)
  133. # view menu
  134. view = bar.addMenu("&View")
  135. designview = QAction("&Design",self)
  136. designview.setShortcut("F1")
  137. view.addAction(designview)
  138. contentview = QAction("&Content",self)
  139. contentview.setShortcut("F2")
  140. view.addAction(contentview)
  141. versionview = QAction("&Version",self)
  142. versionview.setShortcut("F3")
  143. view.addAction(versionview)
  144. view.triggered[QAction].connect(self.onviewmenutrigger)
  145. # about menu
  146. about = bar.addMenu("About")
  147. about.addAction("&Website")
  148. def onfilemenutrigger(self, q):
  149. print(q.text()+" is triggered")
  150. if q.text() == "&New Project":
  151. self.newprojectdialogue()
  152. elif q.text() == "&Open":
  153. self.openprojectdialogue()
  154. elif q.text() == "&Save Project as":
  155. self.saveprojectdialogue()
  156. elif q.text() == "&Quit":
  157. self.quit()
  158. def openprojectdialogue(self):
  159. print("open")
  160. def newprojectdialogue(self):
  161. dialog = QFileDialog()
  162. dialog.setFileMode(QFileDialog.Directory)
  163. dialog.setAcceptMode(QFileDialog.AcceptOpen)
  164. projectname = dialog.getSaveFileName(
  165. self,
  166. 'New Project',
  167. self.core.dialog_path
  168. )[0]
  169. # TODO: no file type
  170. try:
  171. head, tail = os.path.split(projectname)
  172. self.core.dialog_path = head
  173. if not os.path.isdir(projectname):
  174. self.core.initnewproject(projectname)
  175. else:
  176. print("folder already exists")
  177. # TODO: check if is cascade folder
  178. except Exception as e:
  179. print('Exception', e)
  180. pass
  181. def saveprojectdialogue(self, quit=False):
  182. dialog = QFileDialog()
  183. dialog.setFileMode(QFileDialog.Directory)
  184. dialog.setAcceptMode(QFileDialog.AcceptOpen)
  185. projectname = dialog.getSaveFileName(
  186. self,
  187. 'Save Project',
  188. self.core.dialog_path
  189. )[0]
  190. # TODO: no file type
  191. try:
  192. head, tail = os.path.split(projectname)
  193. self.core.dialog_path = head
  194. if not os.path.isdir(projectname):
  195. self.core.saveproject(projectname)
  196. if quit:
  197. self.quit()
  198. else:
  199. print("folder already exists")
  200. # TODO: check if is cascade folder
  201. except Exception as e:
  202. print('Exception', e)
  203. pass
  204. def quit(self):
  205. print("Quit")
  206. if self.core.tempcwd:
  207. buttonReply = QMessageBox.question(self, 'Project Not Saved', "Do you want to save your current project before quiting?", QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel, QMessageBox.Cancel)
  208. if buttonReply == QMessageBox.Yes:
  209. self.saveprojectdialogue(quit=True)
  210. if buttonReply == QMessageBox.No:
  211. self.core.quit()
  212. else:
  213. self.core.quit()
  214. def oneditmenutrigger(self, q):
  215. print(q.text()+" is triggered")
  216. if q.text() == "&Reload":
  217. self.designstack.webkitview.reload()
  218. def onviewmenutrigger(self, q):
  219. print(q.text()+" is triggered")
  220. if q.text() == "&Design":
  221. self.mainstack.setCurrentIndex(0)
  222. elif q.text() == "&Content":
  223. self.mainstack.setCurrentIndex(1)
  224. elif q.text() == "&Version":
  225. self.mainstack.setCurrentIndex(2)
  226. def initMainStack(self):
  227. self.mainstack = QStackedWidget()
  228. self.designstack = design.DesignStack(self.core)
  229. self.contentstack = content.ContentStack(self.core)
  230. self.versionstack = QLabel("Version (git).")
  231. self.mainstack.addWidget(self.designstack)
  232. self.mainstack.addWidget(self.contentstack)
  233. self.mainstack.addWidget(self.versionstack)
  234. self.mainstack.setCurrentIndex(self.core.mw_curstack)
  235. self.setCentralWidget(self.mainstack)
  236. def main():
  237. app = QApplication(sys.argv)
  238. app.setOrganizationName('figli')
  239. app.setApplicationName('Cascade')
  240. core = Core()
  241. mainappwindow = MainWindow(core)
  242. core.mainwindow = mainappwindow
  243. sys.exit(app.exec_())
  244. if __name__ == "__main__":
  245. main()