content.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. import sys, os
  4. from PyQt5 import QtCore
  5. from PyQt5.QtCore import QSettings
  6. from PyQt5.QtGui import QFont, QSyntaxHighlighter, QKeySequence
  7. from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QVBoxLayout, QSplitter, QListWidget, QListWidgetItem, QAbstractItemView, QButtonGroup, QPushButton, QInputDialog, QPlainTextEdit, QTextEdit,QShortcut
  8. import markdown2
  9. import re
  10. import json
  11. # _____
  12. # / ___/__ ______ ___ ____ ___ ____ ________ __
  13. # \__ \/ / / / __ `__ \/ __ `__ \/ __ `/ ___/ / / /
  14. # ___/ / /_/ / / / / / / / / / / / /_/ / / / /_/ /
  15. # /____/\__,_/_/ /_/ /_/_/ /_/ /_/\__,_/_/ \__, /
  16. # /____/
  17. class Summary(QWidget):
  18. def __init__(self, parent):
  19. super(Summary, self).__init__(parent)
  20. self.parent = parent
  21. jsonfilepath = os.path.join(self.parent.core.cwd,'.config/summary.json')
  22. sum_json = open(jsonfilepath).read()
  23. self.sum = json.loads(sum_json)
  24. vbox = QVBoxLayout()
  25. vbox.setContentsMargins(0,0,0,0)
  26. self.list = SummaryList(self)
  27. vbox.addWidget(self.list)
  28. self.actions = SummaryActions(self)
  29. vbox.addWidget(self.actions)
  30. self.setLayout(vbox)
  31. def addItem(self, text):
  32. # file
  33. filename = re.sub(r'\W', "_", text)+".md"
  34. # TODO: check if file does not already exists
  35. filepath = os.path.join(self.parent.core.cwd,'contents',filename)
  36. with open(filepath, 'w') as fp:
  37. fp.write('#'+text)
  38. # json
  39. item = {"title":text,"file":filename}
  40. self.sum.append(item)
  41. jsonfilepath = os.path.join(self.parent.core.cwd,'.config/summary.json')
  42. with open(jsonfilepath, "w") as fp:
  43. json.dump(self.sum, fp, ensure_ascii=False, indent="\t")
  44. # refresh list
  45. self.list.addNewItem(item)
  46. # reload content compiler
  47. self.parent.core.contentcompiler.reload()
  48. def recordNewList(self):
  49. newdata = []
  50. for i in range(0,self.list.count()):
  51. # print(self.item(i).item['title'])
  52. newdata.append(self.list.item(i).data)
  53. # print(newdata)
  54. self.sum = newdata
  55. jsonfilepath = os.path.join(self.parent.core.cwd,'.config/summary.json')
  56. with open(jsonfilepath, "w") as fp:
  57. json.dump(newdata, fp, ensure_ascii=False, indent="\t")
  58. # reload content compiler
  59. self.parent.core.contentcompiler.reload()
  60. class SummaryList(QListWidget):
  61. def __init__(self, parent):
  62. super(SummaryList, self).__init__(parent)
  63. self.parent = parent
  64. # self.sum = sum
  65. # print(self.sum)
  66. # self.setSortingEnabled(True)
  67. self.setDragEnabled(True)
  68. self.setSelectionMode(QAbstractItemView.SingleSelection)
  69. self.setAcceptDrops(True)
  70. self.setDropIndicatorShown(True)
  71. self.setDragDropMode(QAbstractItemView.InternalMove)
  72. self.model().rowsMoved.connect(self.onRowsMoved)
  73. # print(self.model())
  74. self.itemActivated.connect(self.onItemActivated)
  75. # add markdown files to the list
  76. for itemdata in self.parent.sum:
  77. self.addNewItem(itemdata)
  78. # self.setCurrentRow(0)
  79. # self.setCurrentIndex()
  80. # self.setCurrentItem()
  81. self.item(0).setSelected(True)
  82. # TODO: activate first item by default as it will open it with editor
  83. # TODO: show activated item on the list
  84. # TODO: show modifed item on the list
  85. def onRowsMoved(self, model, start, end, dest):
  86. # print("onRowsMoved")
  87. self.parent.recordNewList()
  88. def addNewItem(self, item):
  89. self.addItem(SummaryListWidgetItem(self,item))
  90. def onItemActivated(self, item):
  91. # print('onItemActivated', item.data)
  92. self.parent.parent.editor.openFile()
  93. class SummaryListWidgetItem(QListWidgetItem):
  94. def __init__(self,parent,data):
  95. super(SummaryListWidgetItem, self).__init__(parent)
  96. self.parent = parent
  97. self.data = data
  98. self.setText(data['title'])
  99. self.setToolTip(data['file'])
  100. class SummaryActions(QWidget):
  101. def __init__(self,parent):
  102. super(SummaryActions, self).__init__(parent)
  103. self.parent = parent
  104. self.hbox = QHBoxLayout()
  105. self.hbox.setContentsMargins(0,0,0,0)
  106. new = QPushButton("New Page", self)
  107. new.setShortcut('Ctrl+Shift+n')
  108. # new.setIcon(Icon(ico)))
  109. new.clicked.connect(self.onAddPage)
  110. self.hbox.addWidget(new)
  111. delete = QPushButton("Delete Page", self)
  112. delete.setShortcut('Ctrl+Shift+sup')
  113. # delete.setIcon(Icon(ico)))
  114. delete.clicked.connect(self.onDeletePage)
  115. self.hbox.addWidget(delete)
  116. self.setLayout(self.hbox)
  117. def onAddPage(self):
  118. text, ok = QInputDialog.getText(self, 'Input Dialog', 'Page Name:')
  119. if ok:
  120. self.parent.addItem(text)
  121. def onDeletePage(self):
  122. print("onDeletePage")
  123. # TODO: get the current selected page
  124. # TODO: ask for confirmation for deleting the current selecred page
  125. # TODO: call for summary widget to delete the page
  126. # ______ ___ __
  127. # / ____/___/ (_) /_____ _____
  128. # / __/ / __ / / __/ __ \/ ___/
  129. # / /___/ /_/ / / /_/ /_/ / /
  130. # /_____/\__,_/_/\__/\____/_/
  131. class MarkdownEditor(QWidget):
  132. def __init__(self,parent):
  133. super(MarkdownEditor, self).__init__(parent)
  134. self.parent = parent
  135. self.changed = False
  136. self.hbox = QHBoxLayout()
  137. self.hbox.setContentsMargins(0,0,0,0)
  138. self.styles = """
  139. background-color:white;
  140. color:black;
  141. padding:20px;
  142. """
  143. self.editor = QPlainTextEdit(self)
  144. self.editor.setStyleSheet(self.styles)
  145. self.hbox.addWidget(self.editor)
  146. self.viewer = QTextEdit(self)
  147. self.viewer.setReadOnly(True)
  148. self.viewer.setStyleSheet(self.styles)
  149. # TODO: show all html blocks on viewer
  150. self.hbox.addWidget(self.viewer)
  151. self.setLayout(self.hbox)
  152. self.editor.textChanged.connect(self.onTextChanged)
  153. self.openFile()
  154. self.shortcut = QShortcut(QKeySequence("Ctrl+s"), self)
  155. self.shortcut.activated.connect(self.save)
  156. self.refreshViewer()
  157. def openFile(self):
  158. # print("openFile")
  159. sumlist = self.parent.summary.list
  160. currentitem = sumlist.currentItem()
  161. if currentitem:
  162. if not self.changed:
  163. self.editor.textChanged.disconnect(self.onTextChanged)
  164. filename = currentitem.data['file']
  165. self.file = os.path.join(self.parent.core.cwd,'contents',filename)
  166. self.editor.clear()
  167. self.editor.insertPlainText(open(self.file, 'r').read())
  168. self.refreshViewer()
  169. self.editor.textChanged.connect(self.onTextChanged)
  170. else:
  171. print("Can't changed file, current id modified, please save first")
  172. # TODO: ask for saving current file
  173. def onTextChanged(self):
  174. self.refreshViewer()
  175. if not self.changed:
  176. self.changed = True
  177. # TODO: show in list that content needs to be saved
  178. # i = self.tabs.currentIndex()
  179. # self.tabs.setTabText(i, "* "+self.tabs.tabText(i))
  180. def refreshViewer(self):
  181. markdown = self.editor.toPlainText()
  182. html = markdown2.markdown(markdown)
  183. self.viewer.setHtml(html)
  184. def save(self):
  185. if self.changed:
  186. open(self.file, 'w').write(self.editor.toPlainText())
  187. self.changed = False
  188. # i = self.tabs.currentIndex()
  189. # self.tabs.setTabText(i, re.sub(r'^\*\s', '', self.tabs.tabText(i)))
  190. # TODO: how to combine file save and project save
  191. # __ ___ _
  192. # / |/ /___ _(_)___
  193. # / /|_/ / __ `/ / __ \
  194. # / / / / /_/ / / / / /
  195. # /_/ /_/\__,_/_/_/ /_/
  196. class ContentStack(QWidget):
  197. def __init__(self, core):
  198. super(ContentStack, self).__init__()
  199. self.core = core
  200. hbox = QHBoxLayout()
  201. hbox.setContentsMargins(0,0,0,0)
  202. self.setLayout(hbox)
  203. self.hsplitter = QSplitter(QtCore.Qt.Horizontal)
  204. self.summary = Summary(self)
  205. # TODO: detect external changes (file changed or new file)
  206. self.hsplitter.addWidget(self.summary)
  207. self.editor = MarkdownEditor(self)
  208. self.hsplitter.addWidget(self.editor)
  209. self.hsplitter.splitterMoved.connect(self.movedSplitter)
  210. hbox.addWidget(self.hsplitter)
  211. self.restorePrefs()
  212. def restorePrefs(self):
  213. settings = QSettings('FiguresLibres', 'Cascade')
  214. vals = settings.value('content/hsplitter/sizes', None)
  215. if vals:
  216. sizes = []
  217. for size in vals: sizes.append(int(size))
  218. self.hsplitter.setSizes(sizes)
  219. def movedSplitter(self):
  220. settings = QSettings('FiguresLibres', 'Cascade')
  221. # print(self.hsplitter.sizes())
  222. settings.setValue('content/hsplitter/sizes', self.hsplitter.sizes())