restructured project folders
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,308 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# @Author: Bachir Soussi Chiadmi <bach>
|
||||
# @Date: 23-05-2017
|
||||
# @Email: bachir@figureslibres.io
|
||||
# @Filename: content.py
|
||||
# @Last modified by: bach
|
||||
# @Last modified time: 03-06-2017
|
||||
# @License: GPL-V3
|
||||
|
||||
import os, re
|
||||
|
||||
from PyQt5 import QtCore
|
||||
from PyQt5.QtCore import QSettings
|
||||
from PyQt5.QtGui import QKeySequence
|
||||
from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QVBoxLayout, QSplitter, QListWidget, QListWidgetItem, QAbstractItemView, QPushButton, QInputDialog, QPlainTextEdit, QTextEdit, QShortcut
|
||||
|
||||
from classes import highlighter
|
||||
|
||||
import markdown
|
||||
import json
|
||||
|
||||
|
||||
# _____
|
||||
# / ___/__ ______ ___ ____ ___ ____ ________ __
|
||||
# \__ \/ / / / __ `__ \/ __ `__ \/ __ `/ ___/ / / /
|
||||
# ___/ / /_/ / / / / / / / / / / / /_/ / / / /_/ /
|
||||
# /____/\__,_/_/ /_/ /_/_/ /_/ /_/\__,_/_/ \__, /
|
||||
# /____/
|
||||
class Summary(QWidget):
|
||||
def __init__(self, parent):
|
||||
super(Summary, self).__init__(parent)
|
||||
self.parent = parent
|
||||
|
||||
self.loadJson()
|
||||
|
||||
vbox = QVBoxLayout()
|
||||
vbox.setContentsMargins(0,0,0,0)
|
||||
|
||||
self.list = SummaryList(self)
|
||||
vbox.addWidget(self.list)
|
||||
|
||||
self.actions = SummaryActions(self)
|
||||
vbox.addWidget(self.actions)
|
||||
|
||||
self.setLayout(vbox)
|
||||
|
||||
def loadJson(self):
|
||||
jsonfilepath = os.path.join(self.parent.core.cwd,'.config/summary.json')
|
||||
sum_json = open(jsonfilepath).read()
|
||||
self.sum = json.loads(sum_json)
|
||||
|
||||
|
||||
def addItem(self, text):
|
||||
# file
|
||||
filename = re.sub(r'\W', "_", text)+".md"
|
||||
# TODO: check if file does not already exists
|
||||
filepath = os.path.join(self.parent.core.cwd,'contents',filename)
|
||||
with open(filepath, 'w') as fp:
|
||||
fp.write('#'+text)
|
||||
# json
|
||||
item = {"title":text,"file":filename}
|
||||
self.sum.append(item)
|
||||
jsonfilepath = os.path.join(self.parent.core.cwd,'.config/summary.json')
|
||||
with open(jsonfilepath, "w") as fp:
|
||||
json.dump(self.sum, fp, ensure_ascii=False, indent="\t")
|
||||
# refresh list
|
||||
self.list.addNewItem(item)
|
||||
# reload content compiler
|
||||
self.parent.core.contentcompiler.reload()
|
||||
|
||||
def recordNewList(self):
|
||||
newdata = []
|
||||
for i in range(0,self.list.count()):
|
||||
# print(self.item(i).item['title'])
|
||||
newdata.append(self.list.item(i).data)
|
||||
|
||||
# print(newdata)
|
||||
self.sum = newdata
|
||||
jsonfilepath = os.path.join(self.parent.core.cwd,'.config/summary.json')
|
||||
with open(jsonfilepath, "w") as fp:
|
||||
json.dump(newdata, fp, ensure_ascii=False, indent="\t")
|
||||
|
||||
# reload content compiler
|
||||
self.parent.core.contentcompiler.reload()
|
||||
|
||||
def reload(self):
|
||||
self.loadJson()
|
||||
self.list.setItems()
|
||||
|
||||
class SummaryList(QListWidget):
|
||||
def __init__(self, parent):
|
||||
super(SummaryList, self).__init__(parent)
|
||||
self.parent = parent
|
||||
# self.sum = sum
|
||||
# print(self.sum)
|
||||
# self.setSortingEnabled(True)
|
||||
self.setDragEnabled(True)
|
||||
self.setSelectionMode(QAbstractItemView.SingleSelection)
|
||||
self.setAcceptDrops(True)
|
||||
self.setDropIndicatorShown(True)
|
||||
self.setDragDropMode(QAbstractItemView.InternalMove)
|
||||
|
||||
self.model().rowsMoved.connect(self.onRowsMoved)
|
||||
# print(self.model())
|
||||
|
||||
self.itemActivated.connect(self.onItemActivated)
|
||||
|
||||
self.setItems()
|
||||
|
||||
# self.setCurrentRow(0)
|
||||
# self.setCurrentIndex()
|
||||
# self.setCurrentItem()
|
||||
self.item(0).setSelected(True)
|
||||
# TODO: activate first item by default as it will open it with editor
|
||||
|
||||
# TODO: show activated item on the list
|
||||
# TODO: show modifed item on the list
|
||||
|
||||
def setItems(self):
|
||||
self.clear()
|
||||
# add markdown files to the list
|
||||
for itemdata in self.parent.sum:
|
||||
self.addNewItem(itemdata)
|
||||
|
||||
def onRowsMoved(self, model, start, end, dest):
|
||||
# print("onRowsMoved")
|
||||
self.parent.recordNewList()
|
||||
|
||||
def addNewItem(self, item):
|
||||
self.addItem(SummaryListWidgetItem(self,item))
|
||||
|
||||
def onItemActivated(self, item):
|
||||
# print('onItemActivated', item.data)
|
||||
self.parent.parent.editor.openFile(self.currentRow())
|
||||
|
||||
class SummaryListWidgetItem(QListWidgetItem):
|
||||
def __init__(self,parent,data):
|
||||
super(SummaryListWidgetItem, self).__init__(parent)
|
||||
self.parent = parent
|
||||
self.data = data
|
||||
|
||||
self.setText(data['title'])
|
||||
self.setToolTip(data['file'])
|
||||
|
||||
class SummaryActions(QWidget):
|
||||
def __init__(self,parent):
|
||||
super(SummaryActions, self).__init__(parent)
|
||||
|
||||
self.parent = parent
|
||||
|
||||
self.hbox = QHBoxLayout()
|
||||
self.hbox.setContentsMargins(0,0,0,0)
|
||||
|
||||
new = QPushButton("New Page", self)
|
||||
new.setShortcut('Ctrl+Shift+n')
|
||||
# new.setIcon(Icon(ico)))
|
||||
new.clicked.connect(self.onAddPage)
|
||||
self.hbox.addWidget(new)
|
||||
|
||||
delete = QPushButton("Delete Page", self)
|
||||
delete.setShortcut('Ctrl+Shift+sup')
|
||||
# delete.setIcon(Icon(ico)))
|
||||
delete.clicked.connect(self.onDeletePage)
|
||||
self.hbox.addWidget(delete)
|
||||
|
||||
|
||||
self.setLayout(self.hbox)
|
||||
|
||||
def onAddPage(self):
|
||||
text, ok = QInputDialog.getText(self, 'Input Dialog', 'Page Name:')
|
||||
if ok:
|
||||
self.parent.addItem(text)
|
||||
|
||||
def onDeletePage(self):
|
||||
print("onDeletePage")
|
||||
# TODO: get the current selected page
|
||||
# TODO: ask for confirmation for deleting the current selecred page
|
||||
# TODO: call for summary widget to delete the page
|
||||
|
||||
# ______ ___ __
|
||||
# / ____/___/ (_) /_____ _____
|
||||
# / __/ / __ / / __/ __ \/ ___/
|
||||
# / /___/ /_/ / / /_/ /_/ / /
|
||||
# /_____/\__,_/_/\__/\____/_/
|
||||
class MarkdownEditor(QWidget):
|
||||
def __init__(self,parent):
|
||||
super(MarkdownEditor, self).__init__(parent)
|
||||
self.parent = parent
|
||||
self.changed = False
|
||||
|
||||
self.hbox = QHBoxLayout()
|
||||
self.hbox.setContentsMargins(0,0,0,0)
|
||||
|
||||
self.styles = """
|
||||
background-color:white;
|
||||
color:black;
|
||||
padding:20px;
|
||||
"""
|
||||
|
||||
self.editor = QPlainTextEdit(self)
|
||||
self.editor.setStyleSheet(self.styles)
|
||||
|
||||
self.hl=highlighter.Highlighter(self.editor.document(),"md")
|
||||
self.hbox.addWidget(self.editor)
|
||||
|
||||
self.viewer = QTextEdit(self)
|
||||
self.viewer.setReadOnly(True)
|
||||
self.viewer.setStyleSheet(self.styles)
|
||||
# TODO: show all html blocks on viewer
|
||||
self.hbox.addWidget(self.viewer)
|
||||
|
||||
self.setLayout(self.hbox)
|
||||
|
||||
self.editor.textChanged.connect(self.onTextChanged)
|
||||
self.openFile()
|
||||
|
||||
self.shortcut = QShortcut(QKeySequence("Ctrl+s"), self)
|
||||
self.shortcut.activated.connect(self.save)
|
||||
|
||||
self.refreshViewer()
|
||||
|
||||
def openFile(self, row = 0):
|
||||
# print("openFile")
|
||||
sumlist = self.parent.summary.list
|
||||
item = sumlist.item(row)
|
||||
if item:
|
||||
if not self.changed:
|
||||
self.editor.textChanged.disconnect(self.onTextChanged)
|
||||
filename = item.data['file']
|
||||
self.file = os.path.join(self.parent.core.cwd,'contents',filename)
|
||||
self.editor.clear()
|
||||
self.editor.insertPlainText(open(self.file, 'r').read())
|
||||
self.refreshViewer()
|
||||
self.editor.textChanged.connect(self.onTextChanged)
|
||||
else:
|
||||
print("Can't changed file, current id modified, please save first")
|
||||
# TODO: ask for saving current file
|
||||
|
||||
def onTextChanged(self):
|
||||
self.refreshViewer()
|
||||
if not self.changed:
|
||||
self.changed = True
|
||||
# TODO: show in list that content needs to be saved
|
||||
# i = self.tabs.currentIndex()
|
||||
# self.tabs.setTabText(i, "* "+self.tabs.tabText(i))
|
||||
|
||||
def refreshViewer(self):
|
||||
md = self.editor.toPlainText()
|
||||
html = markdown.markdown(md)
|
||||
self.viewer.setHtml(html)
|
||||
|
||||
def save(self):
|
||||
if self.changed:
|
||||
open(self.file, 'w').write(self.editor.toPlainText())
|
||||
self.changed = False
|
||||
# i = self.tabs.currentIndex()
|
||||
# self.tabs.setTabText(i, re.sub(r'^\*\s', '', self.tabs.tabText(i)))
|
||||
# TODO: how to combine file save and project save
|
||||
|
||||
# _____ __ __
|
||||
# / ___// /_____ ______/ /__
|
||||
# \__ \/ __/ __ `/ ___/ //_/
|
||||
# ___/ / /_/ /_/ / /__/ ,<
|
||||
# /____/\__/\__,_/\___/_/|_|
|
||||
class ContentStack(QWidget):
|
||||
def __init__(self, core):
|
||||
super(ContentStack, self).__init__()
|
||||
self.core = core
|
||||
|
||||
hbox = QHBoxLayout()
|
||||
hbox.setContentsMargins(0,0,0,0)
|
||||
self.setLayout(hbox)
|
||||
|
||||
self.hsplitter = QSplitter(QtCore.Qt.Horizontal)
|
||||
|
||||
self.summary = Summary(self)
|
||||
# TODO: detect external changes (file changed or new file)
|
||||
self.hsplitter.addWidget(self.summary)
|
||||
|
||||
self.editor = MarkdownEditor(self)
|
||||
|
||||
self.hsplitter.addWidget(self.editor)
|
||||
|
||||
self.hsplitter.splitterMoved.connect(self.movedSplitter)
|
||||
|
||||
hbox.addWidget(self.hsplitter)
|
||||
|
||||
self.restorePrefs()
|
||||
|
||||
|
||||
def restorePrefs(self):
|
||||
settings = QSettings('FiguresLibres', 'Cascade')
|
||||
vals = settings.value('content/hsplitter/sizes', None)
|
||||
if vals:
|
||||
sizes = []
|
||||
for size in vals: sizes.append(int(size))
|
||||
self.hsplitter.setSizes(sizes)
|
||||
|
||||
def movedSplitter(self):
|
||||
settings = QSettings('FiguresLibres', 'Cascade')
|
||||
# print(self.hsplitter.sizes())
|
||||
settings.setValue('content/hsplitter/sizes', self.hsplitter.sizes())
|
||||
|
||||
def refresh(self):
|
||||
self.summary.reload()
|
||||
self.editor.openFile()
|
||||
@@ -0,0 +1,261 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# @Author: Bachir Soussi Chiadmi <bach>
|
||||
# @Date: 23-05-2017
|
||||
# @Email: bachir@figureslibres.io
|
||||
# @Last modified by: bach
|
||||
# @Last modified time: 03-06-2017
|
||||
# @License: GPL-V3
|
||||
|
||||
import os, re, shutil, tempfile
|
||||
# sys,
|
||||
from PyQt5 import QtCore
|
||||
from PyQt5.QtCore import QSettings, QCoreApplication
|
||||
|
||||
import json
|
||||
# import git
|
||||
# from pygit2 import Repository
|
||||
|
||||
from classes import server, sasscompiler, md2html
|
||||
|
||||
# ______
|
||||
# / ____/___ ________
|
||||
# / / / __ \/ ___/ _ \
|
||||
# / /___/ /_/ / / / __/
|
||||
# \____/\____/_/ \___/
|
||||
class Core():
|
||||
def __init__(self, parent=None):
|
||||
# restore previous preferences
|
||||
self.appcwd = os.getcwd()
|
||||
|
||||
self.restorePreferences()
|
||||
self._mw = False
|
||||
self.temp = tempfile.mkdtemp()
|
||||
# print(self.temp)
|
||||
|
||||
self.tempcwd = False
|
||||
# if ther's not current project folder from restorepref
|
||||
# initaite a new temp project
|
||||
if(self.cwd == None or not os.path.isdir(self.cwd)):
|
||||
self.cwd = os.path.join(self.temp, 'cwd')
|
||||
self.tempcwd = True
|
||||
self.initnewproject()
|
||||
self.initDeamons()
|
||||
else:
|
||||
self.initDeamons()
|
||||
head, tail = os.path.split(self.cwd)
|
||||
print('tail', tail)
|
||||
self.projectname = tail
|
||||
|
||||
self.loadDocSettings()
|
||||
|
||||
|
||||
def initDeamons(self):
|
||||
self.server = server.Server(self)
|
||||
self.sasscompiler = sasscompiler.Compiler(self)
|
||||
self.contentcompiler = md2html.Compiler(self)
|
||||
|
||||
@property
|
||||
def mainwindow(self):
|
||||
return self.mainwindow
|
||||
|
||||
@mainwindow.setter
|
||||
def mainwindow(self, mw):
|
||||
if not self._mw:
|
||||
self._mw = mw
|
||||
if not self.tempcwd:
|
||||
self._mw.setWindowTitle("Cascade – "+self.cwd)
|
||||
|
||||
# ____ ____
|
||||
# / __ \________ / __/____
|
||||
# / /_/ / ___/ _ \/ /_/ ___/
|
||||
# / ____/ / / __/ __(__ )
|
||||
# /_/ /_/ \___/_/ /____/
|
||||
def restorePreferences(self):
|
||||
# print("restorePreferences")
|
||||
settings = QSettings('FiguresLibres', 'Cascade')
|
||||
# settings.clear()
|
||||
# print(settings.allKeys())
|
||||
|
||||
self.cwd = settings.value('core/cwd', None)
|
||||
self.dialog_path = settings.value('core/dialog_path', os.path.expanduser('~'))
|
||||
|
||||
self.mw_size = settings.value('mainwindow/size', QtCore.QSize(1024, 768))
|
||||
self.mw_pos = settings.value('mainwindow/pos', QtCore.QPoint(0, 0))
|
||||
self.mw_curstack = int(settings.value('mainwindow/curstack', 0))
|
||||
|
||||
def savePreferences(self):
|
||||
# print("savePreferences")
|
||||
settings = QSettings('FiguresLibres', 'Cascade')
|
||||
# print(settings.allKeys())
|
||||
|
||||
if not self.tempcwd:
|
||||
settings.setValue('core/cwd', self.cwd)
|
||||
|
||||
settings.setValue('core/dialog_path', self.dialog_path)
|
||||
|
||||
settings.setValue('mainwindow/size', self._mw.size())
|
||||
settings.setValue('mainwindow/pos', self._mw.pos())
|
||||
settings.setValue('mainwindow/curstack', self._mw.mainstack.currentIndex())
|
||||
|
||||
# ____ _____ __ __ _
|
||||
# / __ \____ _____ / ___/___ / /_/ /_(_)___ ____ ______
|
||||
# / / / / __ \/ ___/ \__ \/ _ \/ __/ __/ / __ \/ __ `/ ___/
|
||||
# / /_/ / /_/ / /__ ___/ / __/ /_/ /_/ / / / / /_/ (__ )
|
||||
# /_____/\____/\___/ /____/\___/\__/\__/_/_/ /_/\__, /____/
|
||||
# /____/
|
||||
def loadDocSettings(self):
|
||||
self.docsettings = json.loads(open(os.path.join(self.cwd,'.config/docsettings.json')).read())
|
||||
|
||||
def recordDocSettings(self,docsettings):
|
||||
# print("doc settings",docsettings)
|
||||
for key in docsettings:
|
||||
self.docsettings[key] = docsettings[key]
|
||||
jsonfilepath = os.path.join(self.cwd,'.config/docsettings.json')
|
||||
with open(jsonfilepath, "w") as fp:
|
||||
json.dump(self.docsettings, fp, ensure_ascii=False, indent="\t")
|
||||
|
||||
self.updateScss(False)
|
||||
self.updateJs()
|
||||
|
||||
def updateScss(self, reload=True):
|
||||
# print(self.docsettings)
|
||||
sassfilepath = os.path.join(self.cwd,'assets/css/setup.scss')
|
||||
# print(sassfilepath)
|
||||
sass = open(sassfilepath,"r").read()
|
||||
sets = {
|
||||
'pw':'page-width',
|
||||
'ph':'page-height',
|
||||
'mt':'page-margin-top',
|
||||
'mb':'page-margin-bottom',
|
||||
'me':'page-margin-outside',
|
||||
'mi':'page-margin-inside',
|
||||
'cs':'crop-size',
|
||||
'bs':'bleed',
|
||||
'cg':'col-gutter',
|
||||
'rg':'row-gutter',
|
||||
'lh':'line-height'
|
||||
}
|
||||
for s in sets:
|
||||
sass = re.sub(
|
||||
r'\$'+sets[s]+':\smm2pt\([0-9|\.]+\);',
|
||||
'$'+sets[s]+': mm2pt('+self.docsettings[s]+');',
|
||||
sass)
|
||||
|
||||
# $col-number: 9;
|
||||
sass = re.sub(
|
||||
r'\$col-number:\s[0-9|\.]+;',
|
||||
'$col-number: '+self.docsettings['cn']+';',
|
||||
sass)
|
||||
# $row-number: 12;
|
||||
sass = re.sub(
|
||||
r'\$row-number:\s[0-9|\.]+;',
|
||||
'$row-number: '+self.docsettings['rn']+';',
|
||||
sass)
|
||||
#$header-odd: "Cascade, default header";
|
||||
sass = re.sub(
|
||||
r'\$header-odd:\s".+";',
|
||||
'$header-odd: "'+self.docsettings['ho']+'";',
|
||||
sass)
|
||||
# $header-even: "Cascade, default header";
|
||||
sass = re.sub(
|
||||
r'\$header-even:\s".+";',
|
||||
'$header-even: "'+self.docsettings['he']+'";',
|
||||
sass)
|
||||
|
||||
# print('sass', sass)
|
||||
open(sassfilepath,"w").write(sass)
|
||||
|
||||
if reload:
|
||||
self._mw.designstack.webkitview.reload()
|
||||
|
||||
def updateJs(self, reload=True):
|
||||
# print(self.docsettings)
|
||||
jsfilepath = os.path.join(self.cwd,'assets/js/setup.js')
|
||||
# print(jsfilepath)
|
||||
js = open(jsfilepath,"r").read()
|
||||
|
||||
# $row-number: 12;
|
||||
js = re.sub(
|
||||
r'nb_page=[0-9]+;',
|
||||
'nb_page='+str(self.docsettings['np'])+';',
|
||||
js)
|
||||
|
||||
# print('sass', sass)
|
||||
open(jsfilepath,"w").write(js)
|
||||
|
||||
if reload:
|
||||
self._mw.designstack.webkitview.reload()
|
||||
|
||||
def addPage(self):
|
||||
self.docsettings['np'] = int(self.docsettings['np'])+1
|
||||
self.updateJs()
|
||||
|
||||
def rmPage(self):
|
||||
self.docsettings['np'] = int(self.docsettings['np'])-1
|
||||
self.updateJs()
|
||||
|
||||
# ____ _ __
|
||||
# / __ \_________ (_)__ _____/ /_
|
||||
# / /_/ / ___/ __ \ / / _ \/ ___/ __/
|
||||
# / ____/ / / /_/ / / / __/ /__/ /_
|
||||
# /_/ /_/ \____/_/ /\___/\___/\__/
|
||||
# /___/
|
||||
def initnewproject(self, cwd = None):
|
||||
print('initnewproject')
|
||||
if cwd == None :
|
||||
cwd = self.cwd
|
||||
|
||||
shutil.copytree(os.path.join(self.appcwd,'templates/newproject'), cwd)
|
||||
self.changeCWD(cwd)
|
||||
self.loadDocSettings()
|
||||
self.summary = json.loads(open(os.path.join(cwd,'.config/summary.json')).read())
|
||||
# TODO: try python-pygit2 arch package
|
||||
# self.repository = git.Repo.init(cwd)
|
||||
# TODO: set git config user.name & user.email
|
||||
# self.repository
|
||||
# self.repository.index.add(['assets','contents','.config'])
|
||||
# self.repository.index.commit("initial commit")
|
||||
|
||||
|
||||
def saveproject(self, cwd = None):
|
||||
if not cwd == None:
|
||||
shutil.copytree(self.cwd, cwd)
|
||||
self.tempcwd = False
|
||||
self.changeCWD(cwd)
|
||||
|
||||
def openproject(self, cwd=None):
|
||||
if not cwd == None:
|
||||
self.changeCWD(cwd)
|
||||
|
||||
# __ _______ ______
|
||||
# _____/ /_ ____ _____ ____ ____ / ____/ | / / __ \
|
||||
# / ___/ __ \/ __ `/ __ \/ __ `/ _ \/ / | | /| / / / / /
|
||||
# / /__/ / / / /_/ / / / / /_/ / __/ /___ | |/ |/ / /_/ /
|
||||
# \___/_/ /_/\__,_/_/ /_/\__, /\___/\____/ |__/|__/_____/
|
||||
# /____/
|
||||
def changeCWD(self, cwd):
|
||||
if not cwd == self.cwd:
|
||||
self.cwd = cwd
|
||||
self.server.reload()
|
||||
self.sasscompiler.reload()
|
||||
self.contentcompiler.reload()
|
||||
|
||||
if not self.tempcwd:
|
||||
self._mw.setWindowTitle("Cascade – "+self.cwd)
|
||||
head, tail = os.path.split(self.cwd)
|
||||
print('tail', projectname)
|
||||
self.projectname = tail
|
||||
self._mw.designstack.refresh()
|
||||
self._mw.contentstack.refresh()
|
||||
|
||||
# ____ _ __
|
||||
# / __ \__ __(_) /_
|
||||
# / / / / / / / / __/
|
||||
# / /_/ / /_/ / / /_
|
||||
# \___\_\__,_/_/\__/
|
||||
def quit(self):
|
||||
self.savePreferences()
|
||||
shutil.rmtree(self.temp, ignore_errors=True)
|
||||
QCoreApplication.instance().quit()
|
||||
@@ -0,0 +1,492 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# @Author: Bachir Soussi Chiadmi <bach>
|
||||
# @Date: 23-05-2017
|
||||
# @Email: bachir@figureslibres.io
|
||||
# @Filename: design.py
|
||||
# @Last modified by: bach
|
||||
# @Last modified time: 03-06-2017
|
||||
# @License: GPL-V3
|
||||
|
||||
import os, re
|
||||
# sys,
|
||||
from PyQt5 import QtCore
|
||||
from PyQt5.QtCore import QUrl, QSettings, QSizeF, Qt
|
||||
from PyQt5.QtGui import QKeySequence, QFont
|
||||
from PyQt5.QtWidgets import QWidget, QTabWidget, QVBoxLayout, QHBoxLayout, QSplitter, QPlainTextEdit, QShortcut, QPushButton, QCheckBox, QSpinBox, QLabel
|
||||
from PyQt5.QtWebKit import QWebSettings
|
||||
from PyQt5.QtWebKitWidgets import QWebView, QWebInspector
|
||||
from PyQt5.QtPrintSupport import QPrintPreviewDialog, QPrinter
|
||||
|
||||
from classes import highlighter
|
||||
|
||||
|
||||
# _ __ __ _ ___
|
||||
# | | / /__ / /_| | / (_)__ _ __
|
||||
# | | /| / / _ \/ __ \ | / / / _ \ | /| / /
|
||||
# | |/ |/ / __/ /_/ / |/ / / __/ |/ |/ /
|
||||
# |__/|__/\___/_.___/|___/_/\___/|__/|__/
|
||||
class WebkitView(QWebView):
|
||||
def __init__(self, parent, core):
|
||||
self.parent = parent
|
||||
self.core = core
|
||||
self.port = core.server.port
|
||||
self.view = QWebView.__init__(self, parent)
|
||||
self.setZoomFactor(1)
|
||||
self.loadFinished.connect(self.onLoaded)
|
||||
self.load(QUrl('http://localhost:'+str(self.port)))
|
||||
self.settings().setAttribute(QWebSettings.DeveloperExtrasEnabled, True)
|
||||
# self.settings().setAttribute(QWebSettings.PluginsEnabled, True)
|
||||
|
||||
self.initPDF()
|
||||
# self.mainframe = self.page.mainFrame()
|
||||
# print(self.mainframe)
|
||||
|
||||
def onLoaded(self):
|
||||
print("WebView : onLoaded")
|
||||
self.parent.webviewtoolbar.onRefresh()
|
||||
|
||||
def initPDF(self):
|
||||
self.printer = QPrinter(QPrinter.HighResolution)
|
||||
self.printer.setFullPage(True)
|
||||
# self.printer.setPageMargins(0,0,0,0,QPrinter.Millimeter)
|
||||
self.printer.setFontEmbeddingEnabled(True)
|
||||
self.printer.setColorMode(QPrinter.Color)
|
||||
# TODO: set the page size and orientation from doc settings
|
||||
# (need to do doc settings before that)
|
||||
# self.printer.setPageSize(QPrinter.A4)
|
||||
self.printer.setPaperSize(QSizeF(210, 300), QPrinter.Millimeter)
|
||||
# self.printer.setOrientation(QPrinter.Portrait)
|
||||
self.printer.setOutputFormat(QPrinter.PdfFormat)
|
||||
self.printer.setCreator('Cascade')
|
||||
self.printer.setDocName(self.core.projectname)
|
||||
self.printer.setOutputFileName(self.core.projectname+".pdf")
|
||||
# self.setFixedWidth(1000)
|
||||
|
||||
def ongenPDF(self):
|
||||
# QPrinter::Custom
|
||||
# dialog = QPrintPreviewDialog(self.printer)
|
||||
# dialog.setWindowState(Qt.WindowMaximized)
|
||||
# dialog.paintRequested.connect(self.print_)
|
||||
# dialog.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowMinMaxButtonsHint | Qt.WindowCloseButtonHint | Qt.WindowContextHelpButtonHint)
|
||||
# dialog.exec()
|
||||
# TODO: open a dialogue to ask where to save the pdf
|
||||
# TODO: reload webview and wait for it before printing
|
||||
# TODO: addd a progress bar
|
||||
# self.webview.
|
||||
self.print_(self.printer)
|
||||
|
||||
def refresh(self):
|
||||
self.initPDF()
|
||||
self.reload()
|
||||
|
||||
def toggleDocClass(self, c="",a=True):
|
||||
if a :
|
||||
togg = "add"
|
||||
else :
|
||||
togg = "remove"
|
||||
command = """document.documentElement.classList."""+togg+"""('"""+c+"""')"""
|
||||
self.evaluateJS(command)
|
||||
|
||||
def zoom(self,z):
|
||||
self.setZoomFactor(z/100)
|
||||
# command = """
|
||||
# var zoomLevel = """+str(z)+""" / 100;
|
||||
# var elt = document.documentElement.querySelector("#pages");
|
||||
# elt.style.webkitTransform = "scale(" + zoomLevel + ")";
|
||||
# elt.style.webkitTransformOrigin = "0 0";
|
||||
# """
|
||||
# self.evaluateJS(command)
|
||||
|
||||
def changePage(self,p=0):
|
||||
command = """
|
||||
var pageNumber = """+str(p-1)+""";
|
||||
var target = document.documentElement.querySelectorAll('.paper')[pageNumber];
|
||||
var offsetTop = target.offsetTop;
|
||||
var offsetLeft = target.offsetLeft;
|
||||
document.documentElement.querySelector('body').scrollTop = offsetTop;
|
||||
document.documentElement.querySelector('body').scrollLeft = offsetLeft;
|
||||
"""
|
||||
self.evaluateJS(command)
|
||||
|
||||
def evaluateJS(self, command):
|
||||
self.page().mainFrame().evaluateJavaScript(command)
|
||||
|
||||
# ____ __
|
||||
# / _/___ _________ ___ _____/ /_____ _____
|
||||
# / // __ \/ ___/ __ \/ _ \/ ___/ __/ __ \/ ___/
|
||||
# _/ // / / (__ ) /_/ / __/ /__/ /_/ /_/ / /
|
||||
# /___/_/ /_/____/ .___/\___/\___/\__/\____/_/
|
||||
# /_/
|
||||
class WebkitInspector(QWebInspector):
|
||||
def __init__(self, parent, webkitview):
|
||||
super(WebkitInspector, self).__init__(parent)
|
||||
self.webkitview = webkitview
|
||||
self.setPage(self.webkitview.page())
|
||||
self.showMaximized()
|
||||
# TODO: webkitinspector is disappearing when chaging tabs
|
||||
|
||||
# ______ ______
|
||||
# /_ __/___ ____ / / __ )____ ______
|
||||
# / / / __ \/ __ \/ / __ / __ `/ ___/
|
||||
# / / / /_/ / /_/ / / /_/ / /_/ / /
|
||||
# /_/ \____/\____/_/_____/\__,_/_/
|
||||
class WebViewToolBar(QWidget):
|
||||
def __init__(self, parent):
|
||||
super(WebViewToolBar, self).__init__(parent)
|
||||
self.parent = parent
|
||||
|
||||
font = QFont()
|
||||
# font.setFamily("Droid Sans Mono")
|
||||
# font.setFixedPitch(True)
|
||||
font.setPointSize(8)
|
||||
self.setFont(font)
|
||||
|
||||
self.hbox = QHBoxLayout()
|
||||
self.hbox.setContentsMargins(0,0,0,0)
|
||||
|
||||
self.preview = QCheckBox('Prev&iew', self)
|
||||
self.preview.stateChanged.connect(self.onPreview)
|
||||
self.hbox.addWidget(self.preview)
|
||||
|
||||
self.debug = QCheckBox('Deb&ug', self)
|
||||
self.debug.stateChanged.connect(self.onDebug)
|
||||
self.hbox.addWidget(self.debug)
|
||||
|
||||
self.grid = QCheckBox('&Grid', self)
|
||||
self.grid.stateChanged.connect(self.onGrid)
|
||||
self.hbox.addWidget(self.grid)
|
||||
|
||||
self.spread = QCheckBox('&Spread', self)
|
||||
self.spread.stateChanged.connect(self.onSpread)
|
||||
self.hbox.addWidget(self.spread)
|
||||
|
||||
self.facing = QCheckBox('Fa&cing', self)
|
||||
self.facing.stateChanged.connect(self.onFacing)
|
||||
self.hbox.addWidget(self.facing)
|
||||
#
|
||||
self.hbox.addStretch()
|
||||
#
|
||||
# zoom
|
||||
self.hbox.addWidget(QLabel("Zoom:"))
|
||||
self.zoom = QSpinBox(self)
|
||||
self.zoom.setMinimum(-100)
|
||||
self.zoom.setMaximum(200)
|
||||
self.zoom.setSingleStep(10)
|
||||
self.zoom.setValue(90)
|
||||
self.zoom.valueChanged.connect(self.onZoomChanged)
|
||||
self.hbox.addWidget(self.zoom)
|
||||
|
||||
# page
|
||||
self.gotopage = QLabel("Go to Page: /"+self.parent.core.docsettings['np'])
|
||||
self.hbox.addWidget(self.gotopage)
|
||||
self.page = QSpinBox(self)
|
||||
self.page.setMinimum(1)
|
||||
self.page.setMaximum(int(self.parent.core.docsettings['np']))
|
||||
self.page.valueChanged.connect(self.onChangePage)
|
||||
self.hbox.addWidget(self.page)
|
||||
|
||||
self.addpage = QPushButton("&Add Page", self)
|
||||
self.addpage.clicked.connect(self.onAddPage)
|
||||
self.hbox.addWidget(self.addpage)
|
||||
self.rmpage = QPushButton("Re&move Page", self)
|
||||
self.rmpage.clicked.connect(self.onRmPage)
|
||||
self.hbox.addWidget(self.rmpage)
|
||||
|
||||
#
|
||||
self.hbox.addStretch()
|
||||
#
|
||||
self.reload = QPushButton("&Reload", self)
|
||||
# self.reload.setShortcut('Ctrl+Shift+r')
|
||||
# TODO: how to define same shortcut in different places
|
||||
# self.reload.setIcon(Icon(ico)))
|
||||
self.reload.clicked.connect(self.onReload)
|
||||
self.hbox.addWidget(self.reload)
|
||||
|
||||
self.genpdf = QPushButton("&PDF", self)
|
||||
# self.genpdf.setShortcut('Ctrl+Shift+r')
|
||||
# TODO: how to define same shortcut in different places
|
||||
# self.genpdf.setIcon(Icon(ico)))
|
||||
self.genpdf.clicked.connect(self.onGenPDF)
|
||||
self.hbox.addWidget(self.genpdf)
|
||||
|
||||
self.setLayout(self.hbox)
|
||||
|
||||
# def onCheckboxAction(self, box):
|
||||
# self.parent.webkitview.toggleDocClass(box, self[box].isChecked())
|
||||
# self.recToolbarState(box, self[box].isChecked())
|
||||
|
||||
def onPreview(self):
|
||||
print('Toolbar : onPreview', self.preview.isChecked())
|
||||
self.parent.webkitview.toggleDocClass('preview', self.preview.isChecked())
|
||||
self.recToolbarState('preview', self.preview.isChecked())
|
||||
|
||||
def onDebug(self):
|
||||
self.parent.webkitview.toggleDocClass('debug', self.debug.isChecked())
|
||||
self.recToolbarState('debug', self.debug.isChecked())
|
||||
|
||||
def onGrid(self):
|
||||
self.parent.webkitview.toggleDocClass('grid', self.grid.isChecked())
|
||||
self.recToolbarState('grid', self.grid.isChecked())
|
||||
|
||||
def onSpread(self):
|
||||
self.parent.webkitview.toggleDocClass('spread', self.spread.isChecked())
|
||||
self.recToolbarState('spread', self.spread.isChecked())
|
||||
|
||||
def onFacing(self):
|
||||
self.parent.webkitview.toggleDocClass('facing', self.facing.isChecked())
|
||||
self.recToolbarState('facing', self.facing.isChecked())
|
||||
|
||||
def onZoomChanged(self,i):
|
||||
# print("onZoomChanged : "+str(i))
|
||||
self.parent.webkitview.zoom(i)
|
||||
|
||||
def onZoomOn(self):
|
||||
# print("onZoomOn")
|
||||
self.zoom.setValue(self.zoom.value()+self.zoom.singleStep())
|
||||
|
||||
def onZoomOut(self):
|
||||
# print("onZoomOut")
|
||||
self.zoom.setValue(self.zoom.value()-self.zoom.singleStep())
|
||||
|
||||
def onChangePage(self, i):
|
||||
# print("onChangePage : "+str(i))
|
||||
self.parent.webkitview.changePage(i)
|
||||
|
||||
def onNextPage(self):
|
||||
# print('onNextPage')
|
||||
self.page.setValue(self.page.value()+self.page.singleStep())
|
||||
|
||||
def onPrevPage(self):
|
||||
# print('onPrevPage')
|
||||
self.page.setValue(self.page.value()-self.page.singleStep())
|
||||
|
||||
def onAddPage(self):
|
||||
# print("onAddPage")
|
||||
self.parent.core.addPage()
|
||||
|
||||
def onRmPage(self):
|
||||
# print("onAddPage")
|
||||
self.parent.core.rmPage()
|
||||
|
||||
def onReload(self):
|
||||
# print("onReload")
|
||||
self.parent.webkitview.reload()
|
||||
|
||||
def onGenPDF(self):
|
||||
print("onGenPDF")
|
||||
self.parent.webkitview.ongenPDF()
|
||||
|
||||
def recToolbarState(self, prop, val):
|
||||
# print('recToolbarState : '+prop, val)
|
||||
settings = QSettings('FiguresLibres', 'Cascade')
|
||||
settings.setValue('design/toolbar/'+prop, val)
|
||||
# print('recToolbarState after : '+prop, settings.value('design/toolbar/'+prop))
|
||||
|
||||
def onRefresh(self):
|
||||
# apply precedent toolbar state
|
||||
settings = QSettings('FiguresLibres', 'Cascade')
|
||||
self.preview.setChecked(bool(settings.value('design/toolbar/preview', False, type=bool)))
|
||||
self.debug.setChecked(bool(settings.value('design/toolbar/debug', False, type=bool)))
|
||||
self.grid.setChecked(bool(settings.value('design/toolbar/grid', False, type=bool)))
|
||||
self.spread.setChecked(bool(settings.value('design/toolbar/spread', False, type=bool)))
|
||||
self.facing.setChecked(bool(settings.value('design/toolbar/facing', False, type=bool)))
|
||||
# trigger webview changes
|
||||
self.parent.webkitview.toggleDocClass('preview', self.preview.isChecked())
|
||||
self.parent.webkitview.toggleDocClass('debug', self.debug.isChecked())
|
||||
self.parent.webkitview.toggleDocClass('grid', self.grid.isChecked())
|
||||
self.parent.webkitview.toggleDocClass('spread', self.spread.isChecked())
|
||||
|
||||
self.gotopage.setText("Go to Page: /"+str(self.parent.core.docsettings['np']))
|
||||
self.page.setMaximum(int(self.parent.core.docsettings['np']))
|
||||
self.parent.webkitview.changePage(self.page.value())
|
||||
# ______ ___ __
|
||||
# / ____/___/ (_) /_____ _____
|
||||
# / __/ / __ / / __/ __ \/ ___/
|
||||
# / /___/ /_/ / / /_/ /_/ / /
|
||||
# /_____/\__,_/_/\__/\____/_/
|
||||
class CodeEditor(QPlainTextEdit):
|
||||
def __init__(self, parent, core, tabs, file, mode):
|
||||
super(CodeEditor, self).__init__()
|
||||
self.parent = parent
|
||||
self.core = core
|
||||
self.tabs = tabs
|
||||
self.file = file
|
||||
self.hl= highlighter.Highlighter(self.document(),mode)
|
||||
self.setText()
|
||||
self.setTabStopWidth(15)
|
||||
|
||||
self.textChanged.connect(self.onTextChanged)
|
||||
|
||||
self.save_shortcut = QShortcut(QKeySequence("Ctrl+s"), self)
|
||||
self.save_shortcut.activated.connect(self.save)
|
||||
|
||||
def setText(self):
|
||||
# try:
|
||||
# self.textChanged.disconnect(self.onTextChanged)
|
||||
# except Exception as e:
|
||||
# print(e)
|
||||
|
||||
self.filepath = os.path.join(self.core.cwd,self.file)
|
||||
self.clear()
|
||||
self.insertPlainText(open(self.filepath, 'r').read())
|
||||
self.changed = False
|
||||
|
||||
font = QFont()
|
||||
font.setFamily("Droid Sans Mono")
|
||||
font.setFixedPitch(True)
|
||||
font.setPointSize(12)
|
||||
self.setFont(font)
|
||||
|
||||
|
||||
def onTextChanged(self):
|
||||
print('textChanged')
|
||||
# print(self.toPlainText())
|
||||
# open(self.filepath, 'w').write(self.toPlainText())
|
||||
if not self.changed:
|
||||
self.changed = True
|
||||
i = self.tabs.currentIndex()
|
||||
# self.tabs.setTabText(i, re.sub(r'^\**\s', '', self.tabs.tabText(i)))
|
||||
self.tabs.setTabText(i, "* "+self.tabs.tabText(i))
|
||||
# TODO: indicate that webview needs to be reloaded
|
||||
|
||||
def save(self):
|
||||
if self.changed:
|
||||
open(self.filepath, 'w').write(self.toPlainText())
|
||||
i = self.tabs.currentIndex()
|
||||
self.tabs.setTabText(i, re.sub(r'^\**\s', '', self.tabs.tabText(i)))
|
||||
self.parent.reloadView()
|
||||
self.changed = False
|
||||
# TODO: how to combine file save and project save
|
||||
|
||||
class Editor(QWidget):
|
||||
def __init__(self, parent):
|
||||
super(Editor, self).__init__()
|
||||
self.parent = parent
|
||||
|
||||
self.layout = QVBoxLayout(self)
|
||||
self.layout.setContentsMargins(0,0,0,0)
|
||||
|
||||
# Initialize tab screen
|
||||
self.tabs = QTabWidget()
|
||||
|
||||
self.scsstab = CodeEditor(self, self.parent.core, self.tabs, 'assets/css/styles.scss', "sass")
|
||||
self.jstab = CodeEditor(self, self.parent.core, self.tabs, 'assets/js/script.js', 'js')
|
||||
|
||||
# Add tabs
|
||||
self.tabs.addTab(self.scsstab,"scss")
|
||||
self.tabs.addTab(self.jstab,"js")
|
||||
|
||||
# Add tabs to widget
|
||||
self.layout.addWidget(self.tabs)
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def refresh(self):
|
||||
self.scsstab.setText()
|
||||
self.jstab.setText()
|
||||
|
||||
def reloadView(self):
|
||||
self.parent.webkitview.reload()
|
||||
|
||||
# _____ __ __
|
||||
# / ___// /_____ ______/ /__
|
||||
# \__ \/ __/ __ `/ ___/ //_/
|
||||
# ___/ / /_/ /_/ / /__/ ,<
|
||||
# /____/\__/\__,_/\___/_/|_|
|
||||
class DesignStack(QWidget):
|
||||
def __init__(self, core):
|
||||
super(DesignStack, self).__init__()
|
||||
self.core = core
|
||||
|
||||
# self.grid = QGridLayout()
|
||||
self.hbox = QHBoxLayout()
|
||||
self.hbox.setContentsMargins(0,0,0,0)
|
||||
self.setLayout(self.hbox)
|
||||
|
||||
|
||||
self.webview = QWidget()
|
||||
self.webview.vbox = QVBoxLayout()
|
||||
self.webview.setLayout(self.webview.vbox)
|
||||
self.webview.vbox.setContentsMargins(0,0,0,0)
|
||||
|
||||
# toolbar
|
||||
self.webviewtoolbar = WebViewToolBar(self)
|
||||
self.webview.vbox.addWidget(self.webviewtoolbar)
|
||||
|
||||
# webkitview
|
||||
self.webkitview = WebkitView(self, core)
|
||||
|
||||
# webkitinspector
|
||||
self.webkitinspector = WebkitInspector(self, self.webkitview)
|
||||
|
||||
# V layout
|
||||
self.vsplitter = QSplitter(QtCore.Qt.Vertical)
|
||||
self.vsplitter.addWidget(self.webkitview)
|
||||
self.vsplitter.addWidget(self.webkitinspector)
|
||||
self.vsplitter.splitterMoved.connect(self.movedSplitter)
|
||||
|
||||
self.webview.vbox.addWidget(self.vsplitter)
|
||||
|
||||
# H layout
|
||||
self.hsplitter = QSplitter(QtCore.Qt.Horizontal)
|
||||
self.hsplitter.addWidget(self.webview)
|
||||
|
||||
# editor
|
||||
self.editor = Editor(self)
|
||||
self.hsplitter.addWidget(self.editor)
|
||||
|
||||
self.hsplitter.splitterMoved.connect(self.movedSplitter)
|
||||
|
||||
self.hbox.addWidget(self.hsplitter)
|
||||
|
||||
self.restorePrefs()
|
||||
|
||||
def toggleInspector(self):
|
||||
self.webkitinspector.setVisible(not self.webkitinspector.isVisible())
|
||||
|
||||
def initShortcuts(self):
|
||||
# inspector
|
||||
shortcut = QShortcut(self)
|
||||
shortcut.setKey("F12")
|
||||
shortcut.activated.connect(self.toggleInspector)
|
||||
self.webkitinspector.setVisible(False)
|
||||
|
||||
# pages
|
||||
# self.pagenext_shortcut = QShortcut(QKeySequence(Qt.ControlModifier+Qt.ShiftModifier+Qt.Key_Right), self)
|
||||
# self.pagenext_shortcut.activated.connect(self.webviewtoolbar.onNextPage)
|
||||
# self.pageprev_shortcut = QShortcut(QKeySequence(Qt.ControlModifier+Qt.ShiftModifier+Qt.Key_Left), self)
|
||||
# self.pageprev_shortcut.activated.connect(self.webviewtoolbar.onPrevPage)
|
||||
|
||||
# zoom
|
||||
# self.zoomon_shortcut = QShortcut(QKeySequence(Qt.ControlModifier+Qt.Key_Plus), self)
|
||||
# self.zoomon_shortcut.activated.connect(self.webviewtoolbar.onZoomOn)
|
||||
# self.zoomout_shortcut = QShortcut(QKeySequence(Qt.ControlModifier+Qt.Key_Minus), self)
|
||||
# self.zoomout_shortcut.activated.connect(self.webviewtoolbar.onZoomOut)
|
||||
|
||||
|
||||
|
||||
def restorePrefs(self):
|
||||
settings = QSettings('FiguresLibres', 'Cascade')
|
||||
print(settings.value('design/vsplitter/sizes', self.vsplitter.sizes()))
|
||||
vals = settings.value('design/vsplitter/sizes', None)
|
||||
if vals:
|
||||
sizes = []
|
||||
for size in vals: sizes.append(int(size))
|
||||
self.vsplitter.setSizes(sizes)
|
||||
|
||||
vals = settings.value('design/hsplitter/sizes', None)
|
||||
if vals:
|
||||
sizes = []
|
||||
for size in vals: sizes.append(int(size))
|
||||
self.hsplitter.setSizes(sizes)
|
||||
|
||||
def movedSplitter(self):
|
||||
settings = QSettings('FiguresLibres', 'Cascade')
|
||||
# print(self.vsplitter.sizes())
|
||||
settings.setValue('design/vsplitter/sizes', self.vsplitter.sizes())
|
||||
settings.setValue('design/hsplitter/sizes', self.hsplitter.sizes())
|
||||
|
||||
def refresh(self):
|
||||
self.editor.refresh()
|
||||
self.webkitview.refresh()
|
||||
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# @Author: Bachir Soussi Chiadmi <bach>
|
||||
# @Date: 23-05-2017
|
||||
# @Email: bachir@figureslibres.io
|
||||
# @Last modified by: bach
|
||||
# @Last modified time: 03-06-2017
|
||||
# @License: GPL-V3
|
||||
|
||||
import os
|
||||
# from PyQt5.QtCore import QLine
|
||||
from PyQt5.QtGui import QIcon, QIntValidator
|
||||
from PyQt5.QtWidgets import QWidget, QLabel, QDialog, QGroupBox, QDialogButtonBox, QVBoxLayout, QHBoxLayout, QFormLayout, QLineEdit, QComboBox, QSpinBox, QFrame
|
||||
|
||||
class DocsetDialog(QDialog):
|
||||
def __init__(self, parent):
|
||||
super(DocsetDialog, self).__init__(parent)
|
||||
self.parent = parent
|
||||
self.createFormGroupBox()
|
||||
|
||||
buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
||||
buttonBox.accepted.connect(self.accept)
|
||||
buttonBox.rejected.connect(self.reject)
|
||||
|
||||
mainLayout = QVBoxLayout()
|
||||
mainLayout.addWidget(self.formGroupBox)
|
||||
mainLayout.addWidget(buttonBox)
|
||||
self.setLayout(mainLayout)
|
||||
|
||||
self.setWindowTitle("Document settings")
|
||||
|
||||
def createFormGroupBox(self):
|
||||
ds = self.parent.core.docsettings
|
||||
|
||||
self.formGroupBox = QWidget()
|
||||
vbox = QVBoxLayout()
|
||||
vbox.setContentsMargins(0,0,0,0)
|
||||
self.formGroupBox.setLayout(vbox)
|
||||
|
||||
topGroupBox = QWidget()
|
||||
topformlayout = QFormLayout()
|
||||
topformlayout.setContentsMargins(0,0,0,0)
|
||||
topGroupBox.setLayout(topformlayout)
|
||||
vbox.addWidget(topGroupBox)
|
||||
|
||||
colsGroupBox = QWidget()
|
||||
hbox = QHBoxLayout()
|
||||
hbox.setContentsMargins(0,0,0,0)
|
||||
colsGroupBox.setLayout(hbox)
|
||||
vbox.addWidget(colsGroupBox)
|
||||
|
||||
leftGroupBox = QGroupBox()
|
||||
leftformlayout = QFormLayout()
|
||||
# leftformlayout.setContentsMargins(0,0,0,0)
|
||||
leftGroupBox.setLayout(leftformlayout)
|
||||
hbox.addWidget(leftGroupBox)
|
||||
|
||||
rightGroupBox = QGroupBox()
|
||||
rightformlayout = QFormLayout()
|
||||
# rightformlayout.setContentsMargins(0,0,0,0)
|
||||
rightGroupBox.setLayout(rightformlayout)
|
||||
hbox.addWidget(rightGroupBox)
|
||||
|
||||
# headers
|
||||
self.headerOdd = QLineEdit(str(ds['ho']))
|
||||
topformlayout.addRow(QLabel("Header odd:"), self.headerOdd)
|
||||
self.headerEven = QLineEdit(str(ds['he']))
|
||||
topformlayout.addRow(QLabel("Header even:"), self.headerEven)
|
||||
|
||||
self.np = NumLineEdit(str(ds['np']),3,True)
|
||||
leftformlayout.addRow(QLabel("Numbers of Pages:"), self.np)
|
||||
#
|
||||
leftformlayout.addRow(Line(self))
|
||||
#
|
||||
self.pw = NumLineEdit(str(ds['pw']))
|
||||
leftformlayout.addRow(QLabel("Page Width (mm):"), self.pw)
|
||||
self.ph = NumLineEdit(str(ds['ph']))
|
||||
leftformlayout.addRow(QLabel("Page Height (mm):"), self.ph)
|
||||
#
|
||||
leftformlayout.addRow(Line(self))
|
||||
#
|
||||
self.mt = NumLineEdit(str(ds['mt']),3)
|
||||
leftformlayout.addRow(QLabel("Margin Top (mm):"), self.mt)
|
||||
self.mb = NumLineEdit(str(ds['mb']),3)
|
||||
leftformlayout.addRow(QLabel("Margin Bottom (mm):"), self.mb)
|
||||
self.mi = NumLineEdit(str(ds['mi']),3)
|
||||
leftformlayout.addRow(QLabel("Margin inner (mm):"), self.mi)
|
||||
self.me = NumLineEdit(str(ds['me']),3)
|
||||
leftformlayout.addRow(QLabel("Margin external (mm):"), self.me)
|
||||
|
||||
#
|
||||
self.cs = NumLineEdit(str(ds['cs']),3)
|
||||
rightformlayout.addRow(QLabel("Crop size (mm):"), self.cs)
|
||||
self.bs = NumLineEdit(str(ds['bs']),3)
|
||||
rightformlayout.addRow(QLabel("Bleed size (mm):"), self.bs)
|
||||
#
|
||||
rightformlayout.addRow(Line(self))
|
||||
#
|
||||
self.cn = NumLineEdit(str(ds['cn']),2,True)
|
||||
rightformlayout.addRow(QLabel("Columns number:"), self.cn)
|
||||
self.cg = NumLineEdit(str(ds['cg']),2)
|
||||
rightformlayout.addRow(QLabel("Columns gutters:"), self.cg)
|
||||
#
|
||||
self.rn = NumLineEdit(str(ds['rn']),2,True)
|
||||
rightformlayout.addRow(QLabel("Rows number:"), self.rn)
|
||||
self.rg = NumLineEdit(str(ds['rg']),2)
|
||||
rightformlayout.addRow(QLabel("Rows gutters:"), self.rg)
|
||||
#
|
||||
rightformlayout.addRow(Line(self))
|
||||
#
|
||||
self.lh = NumLineEdit(str(ds['lh']),2,True)
|
||||
rightformlayout.addRow(QLabel("Line height:"), self.lh)
|
||||
|
||||
# self.formGroupBox.setLayout(layout)
|
||||
|
||||
class NumLineEdit(QLineEdit):
|
||||
def __init__(self, parent, ml=5, int=False, mw=60):
|
||||
super(NumLineEdit, self).__init__(parent)
|
||||
self.setFixedWidth(mw)
|
||||
self.setMaxLength(ml)
|
||||
if int:
|
||||
self.setValidator(QIntValidator())
|
||||
else:
|
||||
# TODO: set float validator
|
||||
self.setValidator(QIntValidator())
|
||||
|
||||
class Line(QFrame):
|
||||
def __init__(self, parent):
|
||||
super(Line, self).__init__(parent)
|
||||
self.setFrameShape(QFrame.HLine)
|
||||
self.setFrameShadow(QFrame.Sunken)
|
||||
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# @Author: Bachir Soussi Chiadmi <bach>
|
||||
# @Date: 02-06-2017
|
||||
# @Email: bachir@figureslibres.io
|
||||
# @Filename: highlighter.py
|
||||
# @Last modified by: bach
|
||||
# @Last modified time: 03-06-2017
|
||||
# @License: GPL-V3
|
||||
|
||||
# based on code from :
|
||||
# Copyright (C) 2008 Christophe Kibleur <kib2@free.fr>
|
||||
|
||||
# TODO : see pyQode for more features https://github.com/pyQode
|
||||
|
||||
import sys
|
||||
import re
|
||||
# from PyQt5 import QtCore
|
||||
from PyQt5.QtGui import QColor, QTextCharFormat, QFont, QSyntaxHighlighter
|
||||
from pygments import highlight
|
||||
from pygments.lexers import *
|
||||
from pygments.formatter import Formatter
|
||||
from pygments.styles import get_all_styles, get_style_by_name
|
||||
# import time
|
||||
|
||||
|
||||
def hex2QColor(c):
|
||||
r=int(c[0:2],16)
|
||||
g=int(c[2:4],16)
|
||||
b=int(c[4:6],16)
|
||||
return QColor(r,g,b)
|
||||
|
||||
|
||||
class QFormatter(Formatter):
|
||||
def __init__(self, linenos=True, style="default"): #, style
|
||||
Formatter.__init__(self)
|
||||
self.data=[]
|
||||
self.style = get_style_by_name(style)
|
||||
# self.linenos = linenos
|
||||
|
||||
# Create a dictionary of text styles, indexed
|
||||
# by pygments token names, containing QTextCharFormat
|
||||
# instances according to pygments' description
|
||||
# of each style
|
||||
|
||||
self.styles={}
|
||||
for token, style in self.style:
|
||||
qtf=QTextCharFormat()
|
||||
|
||||
if style['color']:
|
||||
qtf.setForeground(hex2QColor(style['color']))
|
||||
if style['bgcolor']:
|
||||
qtf.setBackground(hex2QColor(style['bgcolor']))
|
||||
if style['bold']:
|
||||
qtf.setFontWeight(QFont.Bold)
|
||||
if style['italic']:
|
||||
qtf.setFontItalic(True)
|
||||
if style['underline']:
|
||||
qtf.setFontUnderline(True)
|
||||
|
||||
self.styles[str(token)]=qtf
|
||||
|
||||
def format(self, tokensource, outfile):
|
||||
global styles
|
||||
# We ignore outfile, keep output in a buffer
|
||||
self.data=[]
|
||||
|
||||
# Just store a list of styles, one for each character
|
||||
# in the input. Obviously a smarter thing with
|
||||
# offsets and lengths is a good idea!
|
||||
for ttype, value in tokensource:
|
||||
l=len(value)
|
||||
t=str(ttype)
|
||||
self.data.extend([self.styles[t],]*l)
|
||||
|
||||
|
||||
class Highlighter(QSyntaxHighlighter):
|
||||
|
||||
def __init__(self, parent, mode):
|
||||
QSyntaxHighlighter.__init__(self, parent)
|
||||
|
||||
# styles = list(get_all_styles())
|
||||
# print(styles)
|
||||
|
||||
# Keep the formatter and lexer, initializing them
|
||||
# may be costly.
|
||||
if not mode == "md":
|
||||
self.formatter=QFormatter(linenos=True, style="monokai")
|
||||
else:
|
||||
self.formatter=QFormatter(linenos=False, style="github")
|
||||
|
||||
self.lexer=get_lexer_by_name(mode)
|
||||
|
||||
def highlightBlock(self, text):
|
||||
"""Takes a block, applies format to the document.
|
||||
according to what's in it.
|
||||
"""
|
||||
|
||||
# I need to know where in the document we are,
|
||||
# because our formatting info is global to
|
||||
# the document
|
||||
cb = self.currentBlock()
|
||||
p = cb.position()
|
||||
|
||||
# The \n is not really needed, but sometimes
|
||||
# you are in an empty last block, so your position is
|
||||
# **after** the end of the document.
|
||||
text=str(self.document().toPlainText())+'\n'
|
||||
|
||||
# Yes, re-highlight the whole document.
|
||||
# There **must** be some optimizacion possibilities
|
||||
# but it seems fast enough.
|
||||
highlight(text,self.lexer,self.formatter)
|
||||
|
||||
# Just apply the formatting to this block.
|
||||
# For titles, it may be necessary to backtrack
|
||||
# and format a couple of blocks **earlier**.
|
||||
for i in range(len(str(text))):
|
||||
try:
|
||||
self.setFormat(i,1,self.formatter.data[p+i])
|
||||
except IndexError:
|
||||
pass
|
||||
@@ -0,0 +1,272 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# @Author: Bachir Soussi Chiadmi <bach>
|
||||
# @Date: 23-05-2017
|
||||
# @Email: bachir@figureslibres.io
|
||||
# @Last modified by: bach
|
||||
# @Last modified time: 03-06-2017
|
||||
# @License: GPL-V3
|
||||
|
||||
import os
|
||||
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtWidgets import QMainWindow, QAction, QWidget, QLabel, QStackedWidget, QFileDialog, QMessageBox
|
||||
|
||||
from classes import design, content, docsetdialog
|
||||
|
||||
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
def __init__(self, core):
|
||||
super(MainWindow, self).__init__()
|
||||
|
||||
# load core class
|
||||
self.core = core
|
||||
|
||||
self.setWindowTitle("Cascade")
|
||||
self.setWindowIcon(QIcon(os.path.join(self.core.appcwd,'assets/images/icon.png')))
|
||||
|
||||
self.resize(self.core.mw_size)
|
||||
self.move(self.core.mw_pos)
|
||||
|
||||
self.initMenuBar()
|
||||
|
||||
self.initMainStack()
|
||||
|
||||
self.show()
|
||||
|
||||
# __ ___ ____
|
||||
# / |/ /__ ____ __ __/ __ )____ ______
|
||||
# / /|_/ / _ \/ __ \/ / / / __ / __ `/ ___/
|
||||
# / / / / __/ / / / /_/ / /_/ / /_/ / /
|
||||
# /_/ /_/\___/_/ /_/\__,_/_____/\__,_/_/
|
||||
def initMenuBar(self):
|
||||
# menu bar
|
||||
bar = self.menuBar()
|
||||
file = bar.addMenu("&File")
|
||||
|
||||
new = QAction("&New Project",self)
|
||||
new.setShortcut("Ctrl+n")
|
||||
file.addAction(new)
|
||||
|
||||
open = QAction("&Open",self)
|
||||
open.setShortcut("Ctrl+o")
|
||||
file.addAction(open)
|
||||
|
||||
self.save_action = QAction("&Save Project as",self)
|
||||
self.save_action.setShortcut("Ctrl+Shift+s")
|
||||
file.addAction(self.save_action)
|
||||
|
||||
self.save_action = QAction("&Save Project as",self)
|
||||
self.save_action.setShortcut("Ctrl+Shift+s")
|
||||
file.addAction(self.save_action)
|
||||
|
||||
self.docset_action = QAction("&Document Settings",self)
|
||||
self.docset_action.setShortcut("Ctrl+d")
|
||||
file.addAction(self.docset_action)
|
||||
|
||||
self.pdf_action = QAction("&PDF",self)
|
||||
self.pdf_action.setShortcut("Ctrl+p")
|
||||
file.addAction(self.pdf_action)
|
||||
|
||||
self.quit_action = QAction("&Quit",self)
|
||||
self.quit_action.setShortcut("Ctrl+q")
|
||||
file.addAction(self.quit_action)
|
||||
|
||||
file.triggered[QAction].connect(self.onfilemenutrigger)
|
||||
|
||||
# edit menu
|
||||
edit = bar.addMenu("&Edit")
|
||||
# edit.addAction("©")
|
||||
# edit.addAction("&paste")
|
||||
edit.addAction("&build")
|
||||
|
||||
self.reload_action = QAction("&Reload",self)
|
||||
self.reload_action.setShortcut("Ctrl+r")
|
||||
edit.addAction(self.reload_action)
|
||||
|
||||
edit.addAction("&preferences")
|
||||
|
||||
edit.triggered[QAction].connect(self.oneditmenutrigger)
|
||||
|
||||
|
||||
# view menu
|
||||
view = bar.addMenu("&View")
|
||||
|
||||
designview = QAction("&Design",self)
|
||||
designview.setShortcut("F1")
|
||||
view.addAction(designview)
|
||||
|
||||
contentview = QAction("&Content",self)
|
||||
contentview.setShortcut("F2")
|
||||
view.addAction(contentview)
|
||||
|
||||
versionview = QAction("&Version",self)
|
||||
versionview.setShortcut("F3")
|
||||
view.addAction(versionview)
|
||||
|
||||
view.triggered[QAction].connect(self.onviewmenutrigger)
|
||||
|
||||
# about menu
|
||||
about = bar.addMenu("About")
|
||||
about.addAction("&Website")
|
||||
|
||||
def onfilemenutrigger(self, q):
|
||||
print(q.text()+" is triggered")
|
||||
if q.text() == "&New Project":
|
||||
self.newprojectdialogue()
|
||||
elif q.text() == "&Open":
|
||||
self.openprojectdialogue()
|
||||
elif q.text() == "&Save Project as":
|
||||
self.saveprojectdialogue()
|
||||
elif q.text() == "&Document Settings":
|
||||
self.onDocSettings()
|
||||
elif q.text() == "&PDF":
|
||||
self.genPDF()
|
||||
elif q.text() == "&Quit":
|
||||
self.quit()
|
||||
|
||||
def openprojectdialogue(self):
|
||||
print("open")
|
||||
dialog = QFileDialog()
|
||||
dialog.setFileMode(QFileDialog.Directory)
|
||||
dialog.setAcceptMode(QFileDialog.AcceptOpen)
|
||||
options = QFileDialog.DontResolveSymlinks | QFileDialog.ShowDirsOnly
|
||||
folder = dialog.getExistingDirectory(
|
||||
self,
|
||||
'Open Project',
|
||||
self.core.dialog_path,
|
||||
options
|
||||
)
|
||||
try:
|
||||
head, tail = os.path.split(folder)
|
||||
self.core.dialog_path = head
|
||||
# TODO: check if is cascade folder
|
||||
print(folder)
|
||||
if os.path.isdir(folder):
|
||||
self.core.openproject(folder)
|
||||
else:
|
||||
print("folder doesn't exists")
|
||||
except Exception as e:
|
||||
print('Exception', e)
|
||||
pass
|
||||
|
||||
def newprojectdialogue(self):
|
||||
dialog = QFileDialog()
|
||||
dialog.setFileMode(QFileDialog.Directory)
|
||||
dialog.setAcceptMode(QFileDialog.AcceptOpen)
|
||||
projectname = dialog.getSaveFileName(
|
||||
self,
|
||||
'New Project',
|
||||
self.core.dialog_path
|
||||
)[0]
|
||||
# TODO: no file type
|
||||
try:
|
||||
head, tail = os.path.split(projectname)
|
||||
self.core.dialog_path = head
|
||||
if not os.path.isdir(projectname):
|
||||
self.core.initnewproject(projectname)
|
||||
else:
|
||||
print("folder already exists")
|
||||
# TODO: check if is cascade folder
|
||||
except Exception as e:
|
||||
print('Exception', e)
|
||||
pass
|
||||
|
||||
def saveprojectdialogue(self, quit=False):
|
||||
dialog = QFileDialog()
|
||||
dialog.setFileMode(QFileDialog.Directory)
|
||||
dialog.setAcceptMode(QFileDialog.AcceptOpen)
|
||||
projectname = dialog.getSaveFileName(
|
||||
self,
|
||||
'Save Project',
|
||||
self.core.dialog_path
|
||||
)[0]
|
||||
# TODO: no file type
|
||||
try:
|
||||
head, tail = os.path.split(projectname)
|
||||
self.core.dialog_path = head
|
||||
if not os.path.isdir(projectname):
|
||||
self.core.saveproject(projectname)
|
||||
if quit:
|
||||
self.quit()
|
||||
else:
|
||||
print("folder already exists")
|
||||
# TODO: check if is cascade folder
|
||||
except Exception as e:
|
||||
print('Exception', e)
|
||||
pass
|
||||
|
||||
def onDocSettings(self):
|
||||
d = docsetdialog.DocsetDialog(self)
|
||||
d.exec_()
|
||||
self.core.recordDocSettings({
|
||||
"ho":d.headerOdd.text(),
|
||||
"he":d.headerEven.text(),
|
||||
"np":d.np.text(),
|
||||
"pw":d.pw.text(),
|
||||
"ph":d.ph.text(),
|
||||
"mt":d.mt.text(),
|
||||
"mb":d.mb.text(),
|
||||
"me":d.me.text(),
|
||||
"mi":d.mi.text(),
|
||||
"cs":d.cs.text(),
|
||||
"bs":d.bs.text(),
|
||||
"cn":d.cn.text(),
|
||||
"cg":d.cg.text(),
|
||||
"rn":d.rn.text(),
|
||||
"rg":d.rg.text(),
|
||||
"lh":d.lh.text()
|
||||
})
|
||||
|
||||
def genPDF(self):
|
||||
print('PDF')
|
||||
self.designstack.webkitview.ongenPDF()
|
||||
|
||||
def quit(self):
|
||||
print("Quit")
|
||||
if self.core.tempcwd:
|
||||
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)
|
||||
if buttonReply == QMessageBox.Yes:
|
||||
self.saveprojectdialogue(quit=True)
|
||||
if buttonReply == QMessageBox.No:
|
||||
self.core.quit()
|
||||
else:
|
||||
self.core.quit()
|
||||
|
||||
def oneditmenutrigger(self, q):
|
||||
print(q.text()+" is triggered")
|
||||
if q.text() == "&Reload":
|
||||
self.designstack.webkitview.reload()
|
||||
|
||||
def onviewmenutrigger(self, q):
|
||||
print(q.text()+" is triggered")
|
||||
if q.text() == "&Design":
|
||||
self.mainstack.setCurrentIndex(0)
|
||||
elif q.text() == "&Content":
|
||||
self.mainstack.setCurrentIndex(1)
|
||||
elif q.text() == "&Version":
|
||||
self.mainstack.setCurrentIndex(2)
|
||||
|
||||
# __ ___ _ _____ __ __
|
||||
# / |/ /___ _(_)___ / ___// /_____ ______/ /__
|
||||
# / /|_/ / __ `/ / __ \\__ \/ __/ __ `/ ___/ //_/
|
||||
# / / / / /_/ / / / / /__/ / /_/ /_/ / /__/ ,<
|
||||
# /_/ /_/\__,_/_/_/ /_/____/\__/\__,_/\___/_/|_|
|
||||
def initMainStack(self):
|
||||
self.mainstack = QStackedWidget()
|
||||
|
||||
self.designstack = design.DesignStack(self.core)
|
||||
self.contentstack = content.ContentStack(self.core)
|
||||
self.versionstack = QLabel("Version (git).")
|
||||
|
||||
self.mainstack.addWidget(self.designstack)
|
||||
self.mainstack.addWidget(self.contentstack)
|
||||
self.mainstack.addWidget(self.versionstack)
|
||||
|
||||
self.mainstack.setCurrentIndex(self.core.mw_curstack)
|
||||
|
||||
# TODO: add an app console window (show sass compilation errors for example)
|
||||
|
||||
self.setCentralWidget(self.mainstack)
|
||||
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# @Author: Bachir Soussi Chiadmi <bach>
|
||||
# @Date: 23-05-2017
|
||||
# @Email: bachir@figureslibres.io
|
||||
# @Filename: md2html.py
|
||||
# @Last modified by: bach
|
||||
# @Last modified time: 03-06-2017
|
||||
# @License: GPL-V3
|
||||
|
||||
import os
|
||||
import re
|
||||
from PyQt5.QtCore import QFileSystemWatcher
|
||||
import json
|
||||
from bs4 import BeautifulSoup
|
||||
import pypandoc
|
||||
|
||||
|
||||
class Compiler():
|
||||
def __init__(self,core):
|
||||
self.core = core
|
||||
self.initWatching()
|
||||
self.compileContents()
|
||||
|
||||
def initWatching(self):
|
||||
self.refreshPaths()
|
||||
self.fs_watcher = QFileSystemWatcher(self.paths)
|
||||
# self.fs_watcher.directoryChanged.connect(self.directory_changed)
|
||||
self.fs_watcher.fileChanged.connect(self.onMdFileChanged)
|
||||
|
||||
def onMdFileChanged(self):
|
||||
print("onMdFileChanged")
|
||||
try:
|
||||
self.compileContents()
|
||||
except Exception as e:
|
||||
print("Error compiling MD files", e)
|
||||
pass
|
||||
|
||||
def refreshPaths(self):
|
||||
jsonfilepath = os.path.join(self.core.cwd,'.config/summary.json')
|
||||
sum_json = open(jsonfilepath).read()
|
||||
self.sum = json.loads(sum_json)
|
||||
|
||||
self.paths = [os.path.join(self.core.cwd,'contents')]
|
||||
for item in self.sum:
|
||||
self.paths.append(os.path.join(self.core.cwd,'contents',item['file']))
|
||||
|
||||
def reload(self):
|
||||
self.fs_watcher.removePaths(self.paths)
|
||||
self.refreshPaths()
|
||||
self.fs_watcher.addPaths(self.paths)
|
||||
self.compileContents()
|
||||
|
||||
def compileContents(self):
|
||||
print('Compiling md')
|
||||
|
||||
# create main html dom from template
|
||||
template_f = open(os.path.join(self.core.appcwd,"templates/main.tpl.html"), "r")
|
||||
template_html = template_f.read()
|
||||
template_dom = BeautifulSoup(template_html, 'html.parser')
|
||||
|
||||
# get story div
|
||||
story_dom = template_dom.find('div', {"id":"flow-main"})
|
||||
|
||||
pi = 0
|
||||
for p in self.sum:
|
||||
# print(toc[p])
|
||||
pagename = p['title']
|
||||
pageid = re.sub('[^a-z0-9]+', '-', pagename.lower())
|
||||
print(pageid)
|
||||
|
||||
# files
|
||||
in_f = os.path.join(self.core.cwd, "contents", p['file'])
|
||||
if not os.path.isfile(in_f):
|
||||
print("Source path is not a file, can't generate html : "+in_f)
|
||||
continue
|
||||
# print('in_f : '+in_f)
|
||||
|
||||
pdoc_args = ['--mathjax',
|
||||
'--smart']
|
||||
|
||||
pdoc_filters = []
|
||||
|
||||
output = pypandoc.convert_file(in_f,
|
||||
to='html5',
|
||||
format='markdown+header_attributes+link_attributes+bracketed_spans',
|
||||
extra_args=pdoc_args,
|
||||
filters=pdoc_filters)
|
||||
|
||||
output_dom = BeautifulSoup(output, 'html.parser')
|
||||
|
||||
# TODO: hyphenate paragraph
|
||||
|
||||
# append html story page to template_dom
|
||||
story_page = BeautifulSoup(
|
||||
'<div class="story-page story-page-'+str(pi)+'" id="'+pageid+'"></div>',
|
||||
'html.parser'
|
||||
)
|
||||
story_page.div.append(output_dom)
|
||||
story_dom.append(story_page)
|
||||
|
||||
|
||||
pi = pi+1
|
||||
|
||||
# create main html file from filled template html dom
|
||||
book_html_f = os.path.join(self.core.cwd,'index.html')
|
||||
with open(book_html_f, 'w') as fp:
|
||||
fp.write(template_dom.prettify())
|
||||
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# @Author: Bachir Soussi Chiadmi <bach>
|
||||
# @Date: 30-05-2017
|
||||
# @Email: bachir@figureslibres.io
|
||||
# @Filename: sasscompiler.py
|
||||
# @Last modified by: bach
|
||||
# @Last modified time: 03-06-2017
|
||||
# @License: GPL-V3
|
||||
|
||||
|
||||
import os
|
||||
from PyQt5.QtCore import QFileSystemWatcher
|
||||
import sass
|
||||
|
||||
class Compiler():
|
||||
def __init__(self,parent):
|
||||
self.parent = parent
|
||||
self.initWatching()
|
||||
self.compile_scss()
|
||||
# def directory_changed(path):
|
||||
# print("Directory changed : %s" % path)
|
||||
|
||||
def initWatching(self):
|
||||
self.refreshPaths()
|
||||
self.fs_watcher = QFileSystemWatcher(self.paths)
|
||||
# self.fs_watcher.directoryChanged.connect(self.directory_changed)
|
||||
self.fs_watcher.fileChanged.connect(self.compile_scss)
|
||||
|
||||
def compile_scss(self):
|
||||
print("compiling sass")
|
||||
try:
|
||||
scss = sass.compile_file(str.encode(os.path.join(self.parent.cwd,'assets/css/main.scss')))
|
||||
with open(os.path.join(self.parent.cwd,'assets/css/main.css'), 'w') as fp:
|
||||
fp.write(scss.decode('utf8'))
|
||||
except Exception as e:
|
||||
print("Error compiling Sass", e)
|
||||
pass
|
||||
|
||||
|
||||
def refreshPaths(self):
|
||||
self.paths = [
|
||||
os.path.join(self.parent.cwd,'assets'),
|
||||
os.path.join(self.parent.cwd,'assets/css')
|
||||
]
|
||||
# os.path.join(self.parent.cwd,'assets/css/styles.scss')
|
||||
for f in os.listdir(os.path.join(self.parent.cwd,'assets/css')):
|
||||
if f.endswith("scss"):
|
||||
self.paths.append(os.path.join(self.parent.cwd,'assets/css',f))
|
||||
|
||||
def reload(self):
|
||||
print('Reload sass compiler')
|
||||
self.fs_watcher.removePaths(self.paths)
|
||||
self.refreshPaths()
|
||||
print('paths', self.paths)
|
||||
self.fs_watcher.addPaths(self.paths)
|
||||
print('files', self.fs_watcher.files())
|
||||
self.compile_scss()
|
||||
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# @Author: Bachir Soussi Chiadmi <bach>
|
||||
# @Date: 23-05-2017
|
||||
# @Email: bachir@figureslibres.io
|
||||
# @Filename: server.py
|
||||
# @Last modified by: bach
|
||||
# @Last modified time: 03-06-2017
|
||||
# @License: GPL-V3
|
||||
|
||||
import sys, os
|
||||
from socket import socket
|
||||
import socketserver
|
||||
import http.server
|
||||
import threading
|
||||
|
||||
class Server():
|
||||
def __init__(self, parent):
|
||||
|
||||
self.parent = parent
|
||||
# find free port
|
||||
sock = socket()
|
||||
sock.bind(('', 0))
|
||||
|
||||
self._port = sock.getsockname()[1]
|
||||
sock.close()
|
||||
|
||||
# self.initial_cwd = os.getcwd()
|
||||
self.thread = threading.Thread(target=self.webserver)
|
||||
self.thread.daemon = True
|
||||
self.thread.start()
|
||||
# os.chdir(self.initial_cwd)
|
||||
|
||||
def webserver(self):
|
||||
os.chdir(self.parent.cwd)
|
||||
self.httpd = http.server.HTTPServer(('', self.port), http.server.SimpleHTTPRequestHandler)
|
||||
self.httpd.serve_forever()
|
||||
print("serving at port", self._port)
|
||||
|
||||
@property
|
||||
def port(self):
|
||||
return self._port
|
||||
|
||||
def reload(self):
|
||||
# self.thread.shutdown()
|
||||
os.chdir(self.parent.cwd)
|
||||
# self.thread.start()
|
||||
# os.chdir(self.initial_cwd)
|
||||
Reference in New Issue
Block a user