diff --git a/dev-tools/python/dev-requirements.txt b/dev-tools/python/dev-requirements.txt index 3f32157dd9..08ebcd2d80 100644 --- a/dev-tools/python/dev-requirements.txt +++ b/dev-tools/python/dev-requirements.txt @@ -1,6 +1,6 @@ -flake8==3.6.0 +flake8==3.7.4 pytest==4.0.2 PyQt5==5.11.3 PyQt5-sip==4.19.13 -e dev-tools/python/krita-mock diff --git a/plugins/python/assignprofiledialog/__init__.py b/plugins/python/assignprofiledialog/__init__.py index 68c3ce8b95..9d9559d754 100644 --- a/plugins/python/assignprofiledialog/__init__.py +++ b/plugins/python/assignprofiledialog/__init__.py @@ -1,2 +1,4 @@ -# let's make a module -from .assignprofiledialog import * +from .assignprofiledialog import AssignProfileDialog + + +Scripter.addExtension(AssignProfileDialog(Application)) diff --git a/plugins/python/assignprofiledialog/assignprofiledialog.py b/plugins/python/assignprofiledialog/assignprofiledialog.py index 443a4dde59..bb47a2b97f 100644 --- a/plugins/python/assignprofiledialog/assignprofiledialog.py +++ b/plugins/python/assignprofiledialog/assignprofiledialog.py @@ -1,60 +1,66 @@ -''' -This script is licensed CC 0 1.0, so that you can learn from it. +# This script is licensed CC 0 1.0, so that you can learn from it. ------- CC 0 1.0 --------------- +# ------ CC 0 1.0 --------------- -The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. +# The person who associated a work with this deed has dedicated the +# work to the public domain by waiving all of his or her rights to the +# work worldwide under copyright law, including all related and +# neighboring rights, to the extent allowed by law. -You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. +# You can copy, modify, distribute and perform the work, even for +# commercial purposes, all without asking permission. + +# https://creativecommons.org/publicdomain/zero/1.0/legalcode -https://creativecommons.org/publicdomain/zero/1.0/legalcode -''' from PyQt5.QtCore import Qt from PyQt5.QtWidgets import (QDialogButtonBox, QDialog, QMessageBox, QComboBox, QVBoxLayout) from krita import Extension class AssignProfileDialog(Extension): def __init__(self, parent): super(AssignProfileDialog, self).__init__(parent) def assignProfile(self): doc = Application.activeDocument() if doc is None: - QMessageBox.information(Application.activeWindow().qwindow(), i18n("Assign Profile"), i18n("There is no active document.")) + QMessageBox.information( + Application.activeWindow().qwindow(), + i18n("Assign Profile"), + i18n("There is no active document.")) return self.dialog = QDialog(Application.activeWindow().qwindow()) self.cmbProfile = QComboBox(self.dialog) - for profile in sorted(Application.profiles(doc.colorModel(), doc.colorDepth())): + for profile in sorted( + Application.profiles(doc.colorModel(), doc.colorDepth())): self.cmbProfile.addItem(profile) vbox = QVBoxLayout(self.dialog) vbox.addWidget(self.cmbProfile) self.buttonBox = QDialogButtonBox(self.dialog) self.buttonBox.setOrientation(Qt.Horizontal) - self.buttonBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.buttonBox.setStandardButtons( + QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.buttonBox.accepted.connect(self.dialog.accept) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.dialog.reject) vbox.addWidget(self.buttonBox) self.dialog.show() self.dialog.activateWindow() self.dialog.exec_() def accept(self): doc = Application.activeDocument() doc.setColorProfile(self.cmbProfile.currentText()) def setup(self): pass def createActions(self, window): - action = window.createAction("assing_profile_to_image", i18n("Assign Profile to Image")) + action = window.createAction("assing_profile_to_image", + i18n("Assign Profile to Image")) action.triggered.connect(self.assignProfile) - - -Scripter.addExtension(AssignProfileDialog(Application)) diff --git a/plugins/python/colorspace/__init__.py b/plugins/python/colorspace/__init__.py index 8148cb38f5..cc5cc77064 100644 --- a/plugins/python/colorspace/__init__.py +++ b/plugins/python/colorspace/__init__.py @@ -1,13 +1,18 @@ -''' -This script is licensed CC 0 1.0, so that you can learn from it. +# This script is licensed CC 0 1.0, so that you can learn from it. ------- CC 0 1.0 --------------- +# ------ CC 0 1.0 --------------- -The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. +# The person who associated a work with this deed has dedicated the +# work to the public domain by waiving all of his or her rights to the +# work worldwide under copyright law, including all related and +# neighboring rights, to the extent allowed by law. -You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. +# You can copy, modify, distribute and perform the work, even for +# commercial purposes, all without asking permission. -https://creativecommons.org/publicdomain/zero/1.0/legalcode -''' -# let's make a module -from .colorspace import * +# https://creativecommons.org/publicdomain/zero/1.0/legalcode + +import krita +from .colorspace import ColorSpaceExtension + +Scripter.addExtension(ColorSpaceExtension(krita.Krita.instance())) diff --git a/plugins/python/colorspace/colorspace.py b/plugins/python/colorspace/colorspace.py index fc5a4ab710..7270b31ea9 100644 --- a/plugins/python/colorspace/colorspace.py +++ b/plugins/python/colorspace/colorspace.py @@ -1,34 +1,35 @@ -''' -This script is licensed CC 0 1.0, so that you can learn from it. +# This script is licensed CC 0 1.0, so that you can learn from it. ------- CC 0 1.0 --------------- +# ------ CC 0 1.0 --------------- -The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. +# The person who associated a work with this deed has dedicated the +# work to the public domain by waiving all of his or her rights to the +# work worldwide under copyright law, including all related and +# neighboring rights, to the extent allowed by law. -You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. +# You can copy, modify, distribute and perform the work, even for +# commercial purposes, all without asking permission. + +# https://creativecommons.org/publicdomain/zero/1.0/legalcode -https://creativecommons.org/publicdomain/zero/1.0/legalcode -''' import krita from . import uicolorspace class ColorSpaceExtension(krita.Extension): def __init__(self, parent): super(ColorSpaceExtension, self).__init__(parent) def setup(self): pass def createActions(self, window): action = window.createAction("color_space", i18n("Color Space")) - action.setToolTip(i18n("Plugin to change color space of selected documents.")) + action.setToolTip( + i18n("Plugin to change color space of selected documents.")) action.triggered.connect(self.initialize) def initialize(self): self.uicolorspace = uicolorspace.UIColorSpace() self.uicolorspace.initialize() - - -Scripter.addExtension(ColorSpaceExtension(krita.Krita.instance())) diff --git a/plugins/python/colorspace/colorspacedialog.py b/plugins/python/colorspace/colorspacedialog.py index 57e27e3d00..e1de2e61c2 100644 --- a/plugins/python/colorspace/colorspacedialog.py +++ b/plugins/python/colorspace/colorspacedialog.py @@ -1,21 +1,24 @@ -''' -This script is licensed CC 0 1.0, so that you can learn from it. +# This script is licensed CC 0 1.0, so that you can learn from it. ------- CC 0 1.0 --------------- +# ------ CC 0 1.0 --------------- -The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. +# The person who associated a work with this deed has dedicated the +# work to the public domain by waiving all of his or her rights to the +# work worldwide under copyright law, including all related and +# neighboring rights, to the extent allowed by law. -You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. +# You can copy, modify, distribute and perform the work, even for +# commercial purposes, all without asking permission. + +# https://creativecommons.org/publicdomain/zero/1.0/legalcode -https://creativecommons.org/publicdomain/zero/1.0/legalcode -''' from PyQt5.QtWidgets import QDialog class ColorSpaceDialog(QDialog): def __init__(self, parent=None): super(ColorSpaceDialog, self).__init__(parent) def closeEvent(self, event): event.accept() diff --git a/plugins/python/colorspace/components/colordepthcombobox.py b/plugins/python/colorspace/components/colordepthcombobox.py index e34d58393c..c97e4bbe36 100644 --- a/plugins/python/colorspace/components/colordepthcombobox.py +++ b/plugins/python/colorspace/components/colordepthcombobox.py @@ -1,25 +1,28 @@ -''' -This script is licensed CC 0 1.0, so that you can learn from it. +# This script is licensed CC 0 1.0, so that you can learn from it. ------- CC 0 1.0 --------------- +# ------ CC 0 1.0 --------------- -The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. +# The person who associated a work with this deed has dedicated the +# work to the public domain by waiving all of his or her rights to the +# work worldwide under copyright law, including all related and +# neighboring rights, to the extent allowed by law. -You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. +# You can copy, modify, distribute and perform the work, even for +# commercial purposes, all without asking permission. + +# https://creativecommons.org/publicdomain/zero/1.0/legalcode -https://creativecommons.org/publicdomain/zero/1.0/legalcode -''' from PyQt5.QtWidgets import QComboBox class ColorDepthComboBox(QComboBox): def __init__(self, uiColorSpace, parent=None): super(ColorDepthComboBox, self).__init__(parent) self.uiColorSpace = uiColorSpace self.currentTextChanged.connect(self.changedTextColorDepthComboBox) def changedTextColorDepthComboBox(self, colorDepth): self.uiColorSpace.loadColorProfiles() diff --git a/plugins/python/colorspace/components/colormodelcombobox.py b/plugins/python/colorspace/components/colormodelcombobox.py index 80ac4e7dba..0b55de9874 100644 --- a/plugins/python/colorspace/components/colormodelcombobox.py +++ b/plugins/python/colorspace/components/colormodelcombobox.py @@ -1,25 +1,28 @@ -''' -This script is licensed CC 0 1.0, so that you can learn from it. +# This script is licensed CC 0 1.0, so that you can learn from it. ------- CC 0 1.0 --------------- +# ------ CC 0 1.0 --------------- -The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. +# The person who associated a work with this deed has dedicated the +# work to the public domain by waiving all of his or her rights to the +# work worldwide under copyright law, including all related and +# neighboring rights, to the extent allowed by law. -You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. +# You can copy, modify, distribute and perform the work, even for +# commercial purposes, all without asking permission. + +# https://creativecommons.org/publicdomain/zero/1.0/legalcode -https://creativecommons.org/publicdomain/zero/1.0/legalcode -''' from PyQt5.QtWidgets import QComboBox class ColorModelComboBox(QComboBox): def __init__(self, uiColorSpace, parent=None): super(ColorModelComboBox, self).__init__(parent) self.uiColorSpace = uiColorSpace self.currentTextChanged.connect(self.changedTextColorModelComboBox) def changedTextColorModelComboBox(self, colorModel): self.uiColorSpace.loadColorDepths() diff --git a/plugins/python/colorspace/components/colorprofilecombobox.py b/plugins/python/colorspace/components/colorprofilecombobox.py index c067e34738..13a8ec9c36 100644 --- a/plugins/python/colorspace/components/colorprofilecombobox.py +++ b/plugins/python/colorspace/components/colorprofilecombobox.py @@ -1,21 +1,24 @@ -''' -This script is licensed CC 0 1.0, so that you can learn from it. +# This script is licensed CC 0 1.0, so that you can learn from it. ------- CC 0 1.0 --------------- +# ------ CC 0 1.0 --------------- -The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. +# The person who associated a work with this deed has dedicated the +# work to the public domain by waiving all of his or her rights to the +# work worldwide under copyright law, including all related and +# neighboring rights, to the extent allowed by law. -You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. +# You can copy, modify, distribute and perform the work, even for +# commercial purposes, all without asking permission. + +# https://creativecommons.org/publicdomain/zero/1.0/legalcode -https://creativecommons.org/publicdomain/zero/1.0/legalcode -''' from PyQt5.QtWidgets import QComboBox class ColorProfileComboBox(QComboBox): def __init__(self, uiColorSpace, parent=None): super(ColorProfileComboBox, self).__init__(parent) self.uiColorSpace = uiColorSpace self.setSizeAdjustPolicy(self.AdjustToContents) diff --git a/plugins/python/colorspace/uicolorspace.py b/plugins/python/colorspace/uicolorspace.py index d757a190f3..80107a87ca 100644 --- a/plugins/python/colorspace/uicolorspace.py +++ b/plugins/python/colorspace/uicolorspace.py @@ -1,129 +1,150 @@ -''' -This script is licensed CC 0 1.0, so that you can learn from it. +# This script is licensed CC 0 1.0, so that you can learn from it. ------- CC 0 1.0 --------------- +# ------ CC 0 1.0 --------------- -The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. +# The person who associated a work with this deed has dedicated the +# work to the public domain by waiving all of his or her rights to the +# work worldwide under copyright law, including all related and +# neighboring rights, to the extent allowed by law. -You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. +# You can copy, modify, distribute and perform the work, even for +# commercial purposes, all without asking permission. + +# https://creativecommons.org/publicdomain/zero/1.0/legalcode -https://creativecommons.org/publicdomain/zero/1.0/legalcode -''' from . import colorspacedialog -from .components import colormodelcombobox, colordepthcombobox, colorprofilecombobox +from .components import ( + colordepthcombobox, + colormodelcombobox, + colorprofilecombobox, +) from PyQt5.QtCore import Qt -from PyQt5.QtWidgets import (QFormLayout, QListWidget, QListWidgetItem, - QAbstractItemView, QComboBox, QDialogButtonBox, +from PyQt5.QtWidgets import (QFormLayout, QListWidget, + QAbstractItemView, QDialogButtonBox, QVBoxLayout, QFrame, QMessageBox, QPushButton, - QHBoxLayout, QAbstractScrollArea) + QAbstractScrollArea) from PyQt5.QtGui import QIcon import krita -from . import resources_rc class UIColorSpace(object): def __init__(self): self.mainDialog = colorspacedialog.ColorSpaceDialog() self.mainLayout = QVBoxLayout(self.mainDialog) self.formLayout = QFormLayout() self.documentLayout = QVBoxLayout() - self.refreshButton = QPushButton(QIcon(':/icons/refresh.svg'), i18n("Refresh")) + self.refreshButton = QPushButton(QIcon(':/icons/refresh.svg'), + i18n("Refresh")) self.widgetDocuments = QListWidget() self.colorModelComboBox = colormodelcombobox.ColorModelComboBox(self) self.colorDepthComboBox = colordepthcombobox.ColorDepthComboBox(self) - self.colorProfileComboBox = colorprofilecombobox.ColorProfileComboBox(self) - self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.colorProfileComboBox = \ + colorprofilecombobox.ColorProfileComboBox(self) + self.buttonBox = QDialogButtonBox( + QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.kritaInstance = krita.Krita.instance() self.documentsList = [] self.colorModelsList = [] self.colorDepthsList = [] self.colorProfilesList = [] self.refreshButton.clicked.connect(self.refreshButtonClicked) self.buttonBox.accepted.connect(self.confirmButton) self.buttonBox.rejected.connect(self.mainDialog.close) self.mainDialog.setWindowModality(Qt.NonModal) self.widgetDocuments.setSelectionMode(QAbstractItemView.MultiSelection) - self.widgetDocuments.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents) + self.widgetDocuments.setSizeAdjustPolicy( + QAbstractScrollArea.AdjustToContents) def initialize(self): self.loadDocuments() self.loadColorModels() self.loadColorDepths() self.loadColorProfiles() self.documentLayout.addWidget(self.widgetDocuments) self.documentLayout.addWidget(self.refreshButton) self.formLayout.addRow(i18n("Documents:"), self.documentLayout) self.formLayout.addRow(i18n("Color model:"), self.colorModelComboBox) self.formLayout.addRow(i18n("Color depth:"), self.colorDepthComboBox) - self.formLayout.addRow(i18n("Color profile:"), self.colorProfileComboBox) + self.formLayout.addRow(i18n("Color profile:"), + self.colorProfileComboBox) self.line = QFrame() self.line.setFrameShape(QFrame.HLine) self.line.setFrameShadow(QFrame.Sunken) self.mainLayout.addLayout(self.formLayout) self.mainLayout.addWidget(self.line) self.mainLayout.addWidget(self.buttonBox) self.mainDialog.resize(500, 300) self.mainDialog.setWindowTitle(i18n("Color Space")) self.mainDialog.setSizeGripEnabled(True) self.mainDialog.show() self.mainDialog.activateWindow() def loadColorModels(self): self.colorModelsList = sorted(self.kritaInstance.colorModels()) self.colorModelComboBox.addItems(self.colorModelsList) def loadColorDepths(self): self.colorDepthComboBox.clear() colorModel = self.colorModelComboBox.currentText() - self.colorDepthsList = sorted(self.kritaInstance.colorDepths(colorModel)) + self.colorDepthsList = sorted( + self.kritaInstance.colorDepths(colorModel)) self.colorDepthComboBox.addItems(self.colorDepthsList) def loadColorProfiles(self): self.colorProfileComboBox.clear() colorModel = self.colorModelComboBox.currentText() colorDepth = self.colorDepthComboBox.currentText() - self.colorProfilesList = sorted(self.kritaInstance.profiles(colorModel, colorDepth)) + self.colorProfilesList = sorted( + self.kritaInstance.profiles(colorModel, colorDepth)) self.colorProfileComboBox.addItems(self.colorProfilesList) def loadDocuments(self): self.widgetDocuments.clear() - self.documentsList = [document for document in self.kritaInstance.documents() if document.fileName()] + self.documentsList = [ + document for document in self.kritaInstance.documents() + if document.fileName() + ] for document in self.documentsList: self.widgetDocuments.addItem(document.fileName()) def refreshButtonClicked(self): self.loadDocuments() def confirmButton(self): - selectedPaths = [item.text() for item in self.widgetDocuments.selectedItems()] - selectedDocuments = [document for document in self.documentsList for path in selectedPaths if path == document.fileName()] + selectedPaths = [ + item.text() for item in self.widgetDocuments.selectedItems()] + selectedDocuments = [ + document for document in self.documentsList + for path in selectedPaths if path == document.fileName() + ] self.msgBox = QMessageBox(self.mainDialog) if selectedDocuments: self.convertColorSpace(selectedDocuments) - self.msgBox.setText(i18n("The selected documents has been converted.")) + self.msgBox.setText( + i18n("The selected documents has been converted.")) else: self.msgBox.setText(i18n("Select at least one document.")) self.msgBox.exec_() def convertColorSpace(self, documents): for document in documents: document.setColorSpace(self.colorModelComboBox.currentText(), self.colorDepthComboBox.currentText(), self.colorProfileComboBox.currentText()) diff --git a/plugins/python/documenttools/__init__.py b/plugins/python/documenttools/__init__.py index 34deb6c918..0908dbe4aa 100644 --- a/plugins/python/documenttools/__init__.py +++ b/plugins/python/documenttools/__init__.py @@ -1,2 +1,4 @@ -# let's make a module -from .documenttools import * +import krita +from .documenttools import DocumentToolsExtension + +Scripter.addExtension(DocumentToolsExtension(krita.Krita.instance())) diff --git a/plugins/python/documenttools/documenttools.py b/plugins/python/documenttools/documenttools.py index 2fbcdd6c77..79c591d2ed 100644 --- a/plugins/python/documenttools/documenttools.py +++ b/plugins/python/documenttools/documenttools.py @@ -1,34 +1,35 @@ -''' -This script is licensed CC 0 1.0, so that you can learn from it. +# This script is licensed CC 0 1.0, so that you can learn from it. ------- CC 0 1.0 --------------- +# ------ CC 0 1.0 --------------- -The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. +# The person who associated a work with this deed has dedicated the +# work to the public domain by waiving all of his or her rights to the +# work worldwide under copyright law, including all related and +# neighboring rights, to the extent allowed by law. -You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. +# You can copy, modify, distribute and perform the work, even for +# commercial purposes, all without asking permission. + +# https://creativecommons.org/publicdomain/zero/1.0/legalcode -https://creativecommons.org/publicdomain/zero/1.0/legalcode -''' import krita from . import uidocumenttools class DocumentToolsExtension(krita.Extension): def __init__(self, parent): super(DocumentToolsExtension, self).__init__(parent) def setup(self): pass def createActions(self, window): action = window.createAction("document_tools", i18n("Document Tools")) - action.setToolTip(i18n("Plugin to manipulate properties of selected documents.")) + action.setToolTip( + i18n("Plugin to manipulate properties of selected documents.")) action.triggered.connect(self.initialize) def initialize(self): self.uidocumenttools = uidocumenttools.UIDocumentTools() self.uidocumenttools.initialize() - - -Scripter.addExtension(DocumentToolsExtension(krita.Krita.instance())) diff --git a/plugins/python/documenttools/documenttoolsdialog.py b/plugins/python/documenttools/documenttoolsdialog.py index 441d378788..d170617e8e 100644 --- a/plugins/python/documenttools/documenttoolsdialog.py +++ b/plugins/python/documenttools/documenttoolsdialog.py @@ -1,21 +1,24 @@ -''' -This script is licensed CC 0 1.0, so that you can learn from it. +# This script is licensed CC 0 1.0, so that you can learn from it. ------- CC 0 1.0 --------------- +# ------ CC 0 1.0 --------------- -The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. +# The person who associated a work with this deed has dedicated the +# work to the public domain by waiving all of his or her rights to the +# work worldwide under copyright law, including all related and +# neighboring rights, to the extent allowed by law. -You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. +# You can copy, modify, distribute and perform the work, even for +# commercial purposes, all without asking permission. + +# https://creativecommons.org/publicdomain/zero/1.0/legalcode -https://creativecommons.org/publicdomain/zero/1.0/legalcode -''' from PyQt5.QtWidgets import QDialog class DocumentToolsDialog(QDialog): def __init__(self, parent=None): super(DocumentToolsDialog, self).__init__(parent) def closeEvent(self, event): event.accept() diff --git a/plugins/python/documenttools/tools/canvassizetool/canvassizetool.py b/plugins/python/documenttools/tools/canvassizetool/canvassizetool.py index 5d26f7575c..d58fe5844f 100644 --- a/plugins/python/documenttools/tools/canvassizetool/canvassizetool.py +++ b/plugins/python/documenttools/tools/canvassizetool/canvassizetool.py @@ -1,53 +1,55 @@ -''' -This script is licensed CC 0 1.0, so that you can learn from it. +# This script is licensed CC 0 1.0, so that you can learn from it. ------- CC 0 1.0 --------------- +# ------ CC 0 1.0 --------------- -The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. +# The person who associated a work with this deed has dedicated the +# work to the public domain by waiving all of his or her rights to the +# work worldwide under copyright law, including all related and +# neighboring rights, to the extent allowed by law. -You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. +# You can copy, modify, distribute and perform the work, even for +# commercial purposes, all without asking permission. -https://creativecommons.org/publicdomain/zero/1.0/legalcode -''' -from PyQt5.QtWidgets import (QWidget, QSpinBox, QHBoxLayout, +# https://creativecommons.org/publicdomain/zero/1.0/legalcode + +from PyQt5.QtWidgets import (QWidget, QSpinBox, QVBoxLayout, QFormLayout) -import krita class CanvasSizeTool(QWidget): def __init__(self, mainDialog, parent=None): super(CanvasSizeTool, self).__init__(parent) self.setObjectName("Canvas Size") self.layout = QFormLayout() self.offsetLayout = QVBoxLayout() self.widthSpinBox = QSpinBox() self.heightSpinBox = QSpinBox() self.xOffsetSpinBox = QSpinBox() self.yOffsetSpinBox = QSpinBox() self.setLayout(self.layout) self.initialize() def initialize(self): self.widthSpinBox.setRange(1, 10000) self.heightSpinBox.setRange(1, 10000) self.xOffsetSpinBox.setRange(-10000, 10000) self.yOffsetSpinBox.setRange(-10000, 10000) self.offsetLayout.addWidget(self.xOffsetSpinBox) self.offsetLayout.addWidget(self.yOffsetSpinBox) self.layout.addRow(i18n("Width:"), self.widthSpinBox) self.layout.addRow(i18n("Height:"), self.heightSpinBox) self.layout.addRow(i18n("Offset:"), self.offsetLayout) def adjust(self, documents): for document in documents: document.resizeImage(self.xOffsetSpinBox.value(), self.yOffsetSpinBox.value(), self.widthSpinBox.value(), self.heightSpinBox.value()) diff --git a/plugins/python/documenttools/tools/rotatetool/rotatetool.py b/plugins/python/documenttools/tools/rotatetool/rotatetool.py index ae3f1e20e0..a4b7574297 100644 --- a/plugins/python/documenttools/tools/rotatetool/rotatetool.py +++ b/plugins/python/documenttools/tools/rotatetool/rotatetool.py @@ -1,40 +1,42 @@ -''' -This script is licensed CC 0 1.0, so that you can learn from it. +# This script is licensed CC 0 1.0, so that you can learn from it. ------- CC 0 1.0 --------------- +# ------ CC 0 1.0 --------------- -The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. +# The person who associated a work with this deed has dedicated the +# work to the public domain by waiving all of his or her rights to the +# work worldwide under copyright law, including all related and +# neighboring rights, to the extent allowed by law. -You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. +# You can copy, modify, distribute and perform the work, even for +# commercial purposes, all without asking permission. -https://creativecommons.org/publicdomain/zero/1.0/legalcode -''' -from PyQt5.QtWidgets import (QWidget, QSpinBox, QHBoxLayout, - QVBoxLayout, QFormLayout) +# https://creativecommons.org/publicdomain/zero/1.0/legalcode + +from PyQt5.QtWidgets import QWidget, QSpinBox, QFormLayout import math -import krita class RotateTool(QWidget): def __init__(self, mainDialog, parent=None): super(RotateTool, self).__init__(parent) self.setObjectName("Rotate") self.layout = QFormLayout() self.degreesSpinBox = QSpinBox() self.setLayout(self.layout) self.initialize() def initialize(self): self.degreesSpinBox.setRange(-180, 180) - self.degreesSpinBox.setToolTip(i18n("Negative degrees will rotate the image to the left")) + self.degreesSpinBox.setToolTip( + i18n("Negative degrees will rotate the image to the left")) self.layout.addRow(i18n("Degrees:"), self.degreesSpinBox) def adjust(self, documents): for document in documents: document.rotateImage(math.radians(self.degreesSpinBox.value())) diff --git a/plugins/python/documenttools/tools/scaletool/scaletool.py b/plugins/python/documenttools/tools/scaletool/scaletool.py index f71e59fe85..10bba1cde5 100644 --- a/plugins/python/documenttools/tools/scaletool/scaletool.py +++ b/plugins/python/documenttools/tools/scaletool/scaletool.py @@ -1,61 +1,63 @@ -''' -This script is licensed CC 0 1.0, so that you can learn from it. +# This script is licensed CC 0 1.0, so that you can learn from it. ------- CC 0 1.0 --------------- +# ------ CC 0 1.0 --------------- -The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. +# The person who associated a work with this deed has dedicated the +# work to the public domain by waiving all of his or her rights to the +# work worldwide under copyright law, including all related and +# neighboring rights, to the extent allowed by law. -You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. +# You can copy, modify, distribute and perform the work, even for +# commercial purposes, all without asking permission. -https://creativecommons.org/publicdomain/zero/1.0/legalcode -''' -from PyQt5.QtWidgets import (QWidget, QSpinBox, QHBoxLayout, +# https://creativecommons.org/publicdomain/zero/1.0/legalcode + +from PyQt5.QtWidgets import (QWidget, QSpinBox, QVBoxLayout, QFormLayout, QComboBox) -import krita class ScaleTool(QWidget): def __init__(self, mainDialog, parent=None): super(ScaleTool, self).__init__(parent) self.setObjectName("Scale") self.layout = QFormLayout() self.resolutionLayout = QVBoxLayout() self.widthSpinBox = QSpinBox() self.heightSpinBox = QSpinBox() self.xResSpinBox = QSpinBox() self.yResSpinBox = QSpinBox() self.strategyComboBox = QComboBox() self.strategyComboBox.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.setLayout(self.layout) self.initialize() def initialize(self): self.widthSpinBox.setRange(1, 10000) self.heightSpinBox.setRange(1, 10000) self.xResSpinBox.setRange(1, 10000) self.yResSpinBox.setRange(1, 10000) strategies = ['Hermite', 'Bicubic', 'Box', 'Bilinear', 'Bell', 'BSpline', 'Kanczos3', 'Mitchell'] self.strategyComboBox.addItems(strategies) self.resolutionLayout.addWidget(self.xResSpinBox) self.resolutionLayout.addWidget(self.yResSpinBox) self.layout.addRow(i18n("Width:"), self.widthSpinBox) self.layout.addRow(i18n("Height:"), self.heightSpinBox) self.layout.addRow(i18n("Resolution:"), self.resolutionLayout) self.layout.addRow(i18n("Filter:"), self.strategyComboBox) def adjust(self, documents): for document in documents: document.scaleImage(self.widthSpinBox.value(), self.heightSpinBox.value(), self.xResSpinBox.value(), self.yResSpinBox.value(), self.strategyComboBox.currentText()) diff --git a/plugins/python/documenttools/uidocumenttools.py b/plugins/python/documenttools/uidocumenttools.py index ae85d202a6..604293d564 100644 --- a/plugins/python/documenttools/uidocumenttools.py +++ b/plugins/python/documenttools/uidocumenttools.py @@ -1,107 +1,119 @@ -''' -This script is licensed CC 0 1.0, so that you can learn from it. +# This script is licensed CC 0 1.0, so that you can learn from it. ------- CC 0 1.0 --------------- +# ------ CC 0 1.0 --------------- -The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. +# The person who associated a work with this deed has dedicated the +# work to the public domain by waiving all of his or her rights to the +# work worldwide under copyright law, including all related and +# neighboring rights, to the extent allowed by law. -You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. +# You can copy, modify, distribute and perform the work, even for +# commercial purposes, all without asking permission. + +# https://creativecommons.org/publicdomain/zero/1.0/legalcode -https://creativecommons.org/publicdomain/zero/1.0/legalcode -''' from . import documenttoolsdialog from PyQt5.QtCore import Qt from PyQt5.QtWidgets import (QFormLayout, QListWidget, QAbstractItemView, QDialogButtonBox, QVBoxLayout, QFrame, QTabWidget, QPushButton, QAbstractScrollArea, QMessageBox) import krita import importlib class UIDocumentTools(object): def __init__(self): self.mainDialog = documenttoolsdialog.DocumentToolsDialog() self.mainLayout = QVBoxLayout(self.mainDialog) self.formLayout = QFormLayout() self.documentLayout = QVBoxLayout() self.refreshButton = QPushButton(i18n("Refresh")) self.widgetDocuments = QListWidget() self.tabTools = QTabWidget() - self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.buttonBox = QDialogButtonBox( + QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.kritaInstance = krita.Krita.instance() self.documentsList = [] self.refreshButton.clicked.connect(self.refreshButtonClicked) self.buttonBox.accepted.connect(self.confirmButton) self.buttonBox.rejected.connect(self.mainDialog.close) self.mainDialog.setWindowModality(Qt.NonModal) self.widgetDocuments.setSelectionMode(QAbstractItemView.MultiSelection) - self.widgetDocuments.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents) + self.widgetDocuments.setSizeAdjustPolicy( + QAbstractScrollArea.AdjustToContents) def initialize(self): self.loadDocuments() self.loadTools() self.documentLayout.addWidget(self.widgetDocuments) self.documentLayout.addWidget(self.refreshButton) self.formLayout.addRow(i18n("Documents:"), self.documentLayout) self.formLayout.addRow(self.tabTools) self.line = QFrame() self.line.setFrameShape(QFrame.HLine) self.line.setFrameShadow(QFrame.Sunken) self.mainLayout.addLayout(self.formLayout) self.mainLayout.addWidget(self.line) self.mainLayout.addWidget(self.buttonBox) self.mainDialog.resize(500, 300) self.mainDialog.setWindowTitle(i18n("Document Tools")) self.mainDialog.setSizeGripEnabled(True) self.mainDialog.show() self.mainDialog.activateWindow() def loadTools(self): modulePath = 'documenttools.tools' toolsModule = importlib.import_module(modulePath) modules = [] for classPath in toolsModule.ToolClasses: _module = classPath[:classPath.rfind(".")] _klass = classPath[classPath.rfind(".") + 1:] modules.append(dict(module='{0}.{1}'.format(modulePath, _module), klass=_klass)) for module in modules: m = importlib.import_module(module['module']) toolClass = getattr(m, module['klass']) obj = toolClass(self.mainDialog) self.tabTools.addTab(obj, obj.objectName()) def loadDocuments(self): self.widgetDocuments.clear() - self.documentsList = [document for document in self.kritaInstance.documents() if document.fileName()] + self.documentsList = [ + document for document in self.kritaInstance.documents() + if document.fileName() + ] for document in self.documentsList: self.widgetDocuments.addItem(document.fileName()) def refreshButtonClicked(self): self.loadDocuments() def confirmButton(self): - selectedPaths = [item.text() for item in self.widgetDocuments.selectedItems()] - selectedDocuments = [document for document in self.documentsList for path in selectedPaths if path == document.fileName()] + selectedPaths = [ + item.text() for item in self.widgetDocuments.selectedItems()] + selectedDocuments = [ + document for document in self.documentsList + for path in selectedPaths if path == document.fileName()] self.msgBox = QMessageBox(self.mainDialog) if selectedDocuments: widget = self.tabTools.currentWidget() widget.adjust(selectedDocuments) - self.msgBox.setText(i18n("The selected documents has been modified.")) + self.msgBox.setText( + i18n("The selected documents has been modified.")) else: self.msgBox.setText(i18n("Select at least one document.")) self.msgBox.exec_() diff --git a/plugins/python/plugin_importer/plugin_importer.py b/plugins/python/plugin_importer/plugin_importer.py index 2e7c460c1c..c73e8a4bee 100644 --- a/plugins/python/plugin_importer/plugin_importer.py +++ b/plugins/python/plugin_importer/plugin_importer.py @@ -1,248 +1,248 @@ # Copyright (c) 2019 Rebecca Breu # This file is part of Krita. # Krita 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 3 of the License, or # (at your option) any later version. # Krita 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 Krita. If not, see . """This module provides the actual importing logic. See `:class:PluginImporter` for more info. For easy command line testing, call this module like this: > python plugin_importer.py foo.zip /output/path """ from configparser import ConfigParser, Error as ConfigParserError import os import shutil import sys from tempfile import TemporaryDirectory import zipfile from xml.etree import ElementTree class PluginImportError(Exception): """Base class for all exceptions of this module.""" pass class NoPluginsFoundException(PluginImportError): """No valid plugins can be found in the zip file.""" pass class PluginReadError(PluginImportError): """Zip file can't be read or its content can't be parsed.""" pass class PluginImporter: """Import a Krita Python Plugin from a zip file into the given directory. The Importer makes barely any assumptions about the file structure in the zip file. It will find one or more plugins with the following strategy: 1. Find files with the ending `.desktop` and read the Python module name from them 2. Find directories that correspond to the Python module names and that contain an `__init__.py` file 3. Find files with ending `.action` that have matching `` tags (these files are optional) 4. Extract the desktop- and action-files and the Python module directories into the corresponding pykrita and actions folders Usage: >>> importer = PluginImporter( '/path/to/plugin.zip', '/path/to/krita/resources/', confirm_overwrite_callback) >>> imported = importer.import_all() """ def __init__(self, zip_filename, resources_dir, confirm_overwrite_callback): """Initialise the importer. :param zip_filename: Filename of the zip archive containing the plugin(s) :param resources_dir: The Krita resources directory into which to extract the plugin(s) :param confirm_overwrite_callback: A function that gets called if a plugin already exists in the resources directory. It gets called with a dictionary of information about the plugin and should return whether the user wants to overwrite the plugin (True) or not (False). """ self.resources_dir = resources_dir self.confirm_overwrite_callback = confirm_overwrite_callback try: self.archive = zipfile.ZipFile(zip_filename) except(zipfile.BadZipFile, zipfile.LargeZipFile, OSError) as e: raise PluginReadError(str(e)) self.desktop_filenames = [] self.action_filenames = [] for filename in self.archive.namelist(): if filename.endswith('.desktop'): self.desktop_filenames.append(filename) if filename.endswith('.action'): self.action_filenames.append(filename) @property def destination_pykrita(self): dest = os.path.join(self.resources_dir, 'pykrita') if not os.path.exists(dest): os.mkdir(dest) return dest @property def destination_actions(self): dest = os.path.join(self.resources_dir, 'actions') if not os.path.exists(dest): os.mkdir(dest) return dest def get_destination_module(self, plugin): return os.path.join(self.destination_pykrita, plugin['name']) def get_destination_desktop(self, plugin): return os.path.join( self.destination_pykrita, '%s.desktop' % plugin['name']) def get_destination_actionfile(self, plugin): return os.path.join( self.destination_actions, '%s.action' % plugin['name']) def get_source_module(self, name): namelist = self.archive.namelist() for filename in namelist: if (filename.endswith('/%s/' % name) or filename == '%s/' % name): # Sanity check: There should be an __init__.py inside if ('%s__init__.py' % filename) in namelist: return filename def get_source_actionfile(self, name): for filename in self.action_filenames: try: root = ElementTree.fromstring( self.archive.read(filename).decode('utf-8')) except ElementTree.ParseError as e: raise PluginReadError( '%s: %s' % (i18n('Action file'), str(e))) for action in root.findall('./Actions/Action'): if action.get('name') == name: return filename def read_desktop_config(self, desktop_filename): config = ConfigParser() try: config.read_string( self.archive.read(desktop_filename).decode('utf-8')) except ConfigParserError as e: - raise PluginReadError( - '%s: %s' % (i18n('Desktop file'), str(e))) + raise PluginReadError( + '%s: %s' % (i18n('Desktop file'), str(e))) return config def get_plugin_info(self): names = [] for filename in self.desktop_filenames: config = self.read_desktop_config(filename) try: name = config['Desktop Entry']['X-KDE-Library'] ui_name = config['Desktop Entry']['Name'] except KeyError as e: raise PluginReadError( 'Desktop file: Key %s not found' % str(e)) module = self.get_source_module(name) if module: names.append({ 'name': name, 'ui_name': ui_name, 'desktop': filename, 'module': module, 'action': self.get_source_actionfile(name) }) return names def extract_desktop(self, plugin): with open(self.get_destination_desktop(plugin), 'wb') as f: f.write(self.archive.read(plugin['desktop'])) def extract_module(self, plugin): with TemporaryDirectory() as tmp_dir: for name in self.archive.namelist(): if name.startswith(plugin['module']): self.archive.extract(name, tmp_dir) module_dirname = os.path.join( tmp_dir, *plugin['module'].split('/')) try: shutil.rmtree(self.get_destination_module(plugin)) except FileNotFoundError: pass shutil.copytree(module_dirname, self.get_destination_module(plugin)) def extract_actionfile(self, plugin): with open(self.get_destination_actionfile(plugin), 'wb') as f: f.write(self.archive.read(plugin['action'])) def extract_plugin(self, plugin): # Check if the plugin already exists in the source directory: if (os.path.exists(self.get_destination_desktop(plugin)) or os.path.exists(self.get_destination_module(plugin))): confirmed = self.confirm_overwrite_callback(plugin) if not confirmed: return False self.extract_desktop(plugin) self.extract_module(plugin) if plugin['action']: self.extract_actionfile(plugin) return True def import_all(self): """Imports all plugins from the zip archive. Returns a list of imported plugins. """ plugins = self.get_plugin_info() if not plugins: raise NoPluginsFoundException(i18n('No plugins found in archive')) imported = [] for plugin in plugins: success = self.extract_plugin(plugin) if success: imported.append(plugin) return imported if __name__ == '__main__': def callback(plugin): print('Overwriting plugin:', plugin['ui_name']) return True imported = PluginImporter( sys.argv[1], sys.argv[2], callback).import_all() for plugin in imported: print('Imported plugin:', plugin['ui_name']) diff --git a/setup.cfg b/setup.cfg index b646049a1d..8f9693a3da 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,4 +1,5 @@ # Setting for various Python tools (code checks, unit tests etc) [flake8] builtins = i18n,Scripter,Application,Krita +exclude = resources_rc.py