Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Moved all sub-modules to a root package "tikz_editor".

  • Loading branch information...
commit 5e370681d272abe48fffebdc87ea165534967ce7 1 parent dc521f5
@mickael-menu mickael-menu authored
Showing with 909 additions and 848 deletions.
  1. +2 −2 Makefile
  2. +0 −7 resources/resources.qrc
  3. +6 −38 tikz_editor.pyw
  4. +48 −0 tikz_editor/__init__.py
  5. +4 −4 { → tikz_editor}/controllers/__init__.py
  6. +8 −7 { → tikz_editor}/controllers/about.py
  7. +40 −41 { → tikz_editor}/controllers/app.py
  8. +16 −16 { → tikz_editor}/controllers/document.py
  9. +15 −15 { → tikz_editor}/controllers/documents.py
  10. +22 −17 { → tikz_editor}/controllers/errors.py
  11. +15 −14 { → tikz_editor}/controllers/factory.py
  12. +19 −18 { → tikz_editor}/controllers/preferences.py
  13. +15 −14 { → tikz_editor}/controllers/preview.py
  14. +5 −5 { → tikz_editor}/globals/__init__.py
  15. +4 −4 { → tikz_editor}/globals/actions.py
  16. +6 −6 { → tikz_editor}/globals/defaults.py
  17. +4 −4 { → tikz_editor}/globals/editor.py
  18. +3 −3 { → tikz_editor}/models/__init__.py
  19. +21 −19 { → tikz_editor}/models/document.py
  20. +6 −5 { → tikz_editor}/models/factory.py
  21. +92 −91 { → tikz_editor}/models/preferences.py
  22. +1 −1  { → tikz_editor}/resources/__init__.py
  23. 0  {resources → tikz_editor/resources/html}/about.html
  24. 0  {resources → tikz_editor/resources/images}/icon.icns
  25. 0  {resources → tikz_editor/resources/images}/icon.png
  26. 0  {resources → tikz_editor/resources/images}/icon.pxm
  27. 0  {resources → tikz_editor/resources/images}/icon_about.png
  28. +7 −0 tikz_editor/resources/resources.qrc
  29. +10 −6 { → tikz_editor}/tools/__init__.py
  30. +14 −8 { → tikz_editor}/tools/documentIO/__init__.py
  31. +15 −15 { → tikz_editor}/tools/documentIO/reader.py
  32. +4 −4 { → tikz_editor}/tools/documentIO/tags.py
  33. +8 −8 { → tikz_editor}/tools/documentIO/template.py
  34. +29 −26 { → tikz_editor}/tools/file.py
  35. +3 −3 { → tikz_editor}/tools/latex2image/__init__.py
  36. +22 −22 { → tikz_editor}/tools/latex2image/converter.py
  37. +25 −24 { → tikz_editor}/tools/latex2image/logs_parser.py
  38. +3 −3 { → tikz_editor}/tools/qt/__init__.py
  39. +6 −5 { → tikz_editor}/tools/qt/actions.py
  40. +8 −8 { → tikz_editor}/tools/qt/dialogs.py
  41. +8 −7 { → tikz_editor}/tools/qt/toolbar.py
  42. +11 −9 { → tikz_editor}/tools/temp_dir.py
  43. +3 −3 { → tikz_editor}/views/__init__.py
  44. +11 −10 { → tikz_editor}/views/about.py
  45. +20 −21 { → tikz_editor}/views/document/__init__.py
  46. +18 −17 { → tikz_editor}/views/document/content.py
  47. +18 −17 { → tikz_editor}/views/document/feedback/__init__.py
  48. +12 −10 { → tikz_editor}/views/document/feedback/errors.py
  49. +10 −9 { → tikz_editor}/views/document/feedback/logs.py
  50. +19 −18 { → tikz_editor}/views/document/preview.py
  51. +13 −12 { → tikz_editor}/views/document/properties.py
  52. +74 −73 { → tikz_editor}/views/editor.py
  53. +21 −20 { → tikz_editor}/views/factory.py
  54. +22 −21 { → tikz_editor}/views/preferences/__init__.py
  55. +24 −23 { → tikz_editor}/views/preferences/document.py
  56. +46 −45 { → tikz_editor}/views/preferences/editor.py
  57. +31 −30 { → tikz_editor}/views/preferences/preview.py
  58. +42 −40 { → tikz_editor}/views/preferences/snippets.py
View
4 Makefile
@@ -15,9 +15,9 @@
PYRCC = pyrcc4
-all: resources/__init__.py
+all: tikz_editor/resources/__init__.py
# Builds the resources module using PyQt's pyrcc4.
# see: http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/resources.html
-resources/__init__.py: resources/resources.qrc
+tikz_editor/resources/__init__.py: tikz_editor/resources/resources.qrc
$(PYRCC) -o $@ $<
View
7 resources/resources.qrc
@@ -1,7 +0,0 @@
-<!DOCTYPE RCC>
-<RCC version="1.0">
- <qresource>
- <file>icon_about.png</file>
- <file>about.html</file>
- </qresource>
-</RCC>
View
44 tikz_editor.pyw
@@ -1,53 +1,21 @@
#!/usr/bin/env python
# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
-import os
-import sys
-import atexit # necessary for pyinstaller deployment
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
+import tikz_editor
-from controllers import ControllerFactory
-from tools import isMacintoshComputer
-import globals
-
-__version__ = globals.VERSION
-__author__ = globals.AUTHORS
-def main():
- app = QApplication(sys.argv)
- app.setOrganizationName(globals.ORGANIZATION_NAME)
- app.setOrganizationDomain(globals.ORGANIZATION_DOMAIN)
- app.setApplicationName(globals.APPLICATION_NAME)
-
- if isMacintoshComputer():
- # add /opt/local/bin to PATH to find pdflatex binary -- useful for Mac plateform using Macports
- os.environ['PATH'] = os.environ.get('PATH', '/usr/bin') + ':/opt/local/bin'
- app.setQuitOnLastWindowClosed(False)
-
- app_controller = ControllerFactory.createAppController()
-
- args = app.arguments()[1:]
- if len(args) > 0:
- for file_path in args:
- app_controller.open(file_path)
- else:
- app_controller.new()
-
- app.exec_()
- app_controller.quit()
-
-main()
+if __name__ == '__main__':
+ tikz_editor.start()
View
48 tikz_editor/__init__.py
@@ -0,0 +1,48 @@
+# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import sys
+import atexit # necessary for pyinstaller deployment
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+
+from tikz_editor.controllers import ControllerFactory
+from tikz_editor.tools import isMacintoshComputer
+import tikz_editor.globals as globals
+
+
+def start():
+ app = QApplication(sys.argv)
+ app.setOrganizationName(globals.ORGANIZATION_NAME)
+ app.setOrganizationDomain(globals.ORGANIZATION_DOMAIN)
+ app.setApplicationName(globals.APPLICATION_NAME)
+
+ if isMacintoshComputer():
+ # add /opt/local/bin to PATH to find pdflatex binary -- useful for Mac plateform using Macports
+ os.environ['PATH'] = os.environ.get('PATH', '/usr/bin') + ':/opt/local/bin'
+ app.setQuitOnLastWindowClosed(False)
+
+ app_controller = ControllerFactory.createAppController()
+
+ args = app.arguments()[1:]
+ if len(args) > 0:
+ for file_path in args:
+ app_controller.open(file_path)
+ else:
+ app_controller.new()
+
+ app.exec_()
+ app_controller.quit()
View
8 controllers/__init__.py → tikz_editor/controllers/__init__.py
@@ -1,18 +1,18 @@
# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
from factory import ControllerFactory
-__all__ = ['ControllerFactory']
+__all__ = ['ControllerFactory']
View
15 controllers/about.py → tikz_editor/controllers/about.py
@@ -1,22 +1,23 @@
# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt4.QtCore import *
-import resources
-from tools import File
+import tikz_editor.resources
+from tikz_editor.tools import File
+
class AboutController(QObject):
"""
@@ -26,7 +27,7 @@ def __init__(self):
super(AboutController, self).__init__()
self.view = None
self.app_controller = None
-
+
def initController(self):
self.view.setImage(":/icon_about.png")
self.view.setInfoHTML(File.readContentFromFilePath(":/about.html"))
@@ -34,4 +35,4 @@ def initController(self):
@pyqtSlot()
def showAbout(self):
self.view.show()
- self.view.raise_()
+ self.view.raise_()
View
81 controllers/app.py → tikz_editor/controllers/app.py
@@ -1,36 +1,35 @@
# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
-import os
-
from PyQt4.QtCore import *
from PyQt4.QtGui import *
-import globals.actions as actions
-from models import Preferences
-from views import DocumentView
-from views.editor import EditorView
-from tools import addToClipboard, isMacintoshComputer
-from tools import File, TemporaryDirectory
-from tools.qt import ActionFactory, Dialogs
+import tikz_editor.globals.actions as actions
+from tikz_editor.models import Preferences
+from tikz_editor.views import DocumentView
+from tikz_editor.views.editor import EditorView
+from tikz_editor.tools import addToClipboard, isMacintoshComputer
+from tikz_editor.tools import File, TemporaryDirectory
+from tikz_editor.tools.qt import ActionFactory, Dialogs
+
class AppController(QObject):
"""
The application controller is directing all the user actions to sub-controllers.
"""
-
+
def __init__(self):
super(AppController, self).__init__()
self.about_controller = None
@@ -38,7 +37,7 @@ def __init__(self):
self.preferences_controller = None
self.actions = {}
self.menu_bar = None
-
+
def initController(self):
self._createActions()
self._createMenuBar()
@@ -63,18 +62,17 @@ def _createActions(self):
self.actions[actions.SAVE_ALL] = ActionFactory.createAction(self, "Save All", "Save all documents", None, self.saveAll)
self.actions[actions.SAVE_AS] = ActionFactory.createAction(self, "Save As...", "Save the document as...", QKeySequence.SaveAs, self.saveAs)
self.actions[actions.UNDO] = ActionFactory.createAction(self, "Undo", "Undo last action", QKeySequence.Undo, self.undo)
-
+
def _createMenuBar(self):
self.menu_bar = QMenuBar()
self._createFileMenu()
self._createEditMenu()
-
+
# set menu bar of about and preferences windows if we're not on Mac OS X
if not isMacintoshComputer():
self.preferences_controller.view.setMenuBar(self.menu_bar)
self.about_controller.view.setMenuBar(self.menu_bar)
-
def _createFileMenu(self):
file_menu = self.menu_bar.addMenu("File")
ordered_actions = (
@@ -93,7 +91,7 @@ def _createFileMenu(self):
self.actions[actions.QUIT]
)
ActionFactory.addActionsToMenu(ordered_actions, file_menu)
-
+
def _createEditMenu(self):
edit_menu = self.menu_bar.addMenu("Edit")
ordered_actions = (
@@ -102,13 +100,13 @@ def _createEditMenu(self):
None,
self.actions[actions.CUT]
)
- ActionFactory.addActionsToMenu(ordered_actions, edit_menu)
+ ActionFactory.addActionsToMenu(ordered_actions, edit_menu)
self._createCopyMenu(edit_menu)
ActionFactory.addActionsToMenu((self.actions[actions.PASTE], None), edit_menu)
self._createSnippetsMenu(edit_menu)
-
+
def _createCopyMenu(self, edit_menu):
- copy_menu = edit_menu.addMenu("Copy")
+ copy_menu = edit_menu.addMenu("Copy")
ordered_actions = (
self.actions[actions.COPY],
self.actions[actions.COPY_SOURCE],
@@ -117,11 +115,11 @@ def _createCopyMenu(self, edit_menu):
)
ActionFactory.addActionsToMenu(ordered_actions, copy_menu)
self.actions[actions.COPY_MENU] = copy_menu
-
+
def _createSnippetsMenu(self, edit_menu):
self.actions[actions.SNIPPETS_MENU] = edit_menu.addMenu("Insert Snippets")
self.loadSnippets()
-
+
def loadSnippets(self):
snippets_menu = self.actions[actions.SNIPPETS_MENU]
snippets_menu.clear()
@@ -131,7 +129,7 @@ def loadSnippets(self):
action = ActionFactory.createAction(self, snippet_name, "Insert \"%s\" Snippet" % snippet_name, None, self.insertSnippet)
action.setData(QVariant(snippet_code))
snippets_menu.addAction(action)
-
+
@property
def focused_document(self):
"""
@@ -147,7 +145,7 @@ def documentHasFocus(self):
"""
active_window = QApplication.activeWindow()
return isinstance(active_window, DocumentView)
-
+
def _doActionOnFocusedWidget(self, action):
try:
widget = QApplication.focusWidget()
@@ -165,7 +163,7 @@ def about(self):
self.about_controller.showAbout()
except Exception, e:
Dialogs.showError(e)
-
+
@pyqtSlot()
def close(self):
try:
@@ -174,11 +172,11 @@ def close(self):
active_window.close()
except Exception, e:
Dialogs.showError(e)
-
+
@pyqtSlot()
def copy(self):
self._doActionOnFocusedWidget("copy")
-
+
@pyqtSlot()
def copySource(self):
try:
@@ -188,7 +186,7 @@ def copySource(self):
QApplication.beep()
except Exception, e:
Dialogs.showError(e)
-
+
@pyqtSlot()
def copyPreamble(self):
try:
@@ -198,7 +196,7 @@ def copyPreamble(self):
QApplication.beep()
except Exception, e:
Dialogs.showError(e)
-
+
@pyqtSlot()
def copyPreambleAndSource(self):
try:
@@ -208,18 +206,18 @@ def copyPreambleAndSource(self):
QApplication.beep()
except Exception, e:
Dialogs.showError(e)
-
+
@pyqtSlot()
def cut(self):
self._doActionOnFocusedWidget("cut")
-
+
@pyqtSlot()
def new(self):
try:
self.documents_controller.openEmptyDocument()
except Exception, e:
Dialogs.showError(e)
-
+
@pyqtSlot()
def open(self, file_path=None):
try:
@@ -236,11 +234,12 @@ def paste(self):
@pyqtSlot()
def showPreferences(self):
+
try:
self.preferences_controller.showPreferences()
except Exception, e:
Dialogs.showError(e)
-
+
@pyqtSlot()
def preview(self):
try:
@@ -250,11 +249,11 @@ def preview(self):
QApplication.beep()
except Exception, e:
Dialogs.showError(e)
-
+
@pyqtSlot()
def redo(self):
self._doActionOnFocusedWidget("redo")
-
+
@pyqtSlot()
def quit(self):
try:
@@ -273,14 +272,14 @@ def save(self):
QApplication.beep()
except Exception, e:
Dialogs.showError(e)
-
+
@pyqtSlot()
def saveAll(self):
try:
self.documents_controller.saveAllDocuments()
except Exception, e:
Dialogs.showError(e)
-
+
@pyqtSlot()
def saveAs(self):
try:
@@ -290,11 +289,11 @@ def saveAs(self):
QApplication.beep()
except Exception, e:
Dialogs.showError(e)
-
+
@pyqtSlot()
def undo(self):
self._doActionOnFocusedWidget("undo")
-
+
@pyqtSlot()
def insertSnippet(self):
try:
@@ -306,4 +305,4 @@ def insertSnippet(self):
else:
QApplication.beep()
except Exception, e:
- Dialogs.showError(e)
+ Dialogs.showError(e)
View
32 controllers/document.py → tikz_editor/controllers/document.py
@@ -1,23 +1,23 @@
# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt4.QtCore import *
from PyQt4.QtGui import *
-from tools import File
-from tools.qt import Dialogs
+from tikz_editor.tools import File
+
class DocumentController(QObject):
"""
@@ -26,22 +26,22 @@ class DocumentController(QObject):
figurePreviewOutOfSyncSignal = pyqtSignal()
figurePreviewChangedSignal = pyqtSignal(str, list)
documentClosedSignal = pyqtSignal(object)
-
+
def __init__(self):
super(DocumentController, self).__init__()
- self.app_controller = None
+ self.app_controller = None
self.errors_controller = None
self.preview_controller = None
self.model = None
self.view = None
-
+
def initController(self):
- assert self.model and self.view
+ assert self.model and self.view
self._connectViewAndModel()
self._syncViewAndModel()
if not self.model.isEmpty():
self.preview_controller.updatePreview()
-
+
def _connectViewAndModel(self):
self.view.sourceChangedSignal.connect(self.model.setSource)
self.view.preambleChangedSignal.connect(self.model.setPreamble)
@@ -60,15 +60,15 @@ def _syncViewAndModel(self):
self.view.preamble = self.model.preamble
self.view.source = self.model.source
self.view.title = self.model.title
-
+
def showView(self):
self.view.show()
self.view.raise_()
-
+
@pyqtSlot()
def preview(self):
self.preview_controller.updatePreview()
-
+
@pyqtSlot()
def close(self):
self.preview_controller.abortPreview()
@@ -88,9 +88,9 @@ def saveAs(self):
if file_path:
self.model.file_path = file_path
self.model.save()
-
+
def _getDocumentFileName(self):
file_name = self.model.file_path
if not file_name:
- file_name = "%s.tex" % self.model.title
- return file_name
+ file_name = "%s.tex" % self.model.title
+ return file_name
View
30 controllers/documents.py → tikz_editor/controllers/documents.py
@@ -1,40 +1,40 @@
# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt4.QtCore import *
from PyQt4.QtGui import *
-import controllers.factory
-from app import AppController
+import factory
+
class DocumentsController(object):
"""
This is the documents manager. It keeps a list of all opened documents and can open
new or existing documents.
"""
-
+
def __init__(self):
super(DocumentsController, self).__init__()
self.app_controller = None
self.documents = []
-
+
def openEmptyDocument(self):
doc = self._createDocument()
doc.view.content_view.source_editor_view.goToLine(2)
doc.showView()
-
+
def openDocument(self, file_path):
"""
Opens an existing document at given file path and closes the startup document if
@@ -44,32 +44,32 @@ def openDocument(self, file_path):
doc = self._createDocument(file_path)
doc.showView()
self._closeEmptyStartupDocument()
-
+
def _createDocument(self, file_path=None):
"""
Creates a document controller and adds it to the docs list.
"""
- doc = controllers.factory.ControllerFactory.createDocumentController(self.app_controller, file_path)
+ doc = factory.ControllerFactory.createDocumentController(self.app_controller, file_path)
doc.documentClosedSignal.connect(self._documentClosed)
self.documents.append(doc)
return doc
-
+
def _closeEmptyStartupDocument(self):
"""
Closes the startup document if it is empty.
"""
if len(self.documents) > 1 and self.documents[0].model.isUntitled() and self.documents[0].model.isEmpty():
self.documents[0].view.close()
-
+
def saveAllDocuments(self):
for d in self.documents:
if d.isDirty():
d.save()
-
+
def closeAllDocuments(self):
for d in self.documents:
d.close()
-
+
@pyqtSlot()
def _documentClosed(self, document):
"""
@@ -77,4 +77,4 @@ def _documentClosed(self, document):
controller after the user closed the view.
"""
if document in self.documents:
- self.documents.remove(document)
+ self.documents.remove(document)
View
39 controllers/errors.py → tikz_editor/controllers/errors.py
@@ -1,60 +1,65 @@
# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt4.QtCore import *
from PyQt4.QtGui import *
-from models import Preferences
-from tools import documentIO
+from tikz_editor.models import Preferences
+from tikz_editor.tools import documentIO
+
class ConversionError(object):
def __init__(self, line, error):
super(ConversionError, self).__init__()
self.line = line
self.error = error
+
def __str__(self):
return self.error
+
class PreambleError(ConversionError):
def __str__(self):
error = self.error
if self.line is not None:
error = "(preamble l.%d) %s" % (self.line, error)
return error
-
+
+
class SourceError(ConversionError):
def __str__(self):
error = self.error
if self.line is not None:
error = "(source l.%d) %s" % (self.line, error)
return error
-
+
+
class ErrorsController(QObject):
"""
The errors controller populates the errors list and error feedbacks (margin markers
and annotations).
"""
-
+
# list of instances used to reload preferences
instances = []
-
+
@staticmethod
def reloadUserPreferences():
for errors in ErrorsController.instances:
errors.loadUserPreferences()
-
+
def __init__(self):
super(ErrorsController, self).__init__()
self.app_controller = None
@@ -65,7 +70,7 @@ def __init__(self):
self.show_error_markers = None
self.show_error_annotations = None
ErrorsController.instances.append(self)
-
+
def initController(self):
self.errors_view.errorSelectedSignal.connect(self.errorSelected)
self.loadUserPreferences()
@@ -75,7 +80,7 @@ def loadUserPreferences(self):
self.show_error_annotations = Preferences.getShowErrorAnnotations()
self.clearErrorMarginMarkersAndAnnotations()
self._updateEditorsMarginsAndAnnotations()
-
+
def errorSelected(self, error):
if isinstance(error, PreambleError):
self.content_view.showPreambleView()
@@ -103,7 +108,7 @@ def clearErrorMarginMarkersAndAnnotations(self):
self.content_view.source_editor_view.removeAllAnnotations()
self.content_view.preamble_editor_view.removeAllErrorMarginMarkers()
self.content_view.preamble_editor_view.removeAllAnnotations()
-
+
def _matchErrorsToSource(self, errors, latex_source):
"""
Sorts errors between LaTeX sections (preamble and source) according to file
@@ -124,14 +129,14 @@ def _matchErrorsToSource(self, errors, latex_source):
else:
matched_errors.append(ConversionError(None, message))
self.errors = matched_errors
-
+
def _updateEditorsMarginsAndAnnotations(self):
for error in self.errors:
if isinstance(error, PreambleError):
self._addErrorToViewMarginsAndAnnotations(self.content_view.preamble_editor_view, error)
elif isinstance(error, SourceError) or isinstance(error, ConversionError):
self._addErrorToViewMarginsAndAnnotations(self.content_view.source_editor_view, error)
-
+
def _addErrorToViewMarginsAndAnnotations(self, view, error):
line = error.line
if not line:
@@ -140,7 +145,7 @@ def _addErrorToViewMarginsAndAnnotations(self, view, error):
view.addErrorMarginMarkerToLine(line)
if self.show_error_annotations:
view.addAnnotationToLine(line, error.error)
-
+
def _updateErrorsList(self):
for error in self.errors:
- self.errors_view.addError(error)
+ self.errors_view.addError(error)
View
29 controllers/factory.py → tikz_editor/controllers/factory.py
@@ -1,15 +1,15 @@
# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
@@ -21,14 +21,15 @@
from errors import ErrorsController
from preferences import PreferencesController
-from models import DocumentFactory
-from views import ViewFactory
+from tikz_editor.models import DocumentFactory
+from tikz_editor.views import ViewFactory
+
class ControllerFactory(object):
"""
Factory of all controllers.
"""
-
+
@staticmethod
def createAppController():
app_controller = AppController()
@@ -37,7 +38,7 @@ def createAppController():
app_controller.preferences_controller = ControllerFactory.createPreferencesController(app_controller)
app_controller.initController()
return app_controller
-
+
@staticmethod
def createAboutController(app_controller):
about_controller = AboutController()
@@ -45,8 +46,8 @@ def createAboutController(app_controller):
about_controller.view = ViewFactory.createAboutView(app_controller)
about_controller.initController()
return about_controller
-
- @staticmethod
+
+ @staticmethod
def createDocumentController(app_controller, file_path=None):
doc_controller = DocumentController()
doc_controller.app_controller = app_controller
@@ -66,7 +67,7 @@ def createDocumentController(app_controller, file_path=None):
doc_controller.model = doc_model
doc_controller.initController()
return doc_controller
-
+
@staticmethod
def createErrorsController(app_controller, doc_controller, doc_view):
errors_controller = ErrorsController()
@@ -76,7 +77,7 @@ def createErrorsController(app_controller, doc_controller, doc_view):
errors_controller.errors_view = doc_view.feedback_view.errors_view
errors_controller.initController()
return errors_controller
-
+
@staticmethod
def createPreviewController(app_controller, doc_controller, doc_view):
preview_controller = PreviewController()
@@ -85,17 +86,17 @@ def createPreviewController(app_controller, doc_controller, doc_view):
preview_controller.preview_view = doc_view.preview_view
preview_controller.initController()
return preview_controller
-
+
@staticmethod
def createDocumentsController(app_controller):
documents_controller = DocumentsController()
documents_controller.app_controller = app_controller
return documents_controller
-
+
@staticmethod
def createPreferencesController(app_controller):
preferences_controller = PreferencesController()
preferences_controller.app_controller = app_controller
preferences_controller.view = ViewFactory.createPreferencesView(app_controller, preferences_controller)
preferences_controller.initController()
- return preferences_controller
+ return preferences_controller
View
37 controllers/preferences.py → tikz_editor/controllers/preferences.py
@@ -1,35 +1,36 @@
# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt4.QtCore import *
-from models import Preferences
-from controllers.errors import ErrorsController
-from views.editor import EditorView
+from tikz_editor.models import Preferences
+from errors import ErrorsController
+from tikz_editor.views.editor import EditorView
+
class PreferencesController(QObject):
"""
Controller of the "Preferences" dialog. It basically connects and syncs user defaults
with the preferences dialog.
"""
-
+
def __init__(self):
super(PreferencesController, self).__init__()
self.app_controller = None
self.view = None
-
+
def initController(self):
assert self.view
self._connectViewAndModel()
@@ -44,7 +45,7 @@ def _connectViewAndModel(self):
self.view.editor.autoWrapChangedSignal.connect(Preferences.setAutoWrap)
self.view.editor.errorMarkersChangedSignal.connect(Preferences.setShowErrorMarkers)
self.view.editor.errorAnnotationsChangedSignal.connect(Preferences.setShowErrorAnnotations)
-
+
self.view.editor.editorFontChangedSignal.connect(EditorView.reloadUserPreferences)
self.view.editor.fileEncodingChangedSignal.connect(EditorView.reloadUserPreferences)
self.view.editor.lineEndingsChangedSignal.connect(EditorView.reloadUserPreferences)
@@ -53,17 +54,17 @@ def _connectViewAndModel(self):
self.view.editor.autoWrapChangedSignal.connect(EditorView.reloadUserPreferences)
self.view.editor.errorMarkersChangedSignal.connect(ErrorsController.reloadUserPreferences)
self.view.editor.errorAnnotationsChangedSignal.connect(ErrorsController.reloadUserPreferences)
-
+
self.view.document.preambleTemplateChangedSignal.connect(Preferences.setPreambleTemplate)
self.view.document.latexFileTemplateChangedSignal.connect(Preferences.setLatexFileTemplate)
-
+
self.view.preview.previewTemplateChangedSignal.connect(Preferences.setPreviewTemplate)
self.view.preview.latexToPDFCommandChangedSignal.connect(Preferences.setLatexToPDFCommand)
self.view.preview.PDFToImageCommandChangedSignal.connect(Preferences.setPDFToImageCommand)
-
+
self.view.snippets.snippetsChangedSignal.connect(Preferences.setSnippets)
self.view.snippets.snippetsChangedSignal.connect(self.app_controller.loadSnippets)
-
+
def _syncViewAndModel(self):
self.view.editor.editor_font = Preferences.getEditorFont()
self.view.editor.file_encoding = Preferences.getFileEncoding()
@@ -73,17 +74,17 @@ def _syncViewAndModel(self):
self.view.editor.auto_wrap = Preferences.getAutoWrap()
self.view.editor.error_markers = Preferences.getShowErrorMarkers()
self.view.editor.error_annotations = Preferences.getShowErrorAnnotations()
-
+
self.view.document.latex_file_template = Preferences.getLatexFileTemplate()
self.view.document.preamble_template = Preferences.getPreambleTemplate()
-
+
self.view.preview.preview_template = Preferences.getPreviewTemplate()
self.view.preview.latex_to_pdf_command = Preferences.getLatexToPDFCommand()
self.view.preview.pdf_to_image_command = Preferences.getPDFToImageCommand()
-
+
self.view.snippets.snippets = Preferences.getSnippets()
-
+
@pyqtSlot()
def showPreferences(self):
self.view.show()
- self.view.raise_()
+ self.view.raise_()
View
29 controllers/preview.py → tikz_editor/controllers/preview.py
@@ -1,15 +1,15 @@
# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
@@ -18,10 +18,11 @@
from PyQt4.QtCore import *
from PyQt4.QtGui import *
-from models import Preferences
-from tools.latex2image import Converter, LatexToImageConversion
-from tools import documentIO
-from tools import TemporaryDirectory
+from tikz_editor.models import Preferences
+from tikz_editor.tools.latex2image import Converter, LatexToImageConversion
+from tikz_editor.tools import documentIO
+from tikz_editor.tools import TemporaryDirectory
+
class PreviewController(QObject):
"""
@@ -31,7 +32,7 @@ class PreviewController(QObject):
willUpdatePreviewSignal = pyqtSignal()
errorsInSourceSignal = pyqtSignal(list, str)
logsSignal = pyqtSignal(str)
-
+
def __init__(self):
super(PreviewController, self).__init__()
self.app_controller = None
@@ -40,7 +41,7 @@ def __init__(self):
self.latex2image_converter = None
self.request_preview_update = False
self.last_time_content_changed = datetime.now()
-
+
def initController(self):
temp_dir = TemporaryDirectory.get()
self.latex2image_converter = Converter(temp_dir)
@@ -53,7 +54,7 @@ def documentContentChanged(self, content):
self.preview_view.showWaitingBackground()
if not self.request_preview_update:
self.requestPreviewUpdate()
-
+
@pyqtSlot()
def conversionAborted(self):
self.preview_view.showErrorBackground()
@@ -79,7 +80,7 @@ def updatePreviewAfterTypingPause(self):
if (datetime.now() - self.last_time_content_changed).microseconds >= 500000:
self.updatePreview()
else:
- QTimer.singleShot(400, self.updatePreviewAfterTypingPause)
+ QTimer.singleShot(400, self.updatePreviewAfterTypingPause)
def updatePreview(self):
self.request_preview_update = False
@@ -87,10 +88,10 @@ def updatePreview(self):
template = Preferences.getPreviewTemplate()
source = documentIO.buildFileContentFromDocument(template, doc)
self.latex2image_converter.convertLatexToImage(source)
-
+
def abortPreview(self):
self.latex2image_converter.stopConversion()
-
+
@pyqtSlot(LatexToImageConversion)
def previewGenerated(self, conversion):
self.willUpdatePreviewSignal.emit()
@@ -98,4 +99,4 @@ def previewGenerated(self, conversion):
self.preview_view.figure = conversion.image_path
self.preview_view.showNormalBackground()
self.logsSignal.emit(conversion.logs)
- self.errorsInSourceSignal.emit(conversion.errors, conversion.source)
+ self.errorsInSourceSignal.emit(conversion.errors, conversion.source)
View
10 globals/__init__.py → tikz_editor/globals/__init__.py
@@ -1,21 +1,21 @@
# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
APPLICATION_NAME = u"TikZ Editor"
ORGANIZATION_NAME = u"UPMC"
ORGANIZATION_DOMAIN = u"upmc.fr"
-AUTHORS = u"Micka&euml;l Menu" # add authors separated by commas -- accents must be encoded as HTML entities
+AUTHORS = u"Micka&euml;l Menu" # add authors separated by commas -- accents must be encoded as HTML entities
VERSION = u"1.0"
-GIT_VERSION = u"" # returned by "git describe --always" in the GIT repository
+GIT_VERSION = u"" # returned by "git describe --always" in the GIT repository
View
8 globals/actions.py → tikz_editor/globals/actions.py
@@ -1,15 +1,15 @@
# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
@@ -41,4 +41,4 @@
FILE_MENU = "fileMenu"
EDIT_MENU = "editMenu"
COPY_MENU = "copyMenu"
-SNIPPETS_MENU = "snippetsMenu"
+SNIPPETS_MENU = "snippetsMenu"
View
12 globals/defaults.py → tikz_editor/globals/defaults.py
@@ -1,22 +1,22 @@
# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
# Default user preferences
EDITOR_FONT = u'Monaco, Courrier,13,-1,5,50,0,0,0,1,0'
-FILE_ENCODING = "UTF-8" # UTF-8, LATIN-1
-INDENTATION_TYPE = "tab" # tab, spaces
+FILE_ENCODING = "UTF-8" # UTF-8, LATIN-1
+INDENTATION_TYPE = "tab" # tab, spaces
INDENTATION_SIZE = 4
AUTO_WRAP = True
SHOW_ERROR_MARKERS = True
@@ -53,4 +53,4 @@
u'Foreach x': u'\\foreach \\x in {@@@}',
u'Tabular': u"""\\begin{tabular}{@@@}
\end{tabular}"""
-}
+}
View
8 globals/editor.py → tikz_editor/globals/editor.py
@@ -1,15 +1,15 @@
# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
@@ -39,4 +39,4 @@
# Symbols {}$
EDITOR_SYMBOLS2_COLOR = '#C80000'
EDITOR_SYMBOLS2_BOLD = False
-EDITOR_SYMBOLS2_ITALIC = False
+EDITOR_SYMBOLS2_ITALIC = False
View
6 models/__init__.py → tikz_editor/models/__init__.py
@@ -1,15 +1,15 @@
# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
View
40 models/document.py → tikz_editor/models/document.py
@@ -1,15 +1,15 @@
# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
@@ -17,27 +17,29 @@
from PyQt4.QtGui import *
from preferences import PreferencesModel as Preferences
-from tools import File
-from tools import documentIO
+from tikz_editor.tools import File
+from tikz_editor.tools import documentIO
+
class DocumentError(Exception):
pass
-
+
+
class DocumentModel(QObject):
"""
The document model represents a TikZ document, that is composed of a preamble and a
source.
"""
-
+
LAST_CREATED_DOCUMENT_ID = 0
DEFAULT_SOURCE = unicode("\\begin{tikzpicture}\n\n\\end{tikzpicture}")
-
+
sourceChangedSignal = pyqtSignal(str)
preambleChangedSignal = pyqtSignal(str)
titleChangedSignal = pyqtSignal(str)
documentDirtiedSignal = pyqtSignal()
documentSavedSignal = pyqtSignal()
-
+
def __init__(self, file_path=None):
super(DocumentModel, self).__init__()
self.id = self._createDocumentId()
@@ -45,11 +47,11 @@ def __init__(self, file_path=None):
self._source = DocumentModel.DEFAULT_SOURCE
self._dirty = False
self._file_path = file_path
-
+
def _createDocumentId(self):
DocumentModel.LAST_CREATED_DOCUMENT_ID += 1
return DocumentModel.LAST_CREATED_DOCUMENT_ID
-
+
def open(self):
"""
To open the document, we read the content from the file path and un-
@@ -61,7 +63,7 @@ def open(self):
self.dirty = False
except Exception, e:
raise DocumentError("The document cannot be opened: %s" % unicode(e))
-
+
def save(self):
"""
To save the document, we write the content to the file path and un-
@@ -77,13 +79,13 @@ def save(self):
@property
def file_path(self):
return self._file_path
-
+
@file_path.setter
def file_path(self, file_path):
if self._file_path != file_path:
self._file_path = file_path
self.titleChangedSignal.emit(self.title)
-
+
@property
def title(self):
"""
@@ -120,7 +122,7 @@ def source(self, source):
self._source = source
self.sourceChangedSignal.emit(source)
self.dirty = True
-
+
@pyqtSlot(str)
def setSource(self, source):
self.source = source
@@ -136,17 +138,17 @@ def preamble(self, preamble):
self._preamble = preamble
self.preambleChangedSignal.emit(preamble)
self.dirty = True
-
+
@pyqtSlot(str)
def setPreamble(self, preamble):
self.preamble = preamble
-
+
def isDirty(self):
return self.dirty
-
+
def isUntitled(self):
# an untitled document has no file path.
return self.file_path is None or self.file_path == ""
def isEmpty(self):
- return (self.preamble == Preferences.getPreambleTemplate() and self.source == DocumentModel.DEFAULT_SOURCE)
+ return (self.preamble == Preferences.getPreambleTemplate() and self.source == DocumentModel.DEFAULT_SOURCE)
View
11 models/factory.py → tikz_editor/models/factory.py
@@ -1,20 +1,21 @@
# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
from document import DocumentModel
+
class DocumentFactory(object):
"""
Factory of document models.
@@ -22,10 +23,10 @@ class DocumentFactory(object):
@staticmethod
def createEmptyDocument():
return DocumentModel()
-
+
@staticmethod
def createDocumentFromFilePath(file_path):
assert file_path is not None
d = DocumentModel(file_path)
d.open()
- return d
+ return d
View
183 models/preferences.py → tikz_editor/models/preferences.py
@@ -1,30 +1,31 @@
# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt4.QtCore import *
from PyQt4.QtGui import *
-import globals.defaults as defaults
-from tools import isMacintoshComputer, isWindowsComputer, findCommandLocation
+import tikz_editor.globals.defaults as defaults
+from tikz_editor.tools import isMacintoshComputer, isWindowsComputer, findCommandLocation
+
class PreferencesModel(object):
"""
The preferences model is a wrapper for QT's QSettings allowing easy retrieval of user
defaults.
"""
-
+
WINDOW_GEOMETRY = "WindowGeometry"
EDITOR_SPLITTER_STATE = "EditorSplitterState"
MAIN_SPLITTER_STATE = "MainSplitterState"
@@ -43,9 +44,9 @@ class PreferencesModel(object):
SHOW_ERROR_MARKERS = "ShowErrorMarkers"
SHOW_ERROR_ANNOTATIONS = "ShowErrorAnnotations"
SNIPPETS = "Snippets"
-
+
FEEDBACK_LOGS_VIEW = 0
- FEEDBACK_ERRORS_VIEW = 1
+ FEEDBACK_ERRORS_VIEW = 1
ENCODING_UTF8 = 1
ENCODING_LATIN1 = 2
LINE_ENDINGS_WINDOWS = 1
@@ -53,12 +54,12 @@ class PreferencesModel(object):
LINE_ENDINGS_UNIX = 3
INDENT_TAB = 1
INDENT_SPACES = 2
-
+
@staticmethod
def containsKey(key):
settings = QSettings()
return settings.contains(key)
-
+
@staticmethod
def getValue(key):
return PreferencesModel.getValueOrDefault(key, None)
@@ -76,57 +77,57 @@ def getValueOrDefault(key, default_value):
def setValue(key, value):
settings = QSettings()
settings.setValue(key, QVariant(value))
-
+
@staticmethod
def removeKey(key):
settings = QSettings()
settings.remove(key)
-
+
################################################################################
@staticmethod
def hasWindowGeometry():
return PreferencesModel.containsKey(PreferencesModel.WINDOW_GEOMETRY)
-
+
@staticmethod
def getWindowGeometry():
return PreferencesModel.getValue(PreferencesModel.WINDOW_GEOMETRY).toByteArray()
-
+
@staticmethod
def setWindowGeometry(value):
PreferencesModel.setValue(PreferencesModel.WINDOW_GEOMETRY, value)
-
-
+
+
@staticmethod
def hasEditorSplitterState():
return PreferencesModel.containsKey(PreferencesModel.EDITOR_SPLITTER_STATE)
-
+
@staticmethod
def getEditorSplitterState():
return PreferencesModel.getValue(PreferencesModel.EDITOR_SPLITTER_STATE).toByteArray()
-
+
@staticmethod
def setEditorSplitterState(value):
PreferencesModel.setValue(PreferencesModel.EDITOR_SPLITTER_STATE, value)
-
-
+
+
@staticmethod
def hasMainSplitterState():
return PreferencesModel.containsKey(PreferencesModel.MAIN_SPLITTER_STATE)
-
+
@staticmethod
def getMainSplitterState():
return PreferencesModel.getValue(PreferencesModel.MAIN_SPLITTER_STATE).toByteArray()
-
+
@staticmethod
def setMainSplitterState(value):
PreferencesModel.setValue(PreferencesModel.MAIN_SPLITTER_STATE, value)
-
-
+
+
@staticmethod
def hasSelectedFeedbackView():
return PreferencesModel.containsKey(PreferencesModel.SELECTED_FEEDBACK_VIEW)
-
+
@staticmethod
def getSelectedFeedbackView():
value = PreferencesModel.getValueOrDefault(PreferencesModel.SELECTED_FEEDBACK_VIEW, PreferencesModel.defaultSelectedFeedbackView()).toInt()
@@ -135,40 +136,40 @@ def getSelectedFeedbackView():
if not (convert_success and value in (PreferencesModel.FEEDBACK_LOGS_VIEW, PreferencesModel.FEEDBACK_ERRORS_VIEW)):
value = PreferencesModel.defaultSelectedFeedbackView()
return value
-
+
@staticmethod
def setSelectedFeedbackView(value):
PreferencesModel.setValue(PreferencesModel.SELECTED_FEEDBACK_VIEW, value)
-
+
@staticmethod
def defaultSelectedFeedbackView():
return PreferencesModel.FEEDBACK_LOGS_VIEW
-
+
################################################################################
@staticmethod
def hasEditorFont():
return PreferencesModel.containsKey(PreferencesModel.EDITOR_FONT)
-
+
@staticmethod
def getEditorFont():
font = QFont()
font.fromString(PreferencesModel.getValueOrDefault(PreferencesModel.EDITOR_FONT, PreferencesModel.defaultEditorFont()).toString())
return font
-
+
@staticmethod
def setEditorFont(value):
PreferencesModel.setValue(PreferencesModel.EDITOR_FONT, value.toString())
-
+
@staticmethod
def defaultEditorFont():
return defaults.EDITOR_FONT
-
-
+
+
@staticmethod
def hasFileEncoding():
return PreferencesModel.containsKey(PreferencesModel.FILE_ENCODING)
-
+
@staticmethod
def getFileEncoding():
value = PreferencesModel.getValueOrDefault(PreferencesModel.FILE_ENCODING, PreferencesModel.defaultFileEncoding()).toInt()
@@ -178,24 +179,24 @@ def getFileEncoding():
value = PreferencesModel.defaultFileEncoding()
return value
-
+
@staticmethod
def setFileEncoding(value):
assert value in (PreferencesModel.ENCODING_LATIN1, PreferencesModel.ENCODING_UTF8)
PreferencesModel.setValue(PreferencesModel.FILE_ENCODING, value)
-
+
@staticmethod
def defaultFileEncoding():
default = PreferencesModel.ENCODING_UTF8
if defaults.FILE_ENCODING == "LATIN-1":
default = PreferencesModel.ENCODING_LATIN1
return default
-
-
+
+
@staticmethod
def hasLineEndings():
return PreferencesModel.containsKey(PreferencesModel.LINE_ENDINGS)
-
+
@staticmethod
def getLineEndings():
value = PreferencesModel.getValueOrDefault(PreferencesModel.LINE_ENDINGS, PreferencesModel.defaultLineEndings()).toInt()
@@ -204,24 +205,24 @@ def getLineEndings():
if not (convert_success and value in (PreferencesModel.LINE_ENDINGS_UNIX, PreferencesModel.LINE_ENDINGS_MAC, PreferencesModel.LINE_ENDINGS_WINDOWS)):
value = PreferencesModel.defaultLineEndings()
return value
-
+
@staticmethod
def setLineEndings(value):
assert value in (PreferencesModel.LINE_ENDINGS_UNIX, PreferencesModel.LINE_ENDINGS_MAC, PreferencesModel.LINE_ENDINGS_WINDOWS)
PreferencesModel.setValue(PreferencesModel.LINE_ENDINGS, value)
-
+
@staticmethod
def defaultLineEndings():
default = PreferencesModel.LINE_ENDINGS_UNIX
if isWindowsComputer():
default = PreferencesModel.LINE_ENDINGS_WINDOWS
return default
-
-
+
+
@staticmethod
def hasIndentationType():
return PreferencesModel.containsKey(PreferencesModel.INDENTATION_TYPE)
-
+
@staticmethod
def getIndentationType():
value = PreferencesModel.getValueOrDefault(PreferencesModel.INDENTATION_TYPE, PreferencesModel.defaultIndentationType()).toInt()
@@ -230,12 +231,12 @@ def getIndentationType():
if not (convert_success and value in (PreferencesModel.INDENT_TAB, PreferencesModel.INDENT_SPACES)):
value = PreferencesModel.defaultIndentationType()
return value
-
+
@staticmethod
def setIndentationType(value):
assert value in (PreferencesModel.INDENT_SPACES, PreferencesModel.INDENT_TAB)
PreferencesModel.setValue(PreferencesModel.INDENTATION_TYPE, value)
-
+
@staticmethod
def defaultIndentationType():
default = PreferencesModel.INDENT_TAB
@@ -247,7 +248,7 @@ def defaultIndentationType():
@staticmethod
def hasIndentationSize():
return PreferencesModel.containsKey(PreferencesModel.INDENTATION_SIZE)
-
+
@staticmethod
def getIndentationSize():
value = PreferencesModel.getValueOrDefault(PreferencesModel.INDENTATION_SIZE, PreferencesModel.defaultIndentationSize()).toInt()
@@ -256,151 +257,151 @@ def getIndentationSize():
if not (convert_success and value > 0):
value = PreferencesModel.defaultIndentationSize()
return value
-
+
@staticmethod
def setIndentationSize(value):
assert value > 0
PreferencesModel.setValue(PreferencesModel.INDENTATION_SIZE, value)
-
+
@staticmethod
def defaultIndentationSize():
return defaults.INDENTATION_SIZE
-
-
+
+
@staticmethod
def hasAutoWrap():
return PreferencesModel.containsKey(PreferencesModel.AUTO_WRAP)
-
+
@staticmethod
def getAutoWrap():
return PreferencesModel.getValueOrDefault(PreferencesModel.AUTO_WRAP, PreferencesModel.defaultAutoWrap()).toBool()
-
+
@staticmethod
def setAutoWrap(value):
PreferencesModel.setValue(PreferencesModel.AUTO_WRAP, value)
-
+
@staticmethod
def defaultAutoWrap():
return defaults.AUTO_WRAP
-
-
+
+
@staticmethod
def hasShowErrorMarkers():
return PreferencesModel.containsKey(PreferencesModel.SHOW_ERROR_MARKERS)
-
+
@staticmethod
def getShowErrorMarkers():
return PreferencesModel.getValueOrDefault(PreferencesModel.SHOW_ERROR_MARKERS, PreferencesModel.defaultShowErrorMarkers()).toBool()
-
+
@staticmethod
def setShowErrorMarkers(value):
PreferencesModel.setValue(PreferencesModel.SHOW_ERROR_MARKERS, value)
-
+
@staticmethod
def defaultShowErrorMarkers():
return defaults.SHOW_ERROR_MARKERS
-
-
+
+
@staticmethod
def hasShowErrorAnnotations():
return PreferencesModel.containsKey(PreferencesModel.SHOW_ERROR_ANNOTATIONS)
-
+
@staticmethod
def getShowErrorAnnotations():
return PreferencesModel.getValueOrDefault(PreferencesModel.SHOW_ERROR_ANNOTATIONS, PreferencesModel.defaultShowErrorAnnotations()).toBool()
-
+
@staticmethod
def setShowErrorAnnotations(value):
PreferencesModel.setValue(PreferencesModel.SHOW_ERROR_ANNOTATIONS, value)
-
+
@staticmethod
def defaultShowErrorAnnotations():
return defaults.SHOW_ERROR_MARKERS
-
+
################################################################################
@staticmethod
def hasLatexFileTemplate():
return PreferencesModel.containsKey(PreferencesModel.LATEX_FILE_TEMPLATE)
-
+
@staticmethod
def getLatexFileTemplate():
return unicode(PreferencesModel.getValueOrDefault(PreferencesModel.LATEX_FILE_TEMPLATE, PreferencesModel.defaultLatexFileTemplate()).toString())
-
+
@staticmethod
def setLatexFileTemplate(value):
PreferencesModel.setValue(PreferencesModel.LATEX_FILE_TEMPLATE, value)
-
+
@staticmethod
def defaultLatexFileTemplate():
return defaults.DEFAULT_TEMPLATE
-
+
@staticmethod
def hasPreambleTemplate():
return PreferencesModel.containsKey(PreferencesModel.PREAMBLE_TEMPLATE)
-
+
@staticmethod
def getPreambleTemplate():
return unicode(PreferencesModel.getValueOrDefault(PreferencesModel.PREAMBLE_TEMPLATE, PreferencesModel.defaultPreambleTemplate()).toString())
-
+
@staticmethod
def setPreambleTemplate(value):
PreferencesModel.setValue(PreferencesModel.PREAMBLE_TEMPLATE, value)
-
+
@staticmethod
def defaultPreambleTemplate():
return defaults.DEFAULT_PREAMBLE_TEMPLATE
-
+
################################################################################
@staticmethod
def hasPreviewTemplate():
return PreferencesModel.containsKey(PreferencesModel.PREVIEW_TEMPLATE)
-
+
@staticmethod
def getPreviewTemplate():
return unicode(PreferencesModel.getValueOrDefault(PreferencesModel.PREVIEW_TEMPLATE, PreferencesModel.defaultPreviewTemplate()).toString())
-
+
@staticmethod
def setPreviewTemplate(value):
PreferencesModel.setValue(PreferencesModel.PREVIEW_TEMPLATE, value)
-
+
@staticmethod
def defaultPreviewTemplate():
return defaults.DEFAULT_TEMPLATE
-
-
+
+
DEFAULT_LATEX_TO_PDF_COMMAND = None
-
+
@staticmethod
def hasLatexToPDFCommand():
return PreferencesModel.containsKey(PreferencesModel.LATEX_TO_PDF_COMMAND)
-
+
@staticmethod
def getLatexToPDFCommand():
return unicode(PreferencesModel.getValueOrDefault(PreferencesModel.LATEX_TO_PDF_COMMAND, PreferencesModel.defaultLatexToPDFCommand()).toString())
-
+
@staticmethod
def setLatexToPDFCommand(value):
PreferencesModel.setValue(PreferencesModel.LATEX_TO_PDF_COMMAND, value)
-
+
@staticmethod
def defaultLatexToPDFCommand():
if PreferencesModel.DEFAULT_LATEX_TO_PDF_COMMAND is None:
pdflatex_path = findCommandLocation(defaults.DEFAULT_LATEX_TO_PDF_COMMAND)
PreferencesModel.DEFAULT_LATEX_TO_PDF_COMMAND = defaults.DEFAULT_LATEX_TO_PDF_ARGS % pdflatex_path
return PreferencesModel.DEFAULT_LATEX_TO_PDF_COMMAND
-
-
+
+
DEFAULT_PDF_TO_IMAGE_COMMAND = None
-
+
@staticmethod
def hasPDFToImageCommand():
return PreferencesModel.containsKey(PreferencesModel.PDF_TO_IMAGE_COMMAND)
-
+
@staticmethod
def getPDFToImageCommand():
return unicode(PreferencesModel.getValueOrDefault(PreferencesModel.PDF_TO_IMAGE_COMMAND, PreferencesModel.defaultPDFToImageCommand()).toString())
@@ -408,13 +409,13 @@ def getPDFToImageCommand():
@staticmethod
def setPDFToImageCommand(value):
PreferencesModel.setValue(PreferencesModel.PDF_TO_IMAGE_COMMAND, value)
-
+
@staticmethod
def defaultPDFToImageCommand():
if PreferencesModel.DEFAULT_PDF_TO_IMAGE_COMMAND is None:
if isMacintoshComputer():
sips_path = findCommandLocation(defaults.DEFAULT_MAC_PDF_TO_IMAGE_COMMAND)
- PreferencesModel.DEFAULT_PDF_TO_IMAGE_COMMAND = defaults.DEFAULT_MAC_PDF_TO_IMAGE_ARGS % sips_path
+ PreferencesModel.DEFAULT_PDF_TO_IMAGE_COMMAND = defaults.DEFAULT_MAC_PDF_TO_IMAGE_ARGS % sips_path
else:
convert_path = findCommandLocation(defaults.DEFAULT_PDF_TO_IMAGE_COMMAND)
PreferencesModel.DEFAULT_PDF_TO_IMAGE_COMMAND = defaults.DEFAULT_PDF_TO_IMAGE_ARGS % convert_path
@@ -425,7 +426,7 @@ def defaultPDFToImageCommand():
@staticmethod
def hasSnippets():
return PreferencesModel.containsKey(PreferencesModel.SNIPPETS)
-
+
@staticmethod
def getSnippets():
snippets = PreferencesModel.getValueOrDefault(PreferencesModel.SNIPPETS, PreferencesModel.defaultSnippets()).toPyObject()
@@ -434,11 +435,11 @@ def getSnippets():
for name, code in snippets.items():
str_snippets[unicode(name)] = unicode(code)
return str_snippets
-
+
@staticmethod
def setSnippets(value):
PreferencesModel.setValue(PreferencesModel.SNIPPETS, value)
-
+
@staticmethod
def defaultSnippets():
return defaults.SNIPPETS
View
2  resources/__init__.py → tikz_editor/resources/__init__.py
@@ -2,7 +2,7 @@
# Resource object code
#
-# Created: Thu May 10 18:11:35 2012
+# Created: Fri May 18 17:30:47 2012
# by: The Resource Compiler for PyQt (Qt v4.7.4)
#
# WARNING! All changes made in this file will be lost!
View
0  resources/about.html → tikz_editor/resources/html/about.html
File renamed without changes
View
0  resources/icon.icns → tikz_editor/resources/images/icon.icns
File renamed without changes
View
0  resources/icon.png → tikz_editor/resources/images/icon.png
File renamed without changes
View
0  resources/icon.pxm → tikz_editor/resources/images/icon.pxm
File renamed without changes
View
0  resources/icon_about.png → tikz_editor/resources/images/icon_about.png
File renamed without changes
View
7 tikz_editor/resources/resources.qrc
@@ -0,0 +1,7 @@
+<!DOCTYPE RCC>
+<RCC version="1.0">
+ <qresource>
+ <file alias="icon_about.png">images/icon_about.png</file>
+ <file alias="about.html">html/about.html</file>
+ </qresource>
+</RCC>
View
16 tools/__init__.py → tikz_editor/tools/__init__.py
@@ -1,15 +1,15 @@
# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
@@ -22,12 +22,15 @@
__all__ = ["File", "FileError", "TemporaryDirectory", "TemporaryDirectoryError"]
+
def isMacintoshComputer():
return (sys.platform == 'darwin')
+
def isWindowsComputer():
return (sys.platform in ('win32', 'cygwin'))
-
+
+
def findCommandLocation(command):
"""
Finds first found location of given command using "which".
@@ -39,11 +42,12 @@ def findCommandLocation(command):
if command_path == "":
raise Exception()
return command_path
- except Exception, e:
+ except Exception:
return command
+
def addToClipboard(text):
"""
Adds the given argument to the system clipboard.
"""
- QApplication.clipboard().setText(text)
+ QApplication.clipboard().setText(text)
View
22 tools/documentIO/__init__.py → tikz_editor/tools/documentIO/__init__.py
@@ -1,15 +1,15 @@
# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
@@ -18,34 +18,40 @@
from reader import DocumentReader
from template import FileTemplate
from tags import *
-from tools import File
+from tikz_editor.tools import File
+
def readPreambleAndSourceFromFilePath(file_path):
reader = DocumentReader(file_path)
return reader.readPreambleAndSource()
+
def writeDocumentToFilePath(template, document, file_path):
content = buildFileContentFromDocument(template, document)
File.writeContentToFilePath(content, file_path)
+
def buildFileContentFromDocument(template, document):
d = FileTemplate(template, document.preamble, document.source)
return d.buildFileContent()
+
def getPreamblePositionFromSourceCode(latex_source):
"""
Returns the position (tuple of line indexes) of the preamble section in the given
LaTeX source.
"""
return getSectionPositionFromSourceCodeAndTags(latex_source, PREAMBLE_BEGIN_TAG, PREAMBLE_END_TAG)
-
+
+
def getSourcePositionFromSourceCode(latex_source):
"""
Returns the position (tuple of line indexes) of the source section in the given LaTeX
source.
"""
return getSectionPositionFromSourceCodeAndTags(latex_source, SOURCE_BEGIN_TAG, SOURCE_END_TAG)
-
+
+
def getSectionPositionFromSourceCodeAndTags(latex_source, begin_tag, end_tag):
"""
Returns the position of a section in LaTeX source code.
@@ -65,8 +71,8 @@ def getSectionPositionFromSourceCodeAndTags(latex_source, begin_tag, end_tag):
end_line = i - 1
break
i += 1
-
+
assert begin_line > 0 and end_line > 0 and begin_line <= end_line
return (begin_line, end_line)
-__all__ = ["readPreambleAndSourceFromFilePath", "writeDocumentToFilePath", "buildFileContentFromDocument"]
+__all__ = ["readPreambleAndSourceFromFilePath", "writeDocumentToFilePath", "buildFileContentFromDocument"]
View
30 tools/documentIO/reader.py → tikz_editor/tools/documentIO/reader.py
@@ -1,26 +1,26 @@
# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
-from tools import File
+from tikz_editor.tools import File
from tags import *
+
class DocumentReaderError(Exception):
- def __init__(self, message):
+ def __init__(self, message="Not a valid TikZ document"):
super(DocumentReaderError, self).__init__(message)
- def __init__(self):
- super(DocumentReaderError, self).__init__("Not a valid TikZ document")
+
class DocumentReader(object):
"""
@@ -36,7 +36,7 @@ def __init__(self, file_path):
self.current_line = ""
self.parsing_preamble = False
self.parsing_source = False
-
+
def readPreambleAndSource(self):
self._checkFileExists()
self._readFileLines()
@@ -46,11 +46,11 @@ def readPreambleAndSource(self):
preamble = "\n".join(self.preamble_lines)
source = "\n".join(self.source_lines)
return (preamble, source)
-
+
def _checkFileExists(self):
if not File.exists(self.file_path):
raise DocumentReaderError("The file does not exist")
-
+
def _readFileLines(self):
content = File.readContentFromFilePath(self.file_path)
self.file_lines = content.split("\n")
@@ -63,14 +63,14 @@ def _checkDocumentValidity(self):
"""
if self._isFileEmpty() or self.file_lines[0] != TIKZ_TAG:
raise DocumentReaderError()
-
+
def _isFileEmpty(self):
return len(self.file_lines) == 0
-
+
def _extractPreambleAndSource(self):
"""
Extracts the preamble and TikZ source from file content using delimiter tags.
- """
+ """
for self.current_line in self.file_lines:
if self.parsing_preamble:
self._parsePreamble()
@@ -80,13 +80,13 @@ def _extractPreambleAndSource(self):
self.parsing_preamble = True
elif self.current_line == SOURCE_BEGIN_TAG:
self.parsing_source = True
-
+
def _parsePreamble(self):
if self.current_line == PREAMBLE_END_TAG:
self.parsing_preamble = False
else:
self.preamble_lines.append(self.current_line)
-
+
def _parseSource(self):
if self.current_line == SOURCE_END_TAG:
self.parsing_source = False
View
8 tools/documentIO/tags.py → tikz_editor/tools/documentIO/tags.py
@@ -1,15 +1,15 @@
# Copyright 2012 (C) Mickael Menu <mickael.menu@gmail.com>
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
@@ -18,4 +18,4 @@
PREAMBLE_BEGIN_TAG = "%!tikz preamble begin"
PREAMBLE_END_TAG = "%!tikz preamble end"
SOURCE_BEGIN_TAG = "%!tikz source begin"
-SOURCE_END_TAG = "%!tikz source end"
+SOURCE_END_TAG = "%!tikz source end"