app.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  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
  10. from socket import socket
  11. import socketserver
  12. import http.server
  13. import threading
  14. from PyQt5 import QtCore
  15. from PyQt5.QtCore import QCoreApplication, QUrl, QFileSystemWatcher, pyqtSlot, QSettings
  16. from PyQt5.QtGui import QKeySequence, QFont, QSyntaxHighlighter
  17. from PyQt5.QtWidgets import QMainWindow, QWidget, QApplication, QShortcut, QGridLayout, QLabel, QTabWidget, QHBoxLayout, QVBoxLayout, QSplitter, QSplitterHandle, QPlainTextEdit
  18. # from PyQt5.QtNetwork import QNetworkProxyFactory, QNetworkRequest
  19. from PyQt5.QtWebKit import QWebSettings
  20. from PyQt5.QtWebKitWidgets import QWebPage, QWebView, QWebInspector
  21. import sass
  22. class Core():
  23. def __init__(self, parent=None):
  24. self.server = Server()
  25. self.compiler = Compiler()
  26. self.settings = QSettings('FiguresLibres', 'Cascade')
  27. class Server():
  28. def __init__(self, parent=None):
  29. # find free port
  30. sock = socket()
  31. sock.bind(('', 0))
  32. self._port = sock.getsockname()[1]
  33. sock.close()
  34. self.httpd = http.server.HTTPServer(('', self.port), http.server.SimpleHTTPRequestHandler)
  35. self.thread = threading.Thread(target=self.httpd.serve_forever)
  36. self.thread.daemon = True
  37. self.thread.start()
  38. print("serving at port", self._port)
  39. @property
  40. def port(self):
  41. return self._port
  42. class Compiler():
  43. def __init__(self,parent=None):
  44. paths = [
  45. 'assets',
  46. 'assets/scss',
  47. 'assets/scss/styles.scss'
  48. ]
  49. self.fs_watcher = QFileSystemWatcher(paths)
  50. # self.fs_watcher.directoryChanged.connect(self.directory_changed)
  51. self.fs_watcher.fileChanged.connect(self.compile_scss)
  52. self.compile_scss()
  53. # def directory_changed(path):
  54. # print("Directory changed : %s" % path)
  55. def compile_scss(path = ""):
  56. print("compiling sass : %s" % path)
  57. scss = sass.compile_file(b'assets/scss/main.scss')
  58. with open('assets/scss/main.css', 'w') as fp:
  59. fp.write(scss.decode('utf8'))
  60. class WebkitView(QWebView):
  61. def __init__(self, port):
  62. self.port = port
  63. self.view = QWebView.__init__(self)
  64. self.load(QUrl('http://localhost:'+str(self.port)))
  65. self.settings().setAttribute(QWebSettings.DeveloperExtrasEnabled, True)
  66. # self.settings().setAttribute(QWebSettings.PluginsEnabled, True)
  67. class WebkitInspector(QWebInspector):
  68. def __init__(self, webkitview):
  69. super(WebkitInspector, self).__init__()
  70. self.webkitview = webkitview
  71. self.setPage(self.webkitview.page())
  72. # TODO: webkitinspector is disappearing when chaging tabs
  73. class CodeEditor(QPlainTextEdit):
  74. def __init__(self):
  75. super(CodeEditor, self).__init__()
  76. font = QFont()
  77. font.setFamily('Courier')
  78. font.setFixedPitch(True)
  79. font.setPointSize(10)
  80. self.setFont(font)
  81. # self.highlighter = Highlighter(self.document())
  82. # https://pypi.python.org/pypi/QScintilla/2.9.2
  83. class ViewTab(QWidget):
  84. def __init__(self, core):
  85. super(ViewTab, self).__init__()
  86. # self.grid = QGridLayout()
  87. hbox = QHBoxLayout()
  88. hbox.setContentsMargins(0,0,0,0)
  89. self.setLayout(hbox)
  90. # webviewbox = QVBoxLayout()
  91. vsplitter = QSplitter(QtCore.Qt.Vertical)
  92. self.webkitview = WebkitView(core.server.port)
  93. vsplitter.addWidget(self.webkitview)
  94. self.webkitinspector = WebkitInspector(self.webkitview)
  95. vsplitter.addWidget(self.webkitinspector)
  96. hsplitter = QSplitter(QtCore.Qt.Horizontal)
  97. hsplitter.addWidget(vsplitter)
  98. self.codeeditor = CodeEditor()
  99. hsplitter.addWidget(self.codeeditor)
  100. hbox.addWidget(hsplitter)
  101. def onChanged(self, text):
  102. print("ViewTba Layout Changed")
  103. self.lbl.setText(text)
  104. self.lbl.adjustSize()
  105. class MainWindow(QMainWindow):
  106. def __init__(self, core):
  107. super(MainWindow, self).__init__()
  108. self.core = core
  109. self.restorePreferences()
  110. # self.setWindowFlags(QtCore.Qt.WindowTitleHint)
  111. # QtCore.Qt.CustomizeWindowHint
  112. # | QtCore.Qt.Tool
  113. # | QtCore.Qt.FramelessWindowHint
  114. # | QtCore.Qt.WindowTitleHint
  115. # | QtCore.Qt.WindowStaysOnTopHint
  116. self.tabwidget = QTabWidget()
  117. # self.tabwidget.setContentsMargins(0,0,0,0)
  118. self.tabwidget.setStyleSheet("""
  119. QTabWidget::pane {
  120. border:0px solid inherted;
  121. margin:0px;
  122. padding:0px;
  123. }
  124. QTabBar::tab {
  125. padding: 4px;
  126. font-size:12px;
  127. }
  128. QTabBar::tab:selected {
  129. font-weight:bold;
  130. }
  131. """)
  132. self.viewtab = ViewTab(core)
  133. self.contenttab = QLabel("Content (markdown editor).")
  134. self.versiontab = QLabel("Version (git).")
  135. self.tabwidget.addTab(self.viewtab, "View")
  136. self.tabwidget.addTab(self.contenttab, "Content")
  137. self.tabwidget.addTab(self.versiontab, "Version")
  138. self.setCentralWidget(self.tabwidget)
  139. self.shortcut = QShortcut(QKeySequence("Ctrl+Q"), self)
  140. self.shortcut.activated.connect(self.on_quit)
  141. self.show()
  142. def restorePreferences(self):
  143. try:
  144. self.resize(self.core.settings.value('mainwindow/size', QtCore.QSize(1024, 768)))
  145. self.move(self.core.settings.value('mainwindow/pos', QtCore.QPoint(0, 0)))
  146. except:
  147. pass
  148. def savePreferences(self):
  149. self.core.settings.beginGroup("mainwindow")
  150. self.core.settings.setValue('size', self.size())
  151. self.core.settings.setValue('pos', self.pos())
  152. self.core.settings.endGroup()
  153. @pyqtSlot()
  154. def on_quit(self):
  155. print("Quit!")
  156. self.savePreferences()
  157. QCoreApplication.instance().quit()
  158. def main():
  159. app = QApplication(sys.argv)
  160. core = Core()
  161. mainappwindow = MainWindow(core)
  162. sys.exit(app.exec_())
  163. if __name__ == "__main__":
  164. main()