renamed package to libriis
This commit is contained in:
@@ -0,0 +1,312 @@
|
||||
#!/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
|
||||
|
||||
from __future__ import absolute_import, print_function, division, unicode_literals
|
||||
|
||||
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 . 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', 'Libriis')
|
||||
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', 'Libriis')
|
||||
# print(self.hsplitter.sizes())
|
||||
settings.setValue('content/hsplitter/sizes', self.hsplitter.sizes())
|
||||
|
||||
def refresh(self):
|
||||
self.summary.reload()
|
||||
self.editor.openFile()
|
||||
@@ -0,0 +1,264 @@
|
||||
#!/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
|
||||
|
||||
from __future__ import absolute_import, print_function, division, unicode_literals
|
||||
|
||||
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 . import server, sasscompiler, md2html
|
||||
|
||||
# ______
|
||||
# / ____/___ ________
|
||||
# / / / __ \/ ___/ _ \
|
||||
# / /___/ /_/ / / / __/
|
||||
# \____/\____/_/ \___/
|
||||
class Core():
|
||||
def __init__(self, apppath):
|
||||
# restore previous preferences
|
||||
self.appcwd = apppath
|
||||
|
||||
self.restorePreferences()
|
||||
self._mw = False
|
||||
self.temp = tempfile.mkdtemp()
|
||||
# print(self.temp)
|
||||
self.projectname = "Libriis"
|
||||
|
||||
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("Libriis – "+self.cwd)
|
||||
|
||||
# ____ ____
|
||||
# / __ \________ / __/____
|
||||
# / /_/ / ___/ _ \/ /_/ ___/
|
||||
# / ____/ / / __/ __(__ )
|
||||
# /_/ /_/ \___/_/ /____/
|
||||
def restorePreferences(self):
|
||||
# print("restorePreferences")
|
||||
settings = QSettings('FiguresLibres', 'Libriis')
|
||||
# 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', 'Libriis')
|
||||
# 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: "Libriis, default header";
|
||||
sass = re.sub(
|
||||
r'\$header-odd:\s".+";',
|
||||
'$header-odd: "'+self.docsettings['ho']+'";',
|
||||
sass)
|
||||
# $header-even: "Libriis, 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("Libriis – "+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,494 @@
|
||||
#!/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
|
||||
|
||||
from __future__ import absolute_import, print_function, division, unicode_literals
|
||||
|
||||
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 . 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('Libriis')
|
||||
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: /"+str(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', 'Libriis')
|
||||
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', 'Libriis')
|
||||
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', 'Libriis')
|
||||
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', 'Libriis')
|
||||
# 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,134 @@
|
||||
#!/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
|
||||
|
||||
from __future__ import absolute_import, print_function, division, unicode_literals
|
||||
|
||||
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,125 @@
|
||||
#!/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
|
||||
|
||||
from __future__ import absolute_import, print_function, division, unicode_literals
|
||||
|
||||
|
||||
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,274 @@
|
||||
#!/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
|
||||
|
||||
from __future__ import absolute_import, print_function, division, unicode_literals
|
||||
|
||||
import os
|
||||
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtWidgets import QMainWindow, QAction, QWidget, QLabel, QStackedWidget, QFileDialog, QMessageBox
|
||||
|
||||
from . import design, content, docsetdialog
|
||||
|
||||
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
def __init__(self, core):
|
||||
super(MainWindow, self).__init__()
|
||||
|
||||
# load core class
|
||||
self.core = core
|
||||
|
||||
self.setWindowTitle("Libriis")
|
||||
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 libriis 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 libriis 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 libriis 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,111 @@
|
||||
#!/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
|
||||
|
||||
from __future__ import absolute_import, print_function, division, unicode_literals
|
||||
|
||||
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,60 @@
|
||||
#!/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
|
||||
|
||||
from __future__ import absolute_import, print_function, division, unicode_literals
|
||||
|
||||
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,51 @@
|
||||
#!/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
|
||||
|
||||
from __future__ import absolute_import, print_function, division, unicode_literals
|
||||
|
||||
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