1""" 2Copyright (c) 2017 Eliakin Costa <eliakim170@gmail.com> 3 4This program is free software; you can redistribute it and/or modify 5it under the terms of the GNU General Public License as published by 6the Free Software Foundation; either version 2 of the License, or 7(at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12GNU General Public License for more details. 13 14You should have received a copy of the GNU General Public License 15along with this program; if not, write to the Free Software 16Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17""" 18from PyQt5.QtCore import Qt, QObject, QFileInfo, QRect 19from PyQt5.QtGui import QTextCursor, QPalette 20from PyQt5.QtWidgets import (QToolBar, QMenuBar, QTabWidget, 21 QLabel, QVBoxLayout, QMessageBox, 22 QSplitter, QSizePolicy) 23from .ui_scripter.syntax import syntax, syntaxstyles 24from .ui_scripter.editor import pythoneditor 25from . import scripterdialog 26import importlib 27import krita 28 29KEY_GEOMETRY = "geometry" 30DEFAULT_GEOMETRY = QRect(600, 200, 400, 500) 31# essentially randomly placed 32 33 34class Elided_Text_Label(QLabel): 35 mainText = str() 36 37 def __init__(self, parent=None): 38 super(QLabel, self).__init__(parent) 39 self.setMinimumWidth(self.fontMetrics().width("...")) 40 self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) 41 42 def setMainText(self, text=str()): 43 self.mainText = text 44 self.elideText() 45 46 def elideText(self): 47 self.setText(self.fontMetrics().elidedText(self.mainText, Qt.ElideRight, self.width())) 48 49 def resizeEvent(self, event): 50 self.elideText() 51 52 53class UIController(object): 54 documentModifiedText = "" 55 documentStatusBarText = "untitled" 56 57 def __init__(self): 58 self.mainWidget = scripterdialog.ScripterDialog(self) 59 self.actionToolbar = QToolBar('toolBar', self.mainWidget) 60 self.menu_bar = QMenuBar(self.mainWidget) 61 62 self.actionToolbar.setObjectName('toolBar') 63 self.menu_bar.setObjectName('menuBar') 64 65 self.actions = [] 66 67 self.mainWidget.setWindowModality(Qt.NonModal) 68 69 def initialize(self, scripter): 70 self.editor = pythoneditor.CodeEditor(scripter) 71 self.tabWidget = QTabWidget() 72 self.statusBar = Elided_Text_Label() 73 self.statusBar.setMainText('untitled') 74 self.splitter = QSplitter() 75 self.splitter.setOrientation(Qt.Vertical) 76 self.highlight = syntax.PythonHighlighter(self.editor.document(), syntaxstyles.DefaultSyntaxStyle()) 77 p = self.editor.palette() 78 p.setColor(QPalette.Base, syntaxstyles.DefaultSyntaxStyle()['background'].foreground().color()) 79 p.setColor(QPalette.Text, syntaxstyles.DefaultSyntaxStyle()['foreground'].foreground().color()) 80 self.editor.setPalette(p) 81 82 self.scripter = scripter 83 84 self.loadMenus() 85 self.loadWidgets() 86 self.loadActions() 87 self._readSettings() # sets window size 88 89 vbox = QVBoxLayout(self.mainWidget) 90 vbox.addWidget(self.menu_bar) 91 vbox.addWidget(self.actionToolbar) 92 self.splitter.addWidget(self.editor) 93 self.splitter.addWidget(self.tabWidget) 94 vbox.addWidget(self.splitter) 95 vbox.addWidget(self.statusBar) 96 97 self.mainWidget.setWindowTitle(i18n("Scripter")) 98 self.mainWidget.setSizeGripEnabled(True) 99 self.mainWidget.show() 100 self.mainWidget.activateWindow() 101 102 self.editor.undoAvailable.connect(self.setStatusModified) 103 104 def loadMenus(self): 105 self.addMenu(i18n('File'), i18n('File')) 106 107 def addMenu(self, menuName, parentName): 108 parent = self.menu_bar.findChild(QObject, parentName) 109 self.newMenu = None 110 111 if parent: 112 self.newMenu = parent.addMenu(menuName) 113 else: 114 self.newMenu = self.menu_bar.addMenu(menuName) 115 116 self.newMenu.setObjectName(menuName) 117 118 return self.newMenu 119 120 def loadActions(self): 121 module_path = 'scripter.ui_scripter.actions' 122 actions_module = importlib.import_module(module_path) 123 modules = [] 124 125 for class_path in actions_module.action_classes: 126 _module = class_path[:class_path.rfind(".")] 127 _klass = class_path[class_path.rfind(".") + 1:] 128 modules.append(dict(module='{0}.{1}'.format(module_path, _module), 129 klass=_klass)) 130 131 for module in modules: 132 m = importlib.import_module(module['module']) 133 action_class = getattr(m, module['klass']) 134 obj = action_class(self.scripter) 135 obj_parent = obj.parent 136 for name in obj_parent: 137 parent = self.mainWidget.findChild(QObject, i18n(name)) 138 self.actions.append(dict(action=obj, parent=parent)) 139 140 for action in self.actions: 141 action['parent'].addAction(action['action']) 142 143 def loadWidgets(self): 144 modulePath = 'scripter.ui_scripter.tabwidgets' 145 widgetsModule = importlib.import_module(modulePath) 146 modules = [] 147 148 for class_path in widgetsModule.widgetClasses: 149 _module = class_path[:class_path.rfind(".")] 150 _klass = class_path[class_path.rfind(".") + 1:] 151 modules.append(dict(module='{0}.{1}'.format(modulePath, _module), 152 klass=_klass)) 153 154 for module in modules: 155 m = importlib.import_module(module['module']) 156 widgetClass = getattr(m, module['klass']) 157 obj = widgetClass(self.scripter) 158 self.tabWidget.addTab(obj, obj.objectName()) 159 160 def invokeAction(self, actionName): 161 for action in self.actions: 162 if action['action'].objectName() == actionName: 163 method = getattr(action['action'], actionName) 164 if method: 165 return method() 166 167 def findTabWidget(self, widgetName, childName=''): 168 for index in range(self.tabWidget.count()): 169 widget = self.tabWidget.widget(index) 170 if widget.objectName() == widgetName: 171 if childName: 172 widget = widget.findChild(QObject, childName) 173 return widget 174 175 def showException(self, exception): 176 QMessageBox.critical(self.editor, i18n("Error Running Script"), str(exception)) 177 178 def setDocumentEditor(self, document): 179 self.editor.clear() 180 self.editor.moveCursor(QTextCursor.Start) 181 self.editor._documentModified = False 182 self.editor.setPlainText(document.data) 183 self.editor.moveCursor(QTextCursor.End) 184 185 def setStatusBar(self, value='untitled'): 186 self.documentStatusBarText = value 187 self.statusBar.setMainText(self.documentStatusBarText + self.documentModifiedText) 188 189 def setStatusModified(self): 190 self.documentModifiedText = "" 191 if (self.editor._documentModified is True): 192 self.documentModifiedText = " [Modified]" 193 self.statusBar.setMainText(self.documentStatusBarText + self.documentModifiedText) 194 195 def setActiveWidget(self, widgetName): 196 widget = self.findTabWidget(widgetName) 197 198 if widget: 199 self.tabWidget.setCurrentWidget(widget) 200 201 def setStepped(self, status): 202 self.editor.setStepped(status) 203 204 def clearEditor(self): 205 self.editor.clear() 206 207 def repaintDebugArea(self): 208 self.editor.repaintDebugArea() 209 210 def closeScripter(self): 211 self.mainWidget.close() 212 213 def _writeSettings(self): 214 """ _writeSettings is a method invoked when the scripter starts, making 215 control inversion. Actions can implement a writeSettings method to 216 save your own settings without this method to know about it. """ 217 218 self.scripter.settings.beginGroup('scripter') 219 220 document = self.scripter.documentcontroller.activeDocument 221 if document: 222 self.scripter.settings.setValue('activeDocumentPath', document.filePath) 223 else: 224 self.scripter.settings.setValue('activeDocumentPath', '') 225 226 self.scripter.settings.setValue('editorFontSize', self.editor.fontInfo().pointSize()) 227 228 for action in self.actions: 229 writeSettings = getattr(action['action'], "writeSettings", None) 230 if callable(writeSettings): 231 writeSettings() 232 233 # Window Geometry 234 rect = self.mainWidget.geometry() 235 self.scripter.settings.setValue(KEY_GEOMETRY, rect) 236 237 self.scripter.settings.endGroup() 238 239 def _readSettings(self): 240 """ It's similar to _writeSettings, but reading the settings when the ScripterDialog is closed. """ 241 242 self.scripter.settings.beginGroup('scripter') 243 244 activeDocumentPath = self.scripter.settings.value('activeDocumentPath', '') 245 246 if activeDocumentPath: 247 if QFileInfo(activeDocumentPath).exists(): 248 document = self.scripter.documentcontroller.openDocument(activeDocumentPath) 249 self.setStatusBar(document.filePath) 250 self.setDocumentEditor(document) 251 252 for action in self.actions: 253 readSettings = getattr(action['action'], "readSettings", None) 254 if callable(readSettings): 255 readSettings() 256 257 pointSize = self.scripter.settings.value('editorFontSize', str(self.editor.fontInfo().pointSize())) 258 self.editor.setFontSize(int(pointSize)) 259 260 # Window Geometry 261 rect = self.scripter.settings.value(KEY_GEOMETRY, DEFAULT_GEOMETRY) 262 self.mainWidget.setGeometry(rect) 263 264 self.scripter.settings.endGroup() 265 266 def _saveSettings(self): 267 self.scripter.settings.sync() 268