renamed package to libriis

This commit is contained in:
Bachir Soussi Chiadmi
2017-06-08 22:39:33 +02:00
parent a136863d25
commit dc1d2ec48e
39 changed files with 56 additions and 63 deletions
View File
+312
View File
@@ -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()
+264
View File
@@ -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()
+494
View File
@@ -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()
+134
View File
@@ -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)
+125
View File
@@ -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
+274
View File
@@ -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("&copy")
# 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)
+111
View File
@@ -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())
+60
View File
@@ -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()
+51
View File
@@ -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)