diff --git a/libs/flake/html/HtmlSavingContext.h b/libs/flake/html/HtmlSavingContext.h index 3142d0856b..d9228c98d9 100644 --- a/libs/flake/html/HtmlSavingContext.h +++ b/libs/flake/html/HtmlSavingContext.h @@ -1,51 +1,51 @@ /* * Copyright (C) 2017 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef HTMLSAVINGCONTEXT_H #define HTMLSAVINGCONTEXT_H #include class KoXmlWriter; class KoShape; class KoImageData; class QIODevice; class QString; class QTransform; class QImage; /** * @brief The HtmlSavingContext class provides context for saving a flake-based document * to html. */ class HtmlSavingContext { public: HtmlSavingContext(QIODevice &shapeDevice); virtual ~HtmlSavingContext(); /// Provides access to the shape writer KoXmlWriter &shapeWriter(); private: - Q_DISABLE_COPY(HtmlSavingContext); + Q_DISABLE_COPY(HtmlSavingContext) private: struct Private; const QScopedPointer d; }; #endif // HTMLSAVINGCONTEXT_H diff --git a/libs/image/KisOptimizedByteArray.cpp b/libs/image/KisOptimizedByteArray.cpp index 1fbb14d26b..e138130097 100644 --- a/libs/image/KisOptimizedByteArray.cpp +++ b/libs/image/KisOptimizedByteArray.cpp @@ -1,240 +1,240 @@ /* * Copyright (c) 2017 Dmitry Kazakov * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KisOptimizedByteArray.h" #include #include #include namespace { /*****************************************************************/ /* DefaultMemoryAllocator */ /*****************************************************************/ struct DefaultMemoryAllocator : KisOptimizedByteArray::MemoryAllocator { KisOptimizedByteArray::MemoryChunk alloc(int size) override { return KisOptimizedByteArray::MemoryChunk(new quint8[size], size); } void free(KisOptimizedByteArray::MemoryChunk chunk) override { // chunk.first might be null delete[] chunk.first; } }; /*****************************************************************/ /* DefaultMemoryAllocatorStore */ /*****************************************************************/ struct DefaultMemoryAllocatorStore { static DefaultMemoryAllocatorStore* instance(); DefaultMemoryAllocatorStore() : m_allocator(new DefaultMemoryAllocator()) { } inline KisOptimizedByteArray::MemoryAllocatorSP allocator() const { return m_allocator; } private: KisOptimizedByteArray::MemoryAllocatorSP m_allocator; }; -Q_GLOBAL_STATIC(DefaultMemoryAllocatorStore, s_instance); +Q_GLOBAL_STATIC(DefaultMemoryAllocatorStore, s_instance) DefaultMemoryAllocatorStore *DefaultMemoryAllocatorStore::instance() { return s_instance; } } // namespace /*****************************************************************/ /* KisOptimizedByteArray::PooledMemoryAllocator */ /*****************************************************************/ KisOptimizedByteArray::PooledMemoryAllocator::PooledMemoryAllocator() : m_meanSize(500) { } KisOptimizedByteArray::PooledMemoryAllocator::~PooledMemoryAllocator() { Q_FOREACH (const MemoryChunk &chunk, m_chunks) { delete[] chunk.first; } } KisOptimizedByteArray::MemoryChunk KisOptimizedByteArray::PooledMemoryAllocator::alloc(int size) { MemoryChunk chunk; { QMutexLocker l(&m_mutex); if (!m_chunks.isEmpty()) { chunk = m_chunks.takeLast(); } m_meanSize(size); } if (chunk.second < size) { delete[] chunk.first; // we alloc a bit more memory for the dabs to let the chunks // be more reusable const int allocSize = 1.2 * size; chunk = KisOptimizedByteArray::MemoryChunk(new quint8[allocSize], allocSize); } return chunk; } void KisOptimizedByteArray::PooledMemoryAllocator::free(KisOptimizedByteArray::MemoryChunk chunk) { if (chunk.first) { QMutexLocker l(&m_mutex); // keep bigger chunks for ourselves and return the // smaller ones to the system if (chunk.second > 0.8 * m_meanSize.rollingMean()) { m_chunks.append(chunk); } else { delete[] chunk.first; } } } /*****************************************************************/ /* KisOptimizedByteArray::Private */ /*****************************************************************/ struct KisOptimizedByteArray::Private : public QSharedData { Private(MemoryAllocatorSP _allocator) { storedAllocator = _allocator ? _allocator : DefaultMemoryAllocatorStore::instance()->allocator(); allocator = storedAllocator.data(); } Private(const Private &rhs) : QSharedData(rhs) { allocator = rhs.allocator; storedAllocator = rhs.storedAllocator; dataSize = rhs.dataSize; if (dataSize) { data = allocator->alloc(dataSize); memcpy(data.first, rhs.data.first, dataSize); } } ~Private() { allocator->free(data); } MemoryAllocator *allocator; // stored allocator shared pointer is used only for keeping // the lifetime of the allocator until the detach of the last // allocated chunk MemoryAllocatorSP storedAllocator; MemoryChunk data; int dataSize = 0; }; /*****************************************************************/ /* KisOptimizedByteArray */ /*****************************************************************/ KisOptimizedByteArray::KisOptimizedByteArray(MemoryAllocatorSP allocator) : m_d(new Private(allocator)) { } KisOptimizedByteArray::KisOptimizedByteArray(const KisOptimizedByteArray &rhs) : m_d(rhs.m_d) { } KisOptimizedByteArray &KisOptimizedByteArray::operator=(const KisOptimizedByteArray &rhs) { m_d = rhs.m_d; return *this; } KisOptimizedByteArray::~KisOptimizedByteArray() { } quint8 *KisOptimizedByteArray::data() { return const_cast(m_d.data())->data.first; } const quint8 *KisOptimizedByteArray::constData() const { return const_cast(m_d.constData())->data.first; } void KisOptimizedByteArray::resize(int size) { if (size == m_d->dataSize) return; if (size > m_d->data.second) { m_d->allocator->free(m_d->data); m_d->data = m_d->allocator->alloc(size); } m_d->dataSize = size; } void KisOptimizedByteArray::fill(quint8 value, int size) { resize(size); memset(m_d->data.first, value, m_d->dataSize); } int KisOptimizedByteArray::size() const { return m_d->dataSize; } bool KisOptimizedByteArray::isEmpty() const { return !m_d->dataSize; } KisOptimizedByteArray::MemoryAllocatorSP KisOptimizedByteArray::customMemoryAllocator() const { return m_d->storedAllocator; } diff --git a/libs/image/brushengine/kis_locked_properties.h b/libs/image/brushengine/kis_locked_properties.h index ad9bcf8799..5b363251b5 100644 --- a/libs/image/brushengine/kis_locked_properties.h +++ b/libs/image/brushengine/kis_locked_properties.h @@ -1,53 +1,53 @@ /* * Copyright (c) 2014 Dmitry Kazakov * Copyright (c) 2014 Mohit Goyal * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KISLOCKEDPROPERTIES_H #define KISLOCKEDPROPERTIES_H #include "kis_properties_configuration.h" /** * This class maintains a list of all the PaintOp Options that are supposed to be * constant across all paintops and presets. * addToLockedProperties() adds all the settings mentioned in the parameter to the list * removeFromLockedProperties() removes a particular set of properties from the list * hasProperty() checks for a particular property in the list */ class KisLockedProperties : public KisShared { public: KisLockedProperties(); ~KisLockedProperties(); /**Whenever any setting is made locked**/ void addToLockedProperties(KisPropertiesConfigurationSP p); void addToLockedProperties(const KisPropertiesConfiguration *p); /**Whenever any property is unlocked**/ void removeFromLockedProperties(KisPropertiesConfigurationSP p); void removeFromLockedProperties(const KisPropertiesConfiguration *p); bool hasProperty(const QString &p); KisPropertiesConfigurationSP lockedProperties(); private: - Q_DISABLE_COPY(KisLockedProperties); + Q_DISABLE_COPY(KisLockedProperties) KisPropertiesConfigurationSP m_lockedProperties; }; #endif // KISLOCKEDPROPERTIES_H diff --git a/libs/image/brushengine/kis_locked_properties_server.cpp b/libs/image/brushengine/kis_locked_properties_server.cpp index 3c6c61d7ed..2729d0e648 100644 --- a/libs/image/brushengine/kis_locked_properties_server.cpp +++ b/libs/image/brushengine/kis_locked_properties_server.cpp @@ -1,87 +1,87 @@ /* * Copyright (c) 2014 Dmitry Kazakov * Copyright (c) 2014 Mohit Goyal * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include -Q_GLOBAL_STATIC(KisLockedPropertiesServer, s_instance); +Q_GLOBAL_STATIC(KisLockedPropertiesServer, s_instance) KisLockedPropertiesServer::KisLockedPropertiesServer() { m_lockedProperties = new KisLockedProperties(); m_propertiesFromLocked = false; } KisLockedPropertiesServer::~KisLockedPropertiesServer() { } KisLockedPropertiesProxySP KisLockedPropertiesServer::createLockedPropertiesProxy(KisPropertiesConfiguration *settings) { return new KisLockedPropertiesProxy(settings, lockedProperties()); } KisLockedPropertiesProxySP KisLockedPropertiesServer::createLockedPropertiesProxy(KisPropertiesConfigurationSP settings) { return createLockedPropertiesProxy(settings.data()); } KisLockedPropertiesServer* KisLockedPropertiesServer::instance() { if (s_instance) { return s_instance; } return NULL; } KisLockedPropertiesSP KisLockedPropertiesServer::lockedProperties() { return m_lockedProperties; } void KisLockedPropertiesServer::addToLockedProperties(KisPropertiesConfigurationSP p) { lockedProperties()->addToLockedProperties(p); } void KisLockedPropertiesServer::removeFromLockedProperties(KisPropertiesConfigurationSP p) { lockedProperties()->removeFromLockedProperties(p); } void KisLockedPropertiesServer::setPropertiesFromLocked(bool value) { m_propertiesFromLocked = value; } bool KisLockedPropertiesServer::propertiesFromLocked() { return m_propertiesFromLocked; } bool KisLockedPropertiesServer::hasProperty(const QString &p) { return m_lockedProperties->hasProperty(p); } diff --git a/libs/image/commands/kis_deselect_global_selection_command.cpp b/libs/image/commands/kis_deselect_global_selection_command.cpp index 919757c055..abb40a50db 100644 --- a/libs/image/commands/kis_deselect_global_selection_command.cpp +++ b/libs/image/commands/kis_deselect_global_selection_command.cpp @@ -1,54 +1,54 @@ /* * Copyright (c) 2007 Sven Langkamp * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_selection_commands.h" #include #include "kis_image.h" #include "kis_selection.h" #include "kis_undo_adapter.h" #include "kis_selection_mask.h" #include "kis_pixel_selection.h" KisDeselectGlobalSelectionCommand::KisDeselectGlobalSelectionCommand(KisImageWSP image, KUndo2Command * parent) : - KUndo2Command(kundo2_i18n("Deselect"), parent) - , m_image(image) + KUndo2Command(kundo2_i18n("Deselect"), parent) + , m_image(image) { } KisDeselectGlobalSelectionCommand::~KisDeselectGlobalSelectionCommand() { } void KisDeselectGlobalSelectionCommand::redo() { KisImageSP image = m_image.toStrongRef(); if (image) { m_oldSelection = image->globalSelection(); image->deselectGlobalSelection(); } } void KisDeselectGlobalSelectionCommand::undo() { KisImageSP image = m_image.toStrongRef(); if (image) { image->setGlobalSelection(m_oldSelection); } } diff --git a/libs/image/kis_fast_math.cpp b/libs/image/kis_fast_math.cpp index f83032f9ab..4b6fe8df74 100644 --- a/libs/image/kis_fast_math.cpp +++ b/libs/image/kis_fast_math.cpp @@ -1,132 +1,132 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * adopted from here http://www.snippetcenter.org/en/a-fast-atan2-function-s1868.aspx */ #include "kis_fast_math.h" #include #include #include #include #include // Algorithm from http://www.snippetcenter.org/en/a-fast-atan2-function-s1868.aspx const qreal MAX_SECOND_DERIV_IN_RANGE = 0.6495; /// precision const qreal MAX_ERROR = 0.0001; struct KisATanTable { KisATanTable() { qreal nf = ::sqrt(MAX_SECOND_DERIV_IN_RANGE / (8 * MAX_ERROR)); NUM_ATAN_ENTRIES = int(nf) + 1; // Build table qreal y = 10.0; qreal x; ATanTable = new qreal[NUM_ATAN_ENTRIES + 1]; ATanTable[0] = 0.0; for (quint32 i = 1; i <= NUM_ATAN_ENTRIES; i++) { x = (y / i) * NUM_ATAN_ENTRIES; ATanTable[i] = (qreal)::atan2(y, x); } } ~KisATanTable() { delete [] ATanTable; } quint32 NUM_ATAN_ENTRIES; qreal* ATanTable; }; -Q_GLOBAL_STATIC(KisATanTable, kisATanTable); +Q_GLOBAL_STATIC(KisATanTable, kisATanTable) /// private functions inline qreal interp(qreal r, qreal a, qreal b) { return r*(b - a) + a; } inline qreal calcAngle(qreal x, qreal y) { static qreal af = kisATanTable->NUM_ATAN_ENTRIES; static int ai = kisATanTable->NUM_ATAN_ENTRIES; static qreal* ATanTable = kisATanTable->ATanTable; qreal di = (y / x) * af; int i = (int)(di); if (i >= ai) return ::atan2(y, x); return interp(di - i, ATanTable[i], ATanTable[i+1]); } qreal KisFastMath::atan2(qreal y, qreal x) { if (y == 0.0) { // the line is horizontal if (x >= 0.0) { // towards the right return(0.0);// the angle is 0 } // toward the left return qreal(M_PI); } // we now know that y is not 0 check x if (x == 0.0) { // the line is vertical if (y > 0.0) { return M_PI_2; } return -M_PI_2; } // from here on we know that niether x nor y is 0 if (x > 0.0) { // we are in quadrant 1 or 4 if (y > 0.0) { // we are in quadrant 1 // now figure out which side of the 45 degree line if (x > y) { return(calcAngle(x, y)); } return(M_PI_2 - calcAngle(y, x)); } // we are in quadrant 4 y = -y; // now figure out which side of the 45 degree line if (x > y) { return(-calcAngle(x, y)); } return(-M_PI_2 + calcAngle(y, x)); } // we are in quadrant 2 or 3 x = -x; // flip x so we can use it as a positive if (y > 0.0) { // we are in quadrant 2 // now figure out which side of the 45 degree line if (x > y) { return(M_PI - calcAngle(x, y)); } return(M_PI_2 + calcAngle(y, x)); } // we are in quadrant 3 y = -y; // flip y so we can use it as a positive // now figure out which side of the 45 degree line if (x > y) { return(-M_PI + calcAngle(x, y)); } return(-M_PI_2 - calcAngle(y, x)); } diff --git a/libs/image/kis_layer_utils.h b/libs/image/kis_layer_utils.h index 821fcc0745..706c0769d5 100644 --- a/libs/image/kis_layer_utils.h +++ b/libs/image/kis_layer_utils.h @@ -1,224 +1,224 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_LAYER_UTILS_H #define __KIS_LAYER_UTILS_H #include #include "kundo2command.h" #include "kis_types.h" #include "kritaimage_export.h" #include "kis_command_utils.h" class KoProperties; class KoColor; class QUuid; namespace KisMetaData { class MergeStrategy; } namespace KisLayerUtils { KRITAIMAGE_EXPORT void sortMergableNodes(KisNodeSP root, QList &inputNodes, QList &outputNodes); KRITAIMAGE_EXPORT KisNodeList sortMergableNodes(KisNodeSP root, KisNodeList nodes); KRITAIMAGE_EXPORT void filterMergableNodes(KisNodeList &nodes, bool allowMasks = false); KRITAIMAGE_EXPORT bool checkIsChildOf(KisNodeSP node, const KisNodeList &parents); /** * Returns true if: * o \p node is a clone of some layer in \p nodes * o \p node is a clone any child layer of any layer in \p nodes * o \p node is a clone of a clone of a ..., that in the end points * to any layer in \p nodes of their children. */ KRITAIMAGE_EXPORT bool checkIsCloneOf(KisNodeSP node, const KisNodeList &nodes); KRITAIMAGE_EXPORT void forceAllDelayedNodesUpdate(KisNodeSP root); KRITAIMAGE_EXPORT KisNodeList sortAndFilterMergableInternalNodes(KisNodeList nodes, bool allowMasks = false); KRITAIMAGE_EXPORT void mergeDown(KisImageSP image, KisLayerSP layer, const KisMetaData::MergeStrategy* strategy); KRITAIMAGE_EXPORT QSet fetchLayerFrames(KisNodeSP node); KRITAIMAGE_EXPORT QSet fetchLayerFramesRecursive(KisNodeSP rootNode); KRITAIMAGE_EXPORT void mergeMultipleLayers(KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter); KRITAIMAGE_EXPORT void newLayerFromVisible(KisImageSP image, KisNodeSP putAfter); KRITAIMAGE_EXPORT bool tryMergeSelectionMasks(KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter); KRITAIMAGE_EXPORT void flattenLayer(KisImageSP image, KisLayerSP layer); KRITAIMAGE_EXPORT void flattenImage(KisImageSP image, KisNodeSP activeNode); KRITAIMAGE_EXPORT void addCopyOfNameTag(KisNodeSP node); KRITAIMAGE_EXPORT KisNodeList findNodesWithProps(KisNodeSP root, const KoProperties &props, bool excludeRoot); KRITAIMAGE_EXPORT void changeImageDefaultProjectionColor(KisImageSP image, const KoColor &color); typedef QMap > FrameJobs; void updateFrameJobs(FrameJobs *jobs, KisNodeSP node); void updateFrameJobsRecursive(FrameJobs *jobs, KisNodeSP rootNode); struct SwitchFrameCommand : public KisCommandUtils::FlipFlopCommand { struct SharedStorage { /** * For some reason the absence of a destructor in the SharedStorage * makes Krita crash on exit. Seems like some compiler weirdness... (DK) */ ~SharedStorage(); int value; }; typedef QSharedPointer SharedStorageSP; public: SwitchFrameCommand(KisImageSP image, int time, bool finalize, SharedStorageSP storage); ~SwitchFrameCommand() override; private: void partA() override; void partB() override; private: KisImageWSP m_image; int m_newTime; SharedStorageSP m_storage; }; /** * A command to keep correct set of selected/active nodes thoroughout * the action. */ class KRITAIMAGE_EXPORT KeepNodesSelectedCommand : public KisCommandUtils::FlipFlopCommand { public: KeepNodesSelectedCommand(const KisNodeList &selectedBefore, const KisNodeList &selectedAfter, KisNodeSP activeBefore, KisNodeSP activeAfter, KisImageSP image, bool finalize, KUndo2Command *parent = 0); void partB() override; private: KisNodeList m_selectedBefore; KisNodeList m_selectedAfter; KisNodeSP m_activeBefore; KisNodeSP m_activeAfter; KisImageWSP m_image; }; struct KRITAIMAGE_EXPORT SelectGlobalSelectionMask : public KUndo2Command { SelectGlobalSelectionMask(KisImageSP image); void redo() override; KisImageSP m_image; }; class KRITAIMAGE_EXPORT RemoveNodeHelper { public: virtual ~RemoveNodeHelper(); protected: virtual void addCommandImpl(KUndo2Command *cmd) = 0; void safeRemoveMultipleNodes(KisNodeList nodes, KisImageSP image); private: bool checkIsSourceForClone(KisNodeSP src, const KisNodeList &nodes); static bool scanForLastLayer(KisImageWSP image, KisNodeList nodesToRemove); }; struct SimpleRemoveLayers : private KisLayerUtils::RemoveNodeHelper, public KisCommandUtils::AggregateCommand { SimpleRemoveLayers(const KisNodeList &nodes, KisImageSP image); void populateChildCommands() override; protected: void addCommandImpl(KUndo2Command *cmd) override; private: KisNodeList m_nodes; KisImageSP m_image; KisNodeList m_selectedNodes; KisNodeSP m_activeNode; }; class KRITAIMAGE_EXPORT KisSimpleUpdateCommand : public KisCommandUtils::FlipFlopCommand { public: KisSimpleUpdateCommand(KisNodeList nodes, bool finalize, KUndo2Command *parent = 0); void partB() override; static void updateNodes(const KisNodeList &nodes); private: KisNodeList m_nodes; }; template bool checkNodesDiffer(KisNodeList nodes, std::function checkerFunc) { bool valueDiffers = false; bool initialized = false; T currentValue = T(); Q_FOREACH (KisNodeSP node, nodes) { if (!initialized) { currentValue = checkerFunc(node); initialized = true; } else if (currentValue != checkerFunc(node)) { valueDiffers = true; break; } } return valueDiffers; } /** * Applies \p func to \p node and all its children recursively */ template void recursiveApplyNodes(NodePointer node, Functor func) { func(node); node = node->firstChild(); while (node) { recursiveApplyNodes(node, func); node = node->nextSibling(); } } /** * Walks through \p node and all its children recursively until * \p func returns true. When \p func returns true, the node is * considered to be found, the search is stopped and the found * node is returned to the caller. */ KisNodeSP KRITAIMAGE_EXPORT recursiveFindNode(KisNodeSP node, std::function func); /** * Recursively searches for a node with specified Uuid */ KisNodeSP KRITAIMAGE_EXPORT findNodeByUuid(KisNodeSP root, const QUuid &uuid); KisImageSP KRITAIMAGE_EXPORT findImageByHierarchy(KisNodeSP node); -}; +} #endif /* __KIS_LAYER_UTILS_H */ diff --git a/libs/image/kis_onion_skin_compositor.cpp b/libs/image/kis_onion_skin_compositor.cpp index af843ae89e..9e408005e7 100644 --- a/libs/image/kis_onion_skin_compositor.cpp +++ b/libs/image/kis_onion_skin_compositor.cpp @@ -1,227 +1,227 @@ /* * Copyright (c) 2015 Jouni Pentikäinen * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_onion_skin_compositor.h" #include "kis_paint_device.h" #include "kis_painter.h" #include "KoColor.h" #include "KoColorSpace.h" #include "KoCompositeOpRegistry.h" #include "KoColorSpaceConstants.h" #include "kis_image_config.h" #include "kis_raster_keyframe_channel.h" -Q_GLOBAL_STATIC(KisOnionSkinCompositor, s_instance); +Q_GLOBAL_STATIC(KisOnionSkinCompositor, s_instance) struct KisOnionSkinCompositor::Private { int numberOfSkins = 0; int tintFactor = 0; QColor backwardTintColor; QColor forwardTintColor; QVector backwardOpacities; QVector forwardOpacities; int configSeqNo = 0; QList colorLabelFilter; int skinOpacity(int offset) { const QVector &bo = backwardOpacities; const QVector &fo = forwardOpacities; return offset > 0 ? fo[qAbs(offset) - 1] : bo[qAbs(offset) - 1]; } KisPaintDeviceSP setUpTintDevice(const QColor &tintColor, const KoColorSpace *colorSpace) { KisPaintDeviceSP tintDevice = new KisPaintDevice(colorSpace); KoColor color = KoColor(tintColor, colorSpace); tintDevice->setDefaultPixel(color); return tintDevice; } KisKeyframeSP getNextFrameToComposite(KisKeyframeChannel *channel, KisKeyframeSP keyframe, bool backwards) { while (!keyframe.isNull()) { keyframe = backwards ? channel->previousKeyframe(keyframe) : channel->nextKeyframe(keyframe); if (colorLabelFilter.isEmpty()) { return keyframe; } else if (!keyframe.isNull()) { if (colorLabelFilter.contains(keyframe->colorLabel())) { return keyframe; } } } return keyframe; } void tryCompositeFrame(KisRasterKeyframeChannel *keyframes, KisKeyframeSP keyframe, KisPainter &gcFrame, KisPainter &gcDest, KisPaintDeviceSP tintSource, int opacity, const QRect &rect) { if (keyframe.isNull() || opacity == OPACITY_TRANSPARENT_U8) return; keyframes->fetchFrame(keyframe, gcFrame.device()); gcFrame.bitBlt(rect.topLeft(), tintSource, rect); gcDest.setOpacity(opacity); gcDest.bitBlt(rect.topLeft(), gcFrame.device(), rect); } void refreshConfig() { KisImageConfig config(true); numberOfSkins = config.numberOfOnionSkins(); tintFactor = config.onionSkinTintFactor(); backwardTintColor = config.onionSkinTintColorBackward(); forwardTintColor = config.onionSkinTintColorForward(); backwardOpacities.resize(numberOfSkins); forwardOpacities.resize(numberOfSkins); const int mainState = (int) config.onionSkinState(0); const qreal scaleFactor = mainState * config.onionSkinOpacity(0) / 255.0; for (int i = 0; i < numberOfSkins; i++) { int backwardState = (int) config.onionSkinState(-(i + 1)); int forwardState = (int) config.onionSkinState(i + 1); backwardOpacities[i] = scaleFactor * backwardState * config.onionSkinOpacity(-(i + 1)); forwardOpacities[i] = scaleFactor * forwardState * config.onionSkinOpacity(i + 1); } configSeqNo++; } }; KisOnionSkinCompositor *KisOnionSkinCompositor::instance() { return s_instance; } KisOnionSkinCompositor::KisOnionSkinCompositor() : m_d(new Private) { m_d->refreshConfig(); } KisOnionSkinCompositor::~KisOnionSkinCompositor() {} int KisOnionSkinCompositor::configSeqNo() const { return m_d->configSeqNo; } void KisOnionSkinCompositor::setColorLabelFilter(QList colors) { m_d->colorLabelFilter = colors; } void KisOnionSkinCompositor::composite(const KisPaintDeviceSP sourceDevice, KisPaintDeviceSP targetDevice, const QRect& rect) { KisRasterKeyframeChannel *keyframes = sourceDevice->keyframeChannel(); KisPaintDeviceSP frameDevice = new KisPaintDevice(sourceDevice->colorSpace()); KisPainter gcFrame(frameDevice); QBitArray channelFlags = targetDevice->colorSpace()->channelFlags(true, false); gcFrame.setChannelFlags(channelFlags); gcFrame.setOpacity(m_d->tintFactor); KisPaintDeviceSP backwardTintDevice = m_d->setUpTintDevice(m_d->backwardTintColor, sourceDevice->colorSpace()); KisPaintDeviceSP forwardTintDevice = m_d->setUpTintDevice(m_d->forwardTintColor, sourceDevice->colorSpace()); KisPainter gcDest(targetDevice); gcDest.setCompositeOp(sourceDevice->colorSpace()->compositeOp(COMPOSITE_BEHIND)); KisKeyframeSP keyframeBck; KisKeyframeSP keyframeFwd; int time = sourceDevice->defaultBounds()->currentTime(); keyframeBck = keyframeFwd = keyframes->activeKeyframeAt(time); for (int offset = 1; offset <= m_d->numberOfSkins; offset++) { keyframeBck = m_d->getNextFrameToComposite(keyframes, keyframeBck, true); keyframeFwd = m_d->getNextFrameToComposite(keyframes, keyframeFwd, false); if (!keyframeBck.isNull()) { m_d->tryCompositeFrame(keyframes, keyframeBck, gcFrame, gcDest, backwardTintDevice, m_d->skinOpacity(-offset), rect); } if (!keyframeFwd.isNull()) { m_d->tryCompositeFrame(keyframes, keyframeFwd, gcFrame, gcDest, forwardTintDevice, m_d->skinOpacity(offset), rect); } } } QRect KisOnionSkinCompositor::calculateFullExtent(const KisPaintDeviceSP device) { QRect rect; KisRasterKeyframeChannel *channel = device->keyframeChannel(); if (!channel) return rect; KisKeyframeSP keyframe = channel->firstKeyframe(); while (keyframe) { rect |= channel->frameExtents(keyframe); keyframe = channel->nextKeyframe(keyframe); } return rect; } QRect KisOnionSkinCompositor::calculateExtent(const KisPaintDeviceSP device) { QRect rect; KisKeyframeSP keyframeBck; KisKeyframeSP keyframeFwd; KisRasterKeyframeChannel *channel = device->keyframeChannel(); keyframeBck = keyframeFwd = channel->activeKeyframeAt(device->defaultBounds()->currentTime()); for (int offset = 1; offset <= m_d->numberOfSkins; offset++) { if (!keyframeBck.isNull()) { keyframeBck = channel->previousKeyframe(keyframeBck); if (!keyframeBck.isNull()) { rect |= channel->frameExtents(keyframeBck); } } if (!keyframeFwd.isNull()) { keyframeFwd = channel->nextKeyframe(keyframeFwd); if (!keyframeFwd.isNull()) { rect |= channel->frameExtents(keyframeFwd); } } } return rect; } void KisOnionSkinCompositor::configChanged() { m_d->refreshConfig(); emit sigOnionSkinChanged(); } diff --git a/libs/image/kis_selection_mask.h b/libs/image/kis_selection_mask.h index 76e264350d..9fd6467cac 100644 --- a/libs/image/kis_selection_mask.h +++ b/libs/image/kis_selection_mask.h @@ -1,100 +1,100 @@ /* * Copyright (c) 2006 Boudewijn Rempt * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _KIS_SELECTION_MASK_ #define _KIS_SELECTION_MASK_ #include #include "kis_base_node.h" #include "kis_types.h" #include "kis_effect_mask.h" /** * An selection mask is a single channel mask that applies a * particular selection to the layer the mask belongs to. A selection * can contain both vector and pixel selection components. */ class KRITAIMAGE_EXPORT KisSelectionMask : public KisEffectMask { Q_OBJECT public: /** * Create an empty selection mask. There is filter and no layer * associated with this mask. */ KisSelectionMask(KisImageWSP image); ~KisSelectionMask() override; KisSelectionMask(const KisSelectionMask& rhs); QIcon icon() const override; KisNodeSP clone() const override { return KisNodeSP(new KisSelectionMask(*this)); } /// Set the selection of this adjustment layer to a copy of selection. void setSelection(KisSelectionSP selection); bool accept(KisNodeVisitor &v) override; void accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter) override; KisBaseNode::PropertyList sectionModelProperties() const override; void setSectionModelProperties(const KisBaseNode::PropertyList &properties) override; void setVisible(bool visible, bool isLoading = false) override; bool active() const; void setActive(bool active); QRect needRect(const QRect &rect, PositionToFilthy pos = N_FILTHY) const override; QRect changeRect(const QRect &rect, PositionToFilthy pos = N_FILTHY) const override; QRect extent() const override; QRect exactBounds() const override; /** * This method works like the one in KisSelection, but it * compressed the incoming events instead of processing each of * them separately. */ void notifySelectionChangedCompressed(); protected: void flattenSelectionProjection(KisSelectionSP selection, const QRect &dirtyRect) const override; void mergeInMaskInternal(KisPaintDeviceSP projection, KisSelectionSP effectiveSelection, const QRect &applyRect, const QRect &preparedNeedRect, KisNode::PositionToFilthy maskPos) const override; bool paintsOutsideSelection() const override; private: - Q_PRIVATE_SLOT(m_d, void slotSelectionChangedCompressed()); - Q_PRIVATE_SLOT(m_d, void slotConfigChanged()); + Q_PRIVATE_SLOT(m_d, void slotSelectionChangedCompressed()) + Q_PRIVATE_SLOT(m_d, void slotConfigChanged()) KisImageWSP image() const; struct Private; Private * const m_d; }; #endif //_KIS_SELECTION_MASK_ diff --git a/libs/image/kis_time_range.h b/libs/image/kis_time_range.h index ca103bed7e..d861dc565f 100644 --- a/libs/image/kis_time_range.h +++ b/libs/image/kis_time_range.h @@ -1,153 +1,153 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_TIME_RANGE_H #define __KIS_TIME_RANGE_H #include "kritaimage_export.h" #include #include #include #include #include "kis_types.h" #include class KRITAIMAGE_EXPORT KisTimeRange : public boost::equality_comparable { public: inline KisTimeRange() : m_start(0), m_end(-1) { } inline KisTimeRange(int start, int duration) : m_start(start), m_end(start + duration - 1) { } inline KisTimeRange(int start, int end, bool) : m_start(start), m_end(end) { } bool operator==(const KisTimeRange &rhs) const { return rhs.m_start == m_start && rhs.m_end == m_end; } KisTimeRange& operator|=(const KisTimeRange &rhs) { if (!isValid()) { m_start = rhs.start(); } else if (rhs.isValid()) { m_start = std::min(m_start, rhs.start()); } if (rhs.isInfinite() || isInfinite()) { m_end = std::numeric_limits::min(); } else if (!isValid()) { m_end = rhs.m_end; } else { m_end = std::max(m_end, rhs.m_end); } return *this; } KisTimeRange& operator&=(const KisTimeRange &rhs) { if (!isValid()) { return *this; } else if (!rhs.isValid()) { m_start = rhs.start(); m_end = rhs.m_end; return *this; } else { m_start = std::max(m_start, rhs.start()); } if (isInfinite()) { m_end = rhs.m_end; } else if (!rhs.isInfinite()) { m_end = std::min(m_end, rhs.m_end); } return *this; } inline int start() const { return m_start; } inline int end() const { return m_end; } inline int duration() const { return m_end >= m_start ? m_end - m_start + 1 : 0; } inline bool isInfinite() const { return m_end == std::numeric_limits::min(); } inline bool isValid() const { return (m_end >= m_start) || (m_end == std::numeric_limits::min() && m_start >= 0); } inline bool contains(int time) const { if (m_end == std::numeric_limits::min()) { return m_start <= time; } return m_start <= time && time <= m_end; } static inline KisTimeRange fromTime(int start, int end) { return KisTimeRange(start, end, true); } static inline KisTimeRange infinite(int start) { return KisTimeRange(start, std::numeric_limits::min(), true); } static KisTimeRange calculateIdenticalFramesRecursive(const KisNode *node, int time); static KisTimeRange calculateAffectedFramesRecursive(const KisNode *node, int time); static KisTimeRange calculateNodeIdenticalFrames(const KisNode *node, int time); static KisTimeRange calculateNodeAffectedFrames(const KisNode *node, int time); private: int m_start; int m_end; }; namespace KisDomUtils { void KRITAIMAGE_EXPORT saveValue(QDomElement *parent, const QString &tag, const KisTimeRange &range); bool KRITAIMAGE_EXPORT loadValue(const QDomElement &parent, const QString &tag, KisTimeRange *range); } -Q_DECLARE_METATYPE(KisTimeRange); +Q_DECLARE_METATYPE(KisTimeRange) KRITAIMAGE_EXPORT QDebug operator<<(QDebug dbg, const KisTimeRange &r); #endif /* __KIS_TIME_RANGE_H */ diff --git a/libs/image/lazybrush/kis_lazy_fill_tools.h b/libs/image/lazybrush/kis_lazy_fill_tools.h index ad81e3c4a3..43fcd5de41 100644 --- a/libs/image/lazybrush/kis_lazy_fill_tools.h +++ b/libs/image/lazybrush/kis_lazy_fill_tools.h @@ -1,98 +1,98 @@ /* * Copyright (c) 2016 Dmitry Kazakov * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_LAZY_FILL_TOOLS_H #define __KIS_LAZY_FILL_TOOLS_H #include "kis_types.h" #include "kritaimage_export.h" #include #include class KoColor; namespace KisLazyFillTools { KRITAIMAGE_EXPORT void normalizeAndInvertAlpha8Device(KisPaintDeviceSP dev, const QRect &rect); KRITAIMAGE_EXPORT void normalizeAlpha8Device(KisPaintDeviceSP dev, const QRect &rect); /** * Uses Boykov-Kolmogorov Max-Flow/Min-Cut algorithm to split the * device \p src into two parts. The first part is defined by \p * colorScribble and the second part --- by \p * backgroundScribble. In the result of the split the area defined * by \p colorScribble in \p resultDevice is filled with \p * color. Also the same area in \p maskDevice is filled with a * non-null scribble index. * * \p maskDevice is used for limiting the area used for filling * the color. */ KRITAIMAGE_EXPORT void cutOneWay(const KoColor &color, KisPaintDeviceSP src, KisPaintDeviceSP colorScribble, KisPaintDeviceSP backgroundScribble, KisPaintDeviceSP resultDevice, KisPaintDeviceSP maskDevice, const QRect &boundingRect); /** * Returns one pixel from each connected component of \p src. * * WARNING: \p src is used as a temporary device, so it will be * cleared(!) after the execution of the algorithm */ KRITAIMAGE_EXPORT QVector splitIntoConnectedComponents(KisPaintDeviceSP src, const QRect &boundingRect); struct KRITAIMAGE_EXPORT KeyStroke : public boost::equality_comparable { KeyStroke(); KeyStroke(KisPaintDeviceSP _dev, const KoColor &_color, bool isTransparent = false); friend bool operator==(const KeyStroke& t1, const KeyStroke&t2); KisPaintDeviceSP dev; KoColor color; bool isTransparent; }; struct KRITAIMAGE_EXPORT FilteringOptions : public boost::equality_comparable { FilteringOptions() = default; FilteringOptions(bool _useEdgeDetection, qreal _edgeDetectionSize, qreal _fuzzyRadius, qreal _cleanUpAmount); friend bool operator==(const FilteringOptions &t1, const FilteringOptions &t2); // default values for filtering: disabled bool useEdgeDetection = false; qreal edgeDetectionSize = 4; qreal fuzzyRadius = 0; qreal cleanUpAmount = 0.0; }; -}; +} #endif /* __KIS_LAZY_FILL_TOOLS_H */ diff --git a/libs/pigment/KoColor.cpp b/libs/pigment/KoColor.cpp index 983e501ddc..c476d909b6 100644 --- a/libs/pigment/KoColor.cpp +++ b/libs/pigment/KoColor.cpp @@ -1,427 +1,427 @@ /* * Copyright (c) 2005 Boudewijn Rempt * Copyright (C) 2007 Thomas Zander * Copyright (C) 2007 Cyrille Berger * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoColor.h" #include #include #include "DebugPigment.h" #include "KoColorModelStandardIds.h" #include "KoColorProfile.h" #include "KoColorSpace.h" #include "KoColorSpaceRegistry.h" #include "KoChannelInfo.h" #include "kis_assert.h" #include #include #ifdef HAVE_OPENEXR #include #endif namespace { struct DefaultKoColorInitializer { DefaultKoColorInitializer() { const KoColorSpace *defaultColorSpace = KoColorSpaceRegistry::instance()->rgb16(0); KIS_ASSERT(defaultColorSpace); value = new KoColor(Qt::black, defaultColorSpace); #ifndef NODEBUG #ifndef QT_NO_DEBUG // warn about rather expensive checks in assertPermanentColorspace(). qWarning() << "KoColor debug runtime checks are active."; #endif #endif } KoColor *value = 0; }; -Q_GLOBAL_STATIC(DefaultKoColorInitializer, s_defaultKoColor); +Q_GLOBAL_STATIC(DefaultKoColorInitializer, s_defaultKoColor) } KoColor::KoColor() { *this = *s_defaultKoColor->value; } KoColor::KoColor(const KoColorSpace * colorSpace) { Q_ASSERT(colorSpace); m_colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(colorSpace); m_size = m_colorSpace->pixelSize(); Q_ASSERT(m_size <= MAX_PIXEL_SIZE); memset(m_data, 0, m_size); } KoColor::KoColor(const QColor & color, const KoColorSpace * colorSpace) { Q_ASSERT(color.isValid()); Q_ASSERT(colorSpace); m_colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(colorSpace); m_size = m_colorSpace->pixelSize(); Q_ASSERT(m_size <= MAX_PIXEL_SIZE); memset(m_data, 0, m_size); m_colorSpace->fromQColor(color, m_data); } KoColor::KoColor(const quint8 * data, const KoColorSpace * colorSpace) { Q_ASSERT(colorSpace); Q_ASSERT(data); m_colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(colorSpace); m_size = m_colorSpace->pixelSize(); Q_ASSERT(m_size <= MAX_PIXEL_SIZE); memmove(m_data, data, m_size); } KoColor::KoColor(const KoColor &src, const KoColorSpace * colorSpace) { Q_ASSERT(colorSpace); m_colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(colorSpace); m_size = m_colorSpace->pixelSize(); Q_ASSERT(m_size <= MAX_PIXEL_SIZE); memset(m_data, 0, m_size); src.colorSpace()->convertPixelsTo(src.m_data, m_data, colorSpace, 1, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); } void KoColor::convertTo(const KoColorSpace * cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) { //dbgPigment <<"Our colormodel:" << d->colorSpace->id().name() // << ", new colormodel: " << cs->id().name() << "\n"; if (*m_colorSpace == *cs) return; quint8 data[MAX_PIXEL_SIZE]; const size_t size = cs->pixelSize(); Q_ASSERT(size <= MAX_PIXEL_SIZE); memset(data, 0, size); m_colorSpace->convertPixelsTo(m_data, data, cs, 1, renderingIntent, conversionFlags); memcpy(m_data, data, size); m_size = size; m_colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(cs); } void KoColor::convertTo(const KoColorSpace * cs) { convertTo(cs, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); } KoColor KoColor::convertedTo(const KoColorSpace *cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const { KoColor result(*this); result.convertTo(cs, renderingIntent, conversionFlags); return result; } KoColor KoColor::convertedTo(const KoColorSpace *cs) const { return convertedTo(cs, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); } void KoColor::setProfile(const KoColorProfile *profile) { const KoColorSpace *dstColorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorSpace()->colorModelId().id(), colorSpace()->colorDepthId().id(), profile); if (!dstColorSpace) return; m_colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(dstColorSpace); } void KoColor::setColor(const quint8 * data, const KoColorSpace * colorSpace) { Q_ASSERT(colorSpace); const size_t size = colorSpace->pixelSize(); Q_ASSERT(size <= MAX_PIXEL_SIZE); memcpy(m_data, data, size); m_colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(colorSpace); } // To save the user the trouble of doing color->colorSpace()->toQColor(color->data(), &c, &a, profile void KoColor::toQColor(QColor *c) const { Q_ASSERT(c); if (m_colorSpace) { m_colorSpace->toQColor(m_data, c); } } QColor KoColor::toQColor() const { QColor c; toQColor(&c); return c; } void KoColor::fromQColor(const QColor& c) { if (m_colorSpace) { m_colorSpace->fromQColor(c, m_data); } } void KoColor::subtract(const KoColor &value) { KIS_SAFE_ASSERT_RECOVER_RETURN(*m_colorSpace == *value.colorSpace()); QVector channels1(m_colorSpace->channelCount()); QVector channels2(m_colorSpace->channelCount()); m_colorSpace->normalisedChannelsValue(m_data, channels1); m_colorSpace->normalisedChannelsValue(value.data(), channels2); for (int i = 0; i < channels1.size(); i++) { channels1[i] -= channels2[i]; } m_colorSpace->fromNormalisedChannelsValue(m_data, channels1); } KoColor KoColor::subtracted(const KoColor &value) const { KoColor result(*this); result.subtract(value); return result; } void KoColor::add(const KoColor &value) { KIS_SAFE_ASSERT_RECOVER_RETURN(*m_colorSpace == *value.colorSpace()); QVector channels1(m_colorSpace->channelCount()); QVector channels2(m_colorSpace->channelCount()); m_colorSpace->normalisedChannelsValue(m_data, channels1); m_colorSpace->normalisedChannelsValue(value.data(), channels2); for (int i = 0; i < channels1.size(); i++) { channels1[i] += channels2[i]; } m_colorSpace->fromNormalisedChannelsValue(m_data, channels1); } KoColor KoColor::added(const KoColor &value) const { KoColor result(*this); result.add(value); return result; } #ifndef NDEBUG void KoColor::dump() const { dbgPigment <<"KoColor (" << this <<")," << m_colorSpace->id() <<""; QList channels = m_colorSpace->channels(); QList::const_iterator begin = channels.constBegin(); QList::const_iterator end = channels.constEnd(); for (QList::const_iterator it = begin; it != end; ++it) { KoChannelInfo * ch = (*it); // XXX: setNum always takes a byte. if (ch->size() == sizeof(quint8)) { // Byte dbgPigment <<"Channel (byte):" << ch->name() <<":" << QString().setNum(m_data[ch->pos()]) <<""; } else if (ch->size() == sizeof(quint16)) { // Short (may also by an nvidia half) dbgPigment <<"Channel (short):" << ch->name() <<":" << QString().setNum(*((const quint16 *)(m_data+ch->pos()))) <<""; } else if (ch->size() == sizeof(quint32)) { // Integer (may also be float... Find out how to distinguish these!) dbgPigment <<"Channel (int):" << ch->name() <<":" << QString().setNum(*((const quint32 *)(m_data+ch->pos()))) <<""; } } } #endif void KoColor::fromKoColor(const KoColor& src) { src.colorSpace()->convertPixelsTo(src.m_data, m_data, colorSpace(), 1, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); } const KoColorProfile *KoColor::profile() const { return m_colorSpace->profile(); } void KoColor::toXML(QDomDocument& doc, QDomElement& colorElt) const { m_colorSpace->colorToXML(m_data, doc, colorElt); } void KoColor::setOpacity(quint8 alpha) { m_colorSpace->setOpacity(m_data, alpha, 1); } void KoColor::setOpacity(qreal alpha) { m_colorSpace->setOpacity(m_data, alpha, 1); } quint8 KoColor::opacityU8() const { return m_colorSpace->opacityU8(m_data); } qreal KoColor::opacityF() const { return m_colorSpace->opacityF(m_data); } KoColor KoColor::fromXML(const QDomElement& elt, const QString& bitDepthId) { bool ok; return fromXML(elt, bitDepthId, &ok); } KoColor KoColor::fromXML(const QDomElement& elt, const QString& bitDepthId, bool* ok) { *ok = true; QString modelId; if (elt.tagName() == "CMYK") { modelId = CMYKAColorModelID.id(); } else if (elt.tagName() == "RGB") { modelId = RGBAColorModelID.id(); } else if (elt.tagName() == "sRGB") { modelId = RGBAColorModelID.id(); } else if (elt.tagName() == "Lab") { modelId = LABAColorModelID.id(); } else if (elt.tagName() == "XYZ") { modelId = XYZAColorModelID.id(); } else if (elt.tagName() == "Gray") { modelId = GrayAColorModelID.id(); } else if (elt.tagName() == "YCbCr") { modelId = YCbCrAColorModelID.id(); } QString profileName; if (elt.tagName() != "sRGB") { profileName = elt.attribute("space", ""); if (!KoColorSpaceRegistry::instance()->profileByName(profileName)) { profileName.clear(); } } const KoColorSpace* cs = KoColorSpaceRegistry::instance()->colorSpace(modelId, bitDepthId, profileName); if (cs == 0) { QList list = KoColorSpaceRegistry::instance()->colorDepthList(modelId, KoColorSpaceRegistry::AllColorSpaces); if (!list.empty()) { cs = KoColorSpaceRegistry::instance()->colorSpace(modelId, list[0].id(), profileName); } } if (cs) { KoColor c(cs); // TODO: Provide a way for colorFromXML() to notify the caller if parsing failed. Currently it returns default values on failure. cs->colorFromXML(c.data(), elt); return c; } else { *ok = false; return KoColor(); } } QString KoColor::toQString(const KoColor &color) { QStringList ls; Q_FOREACH (KoChannelInfo *channel, KoChannelInfo::displayOrderSorted(color.colorSpace()->channels())) { int realIndex = KoChannelInfo::displayPositionToChannelIndex(channel->displayPosition(), color.colorSpace()->channels()); ls << channel->name(); ls << color.colorSpace()->channelValueText(color.data(), realIndex); } return ls.join(" "); } QDebug operator<<(QDebug dbg, const KoColor &color) { dbg.nospace() << "KoColor (" << color.colorSpace()->id(); QList channels = color.colorSpace()->channels(); for (auto it = channels.constBegin(); it != channels.constEnd(); ++it) { KoChannelInfo *ch = (*it); dbg.nospace() << ", " << ch->name() << ":"; switch (ch->channelValueType()) { case KoChannelInfo::UINT8: { const quint8 *ptr = reinterpret_cast(color.data() + ch->pos()); dbg.nospace() << *ptr; break; } case KoChannelInfo::UINT16: { const quint16 *ptr = reinterpret_cast(color.data() + ch->pos()); dbg.nospace() << *ptr; break; } case KoChannelInfo::UINT32: { const quint32 *ptr = reinterpret_cast(color.data() + ch->pos()); dbg.nospace() << *ptr; break; } case KoChannelInfo::FLOAT16: { #ifdef HAVE_OPENEXR const half *ptr = reinterpret_cast(color.data() + ch->pos()); dbg.nospace() << *ptr; #else const quint16 *ptr = reinterpret_cast(color.data() + ch->pos()); dbg.nospace() << "UNSUPPORTED_F16(" << *ptr << ")"; #endif break; } case KoChannelInfo::FLOAT32: { const float *ptr = reinterpret_cast(color.data() + ch->pos()); dbg.nospace() << *ptr; break; } case KoChannelInfo::FLOAT64: { const double *ptr = reinterpret_cast(color.data() + ch->pos()); dbg.nospace() << *ptr; break; } case KoChannelInfo::INT8: { const qint8 *ptr = reinterpret_cast(color.data() + ch->pos()); dbg.nospace() << *ptr; break; } case KoChannelInfo::INT16: { const qint16 *ptr = reinterpret_cast(color.data() + ch->pos()); dbg.nospace() << *ptr; break; } case KoChannelInfo::OTHER: { const quint8 *ptr = reinterpret_cast(color.data() + ch->pos()); dbg.nospace() << "undef(" << *ptr << ")"; break; } } } dbg.nospace() << ")"; return dbg.space(); } diff --git a/libs/pigment/KoColorSpaceEngine.cpp b/libs/pigment/KoColorSpaceEngine.cpp index f941c5c257..359268e8cd 100644 --- a/libs/pigment/KoColorSpaceEngine.cpp +++ b/libs/pigment/KoColorSpaceEngine.cpp @@ -1,76 +1,76 @@ /* * Copyright (c) 2008 Cyrille Berger * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include -Q_GLOBAL_STATIC(KoColorSpaceEngineRegistry, s_instance); +Q_GLOBAL_STATIC(KoColorSpaceEngineRegistry, s_instance) struct Q_DECL_HIDDEN KoColorSpaceEngine::Private { QString id; QString name; }; KoColorSpaceEngine::KoColorSpaceEngine(const QString& id, const QString& name) : d(new Private) { d->id = id; d->name = name; } KoColorSpaceEngine::~KoColorSpaceEngine() { delete d; } const QString& KoColorSpaceEngine::id() const { return d->id; } const QString& KoColorSpaceEngine::name() const { return d->name; } bool KoColorSpaceEngine::supportsColorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile) const { Q_UNUSED(colorModelId); Q_UNUSED(colorDepthId); Q_UNUSED(profile); return true; } KoColorSpaceEngineRegistry::KoColorSpaceEngineRegistry() { } KoColorSpaceEngineRegistry::~KoColorSpaceEngineRegistry() { Q_FOREACH (KoColorSpaceEngine* item, values()) { delete item; } } KoColorSpaceEngineRegistry* KoColorSpaceEngineRegistry::instance() { return s_instance; } diff --git a/libs/pigment/resources/KoHashGeneratorProvider.cpp b/libs/pigment/resources/KoHashGeneratorProvider.cpp index b2bcb53d2b..8dbfcad073 100644 --- a/libs/pigment/resources/KoHashGeneratorProvider.cpp +++ b/libs/pigment/resources/KoHashGeneratorProvider.cpp @@ -1,59 +1,59 @@ /* * Copyright (c) 2015 Stefano Bonicatti * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoHashGeneratorProvider.h" #include #include #include "KoMD5Generator.h" KoHashGeneratorProvider *KoHashGeneratorProvider::instance_var = 0; -Q_GLOBAL_STATIC(KoHashGeneratorProvider, s_instance); +Q_GLOBAL_STATIC(KoHashGeneratorProvider, s_instance) KoHashGeneratorProvider::KoHashGeneratorProvider() { // Initialize default generators hashGenerators.insert("MD5", new KoMD5Generator()); } KoHashGeneratorProvider::~KoHashGeneratorProvider() { qDeleteAll(hashGenerators); } KoHashGenerator *KoHashGeneratorProvider::getGenerator(const QString &algorithm) { QMutexLocker locker(&mutex); return hashGenerators.value(algorithm); } void KoHashGeneratorProvider::setGenerator(const QString &algorithm, KoHashGenerator *generator) { if (hashGenerators.contains(algorithm)) { delete hashGenerators.take(algorithm); hashGenerators[algorithm] = generator; } else hashGenerators.insert(algorithm, generator); } KoHashGeneratorProvider *KoHashGeneratorProvider::instance() { return s_instance; } diff --git a/libs/widgets/KoResourceServerProvider.cpp b/libs/widgets/KoResourceServerProvider.cpp index 0a89dc691b..f33db43416 100644 --- a/libs/widgets/KoResourceServerProvider.cpp +++ b/libs/widgets/KoResourceServerProvider.cpp @@ -1,198 +1,198 @@ /* This file is part of the KDE project Copyright (c) 1999 Matthias Elter Copyright (c) 2003 Patrick Julien Copyright (c) 2005 Sven Langkamp Copyright (C) 2011 Srikanth Tiyyagura This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "KoResourceServerProvider.h" #include #include #include #include #include #include #include #include #include "KoColorSpaceRegistry.h" #include "KoResourcePaths.h" #include using namespace std; class GradientResourceServer : public KoResourceServer { public: GradientResourceServer(const QString& type, const QString& extensions) : KoResourceServer(type, extensions) , m_foregroundToTransparent(0) , m_foregroundToBackground(0) { insertSpecialGradients(); } void insertSpecialGradients() { const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8(); QList stops; KoStopGradient* gradient = new KoStopGradient(); gradient->setType(QGradient::LinearGradient); gradient->setName("Foreground to Transparent"); stops << KoGradientStop(0.0, KoColor(Qt::black, cs)) << KoGradientStop(1.0, KoColor(QColor(0, 0, 0, 0), cs)); gradient->setStops(stops); gradient->setValid(true); gradient->setPermanent(true); addResource(gradient, false, true); m_foregroundToTransparent = gradient; gradient = new KoStopGradient(); gradient->setType(QGradient::LinearGradient); gradient->setName("Foreground to Background"); stops.clear(); stops << KoGradientStop(0.0, KoColor(Qt::black, cs)) << KoGradientStop(1.0, KoColor(Qt::white, cs)); gradient->setStops(stops); gradient->setValid(true); gradient->setPermanent(true); addResource(gradient, false, true); m_foregroundToBackground = gradient; } private: friend class KoResourceBundle; KoAbstractGradient* createResource( const QString & filename ) override { QString fileExtension; int index = filename.lastIndexOf('.'); if (index != -1) fileExtension = filename.mid(index).toLower(); KoAbstractGradient* grad = 0; if(fileExtension == ".svg" || fileExtension == ".kgr") grad = new KoStopGradient(filename); else if(fileExtension == ".ggr" ) grad = new KoSegmentGradient(filename); return grad; } QList< KoAbstractGradient* > sortedResources() override { QList< KoAbstractGradient* > resources = KoResourceServer::sortedResources(); QList< KoAbstractGradient* > sorted; if (m_foregroundToTransparent && resources.contains(m_foregroundToTransparent)) { sorted.append(resources.takeAt(resources.indexOf(m_foregroundToTransparent))); } if (m_foregroundToBackground && resources.contains(m_foregroundToBackground)) { sorted.append(resources.takeAt(resources.indexOf(m_foregroundToBackground))); } return sorted + resources; } KoAbstractGradient* m_foregroundToTransparent; KoAbstractGradient* m_foregroundToBackground; }; struct Q_DECL_HIDDEN KoResourceServerProvider::Private { KoResourceServer* patternServer; KoResourceServer* gradientServer; KoResourceServer* paletteServer; KoResourceServer *svgSymbolCollectionServer; KoResourceServer* gamutMaskServer; }; KoResourceServerProvider::KoResourceServerProvider() : d(new Private) { d->patternServer = new KoResourceServerSimpleConstruction("ko_patterns", "*.pat:*.jpg:*.gif:*.png:*.tif:*.xpm:*.bmp" ); d->patternServer->loadResources(blacklistFileNames(d->patternServer->fileNames(), d->patternServer->blackListedFiles())); d->gradientServer = new GradientResourceServer("ko_gradients", "*.svg:*.ggr"); d->gradientServer->loadResources(blacklistFileNames(d->gradientServer->fileNames(), d->gradientServer->blackListedFiles())); d->paletteServer = new KoResourceServerSimpleConstruction("ko_palettes", "*.kpl:*.gpl:*.pal:*.act:*.aco:*.css:*.colors:*.xml:*.sbz"); d->paletteServer->loadResources(blacklistFileNames(d->paletteServer->fileNames(), d->paletteServer->blackListedFiles())); d->svgSymbolCollectionServer = new KoResourceServerSimpleConstruction("symbols", "*.svg"); d->svgSymbolCollectionServer->loadResources(blacklistFileNames(d->svgSymbolCollectionServer->fileNames(), d->svgSymbolCollectionServer->blackListedFiles())); d->gamutMaskServer = new KoResourceServerSimpleConstruction("ko_gamutmasks", "*.kgm"); d->gamutMaskServer->loadResources(blacklistFileNames(d->gamutMaskServer->fileNames(), d->gamutMaskServer->blackListedFiles())); } KoResourceServerProvider::~KoResourceServerProvider() { delete d->patternServer; delete d->gradientServer; delete d->paletteServer; delete d->svgSymbolCollectionServer; delete d->gamutMaskServer; delete d; } -Q_GLOBAL_STATIC(KoResourceServerProvider, s_instance); +Q_GLOBAL_STATIC(KoResourceServerProvider, s_instance) KoResourceServerProvider* KoResourceServerProvider::instance() { return s_instance; } QStringList KoResourceServerProvider::blacklistFileNames(QStringList fileNames, const QStringList &blacklistedFileNames) { if (!blacklistedFileNames.isEmpty()) { foreach (const QString &s, blacklistedFileNames) { fileNames.removeAll(s); } } return fileNames; } KoResourceServer* KoResourceServerProvider::patternServer() { return d->patternServer; } KoResourceServer* KoResourceServerProvider::gradientServer() { return d->gradientServer; } KoResourceServer* KoResourceServerProvider::paletteServer() { return d->paletteServer; } KoResourceServer *KoResourceServerProvider::svgSymbolCollectionServer() { return d->svgSymbolCollectionServer; } KoResourceServer* KoResourceServerProvider::gamutMaskServer() { return d->gamutMaskServer; } diff --git a/libs/widgetutils/KoResourcePaths.cpp b/libs/widgetutils/KoResourcePaths.cpp index cdc926ed61..103cbbf1e5 100644 --- a/libs/widgetutils/KoResourcePaths.cpp +++ b/libs/widgetutils/KoResourcePaths.cpp @@ -1,596 +1,596 @@ /* * Copyright (c) 2015 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "KoResourcePaths.h" #include #include #include #include #include #include #include #include #include #include #include "kis_debug.h" -Q_GLOBAL_STATIC(KoResourcePaths, s_instance); +Q_GLOBAL_STATIC(KoResourcePaths, s_instance) static QString cleanup(const QString &path) { return QDir::cleanPath(path); } static QStringList cleanup(const QStringList &pathList) { QStringList cleanedPathList; Q_FOREACH(const QString &path, pathList) { cleanedPathList << cleanup(path); } return cleanedPathList; } static QString cleanupDirs(const QString &path) { return QDir::cleanPath(path) + QDir::separator(); } static QStringList cleanupDirs(const QStringList &pathList) { QStringList cleanedPathList; Q_FOREACH(const QString &path, pathList) { cleanedPathList << cleanupDirs(path); } return cleanedPathList; } void appendResources(QStringList *dst, const QStringList &src, bool eliminateDuplicates) { Q_FOREACH (const QString &resource, src) { QString realPath = QDir::cleanPath(resource); if (!eliminateDuplicates || !dst->contains(realPath)) { *dst << realPath; } } } #ifdef Q_OS_WIN static const Qt::CaseSensitivity cs = Qt::CaseInsensitive; #else static const Qt::CaseSensitivity cs = Qt::CaseSensitive; #endif #ifdef Q_OS_OSX #include #include #include #endif QString getInstallationPrefix() { #ifdef Q_OS_OSX QString appPath = qApp->applicationDirPath(); dbgResources << "1" << appPath; appPath.chop(QString("MacOS/").length()); dbgResources << "2" << appPath; bool makeInstall = QDir(appPath + "/../../../share/kritaplugins").exists(); bool inBundle = QDir(appPath + "/Resources/kritaplugins").exists(); dbgResources << "3. After make install" << makeInstall; dbgResources << "4. In Bundle" << inBundle; QString bundlePath; if (inBundle) { bundlePath = appPath + "/"; } else if (makeInstall) { appPath.chop(QString("Contents/").length()); bundlePath = appPath + "/../../"; } else { qFatal("Cannot calculate the bundle path from the app path"); } dbgResources << ">>>>>>>>>>>" << bundlePath; return bundlePath; #else #ifdef Q_OS_QWIN QDir appdir(qApp->applicationDirPath()); // Corrects for mismatched case errors in path (qtdeclarative fails to load) wchar_t buffer[1024]; QString absolute = appdir.absolutePath(); DWORD rv = ::GetShortPathName((wchar_t*)absolute.utf16(), buffer, 1024); rv = ::GetLongPathName(buffer, buffer, 1024); QString correctedPath((QChar *)buffer); appdir.setPath(correctedPath); appdir.cdUp(); return appdir.canonicalPath(); #else return qApp->applicationDirPath() + "/../"; #endif #endif } class Q_DECL_HIDDEN KoResourcePaths::Private { public: QMap absolutes; // For each resource type, the list of absolute paths, from most local (most priority) to most global QMap relatives; // Same with relative paths QMutex relativesMutex; QMutex absolutesMutex; QStringList aliases(const QString &type) { QStringList r; QStringList a; relativesMutex.lock(); if (relatives.contains(type)) { r += relatives[type]; } relativesMutex.unlock(); dbgResources << "\trelatives" << r; absolutesMutex.lock(); if (absolutes.contains(type)) { a += absolutes[type]; } dbgResources << "\tabsolutes" << a; absolutesMutex.unlock(); return r + a; } QStandardPaths::StandardLocation mapTypeToQStandardPaths(const QString &type) { if (type == "tmp") { return QStandardPaths::TempLocation; } else if (type == "appdata") { return QStandardPaths::AppDataLocation; } else if (type == "data") { return QStandardPaths::AppDataLocation; } else if (type == "cache") { return QStandardPaths::CacheLocation; } else if (type == "locale") { return QStandardPaths::AppDataLocation; } else { return QStandardPaths::AppDataLocation; } } }; KoResourcePaths::KoResourcePaths() : d(new Private) { } KoResourcePaths::~KoResourcePaths() { } QString KoResourcePaths::getApplicationRoot() { return getInstallationPrefix(); } void KoResourcePaths::addResourceType(const char *type, const char *basetype, const QString &relativeName, bool priority) { s_instance->addResourceTypeInternal(QString::fromLatin1(type), QString::fromLatin1(basetype), relativeName, priority); } void KoResourcePaths::addResourceDir(const char *type, const QString &dir, bool priority) { s_instance->addResourceDirInternal(QString::fromLatin1(type), dir, priority); } QString KoResourcePaths::findResource(const char *type, const QString &fileName) { return cleanup(s_instance->findResourceInternal(QString::fromLatin1(type), fileName)); } QStringList KoResourcePaths::findDirs(const char *type) { return cleanupDirs(s_instance->findDirsInternal(QString::fromLatin1(type))); } QStringList KoResourcePaths::findAllResources(const char *type, const QString &filter, SearchOptions options) { return cleanup(s_instance->findAllResourcesInternal(QString::fromLatin1(type), filter, options)); } QStringList KoResourcePaths::resourceDirs(const char *type) { return cleanupDirs(s_instance->resourceDirsInternal(QString::fromLatin1(type))); } QString KoResourcePaths::saveLocation(const char *type, const QString &suffix, bool create) { return cleanupDirs(s_instance->saveLocationInternal(QString::fromLatin1(type), suffix, create)); } QString KoResourcePaths::locate(const char *type, const QString &filename) { return cleanup(s_instance->locateInternal(QString::fromLatin1(type), filename)); } QString KoResourcePaths::locateLocal(const char *type, const QString &filename, bool createDir) { return cleanup(s_instance->locateLocalInternal(QString::fromLatin1(type), filename, createDir)); } void KoResourcePaths::addResourceTypeInternal(const QString &type, const QString &basetype, const QString &relativename, bool priority) { Q_UNUSED(basetype); if (relativename.isEmpty()) return; QString copy = relativename; Q_ASSERT(basetype == "data"); if (!copy.endsWith(QLatin1Char('/'))) { copy += QLatin1Char('/'); } d->relativesMutex.lock(); QStringList &rels = d->relatives[type]; // find or insert if (!rels.contains(copy, cs)) { if (priority) { rels.prepend(copy); } else { rels.append(copy); } } d->relativesMutex.unlock(); dbgResources << "addResourceType: type" << type << "basetype" << basetype << "relativename" << relativename << "priority" << priority << d->relatives[type]; } void KoResourcePaths::addResourceDirInternal(const QString &type, const QString &absdir, bool priority) { if (absdir.isEmpty() || type.isEmpty()) return; // find or insert entry in the map QString copy = absdir; if (copy.at(copy.length() - 1) != QLatin1Char('/')) { copy += QLatin1Char('/'); } d->absolutesMutex.lock(); QStringList &paths = d->absolutes[type]; if (!paths.contains(copy, cs)) { if (priority) { paths.prepend(copy); } else { paths.append(copy); } } d->absolutesMutex.unlock(); dbgResources << "addResourceDir: type" << type << "absdir" << absdir << "priority" << priority << d->absolutes[type]; } QString KoResourcePaths::findResourceInternal(const QString &type, const QString &fileName) { QStringList aliases = d->aliases(type); dbgResources<< "aliases" << aliases << getApplicationRoot(); QString resource = QStandardPaths::locate(QStandardPaths::AppDataLocation, fileName, QStandardPaths::LocateFile); if (resource.isEmpty()) { Q_FOREACH (const QString &alias, aliases) { resource = QStandardPaths::locate(d->mapTypeToQStandardPaths(type), alias + '/' + fileName, QStandardPaths::LocateFile); dbgResources << "\t1" << resource; if (QFile::exists(resource)) { continue; } } } if (resource.isEmpty() || !QFile::exists(resource)) { QString approot = getApplicationRoot(); Q_FOREACH (const QString &alias, aliases) { resource = approot + "/share/" + alias + '/' + fileName; dbgResources << "\t2" << resource; if (QFile::exists(resource)) { continue; } } } if (resource.isEmpty() || !QFile::exists(resource)) { QString approot = getApplicationRoot(); Q_FOREACH (const QString &alias, aliases) { resource = approot + "/share/krita/" + alias + '/' + fileName; dbgResources << "\t3" << resource; if (QFile::exists(resource)) { continue; } } } if (resource.isEmpty() || !QFile::exists(resource)) { QString extraResourceDirs = qgetenv("EXTRA_RESOURCE_DIRS"); if (!extraResourceDirs.isEmpty()) { Q_FOREACH(const QString &extraResourceDir, extraResourceDirs.split(':', QString::SkipEmptyParts)) { if (aliases.isEmpty()) { resource = extraResourceDir + '/' + fileName; dbgResources<< "\t4" << resource; if (QFile::exists(resource)) { continue; } } else { Q_FOREACH (const QString &alias, aliases) { resource = extraResourceDir + '/' + alias + '/' + fileName; dbgResources<< "\t4" << resource; if (QFile::exists(resource)) { continue; } } } } } } dbgResources<< "findResource: type" << type << "filename" << fileName << "resource" << resource; Q_ASSERT(!resource.isEmpty()); return resource; } QStringList filesInDir(const QString &startdir, const QString & filter, bool recursive) { dbgResources << "filesInDir: startdir" << startdir << "filter" << filter << "recursive" << recursive; QStringList result; // First the entries in this path QStringList nameFilters; nameFilters << filter; const QStringList fileNames = QDir(startdir).entryList(nameFilters, QDir::Files | QDir::CaseSensitive, QDir::Name); dbgResources << "\tFound:" << fileNames.size() << ":" << fileNames; Q_FOREACH (const QString &fileName, fileNames) { QString file = startdir + '/' + fileName; result << file; } // And then everything underneath, if recursive is specified if (recursive) { const QStringList entries = QDir(startdir).entryList(QDir::Dirs | QDir::NoDotAndDotDot); Q_FOREACH (const QString &subdir, entries) { dbgResources << "\tGoing to look in subdir" << subdir << "of" << startdir; result << filesInDir(startdir + '/' + subdir, filter, recursive); } } return result; } QStringList KoResourcePaths::findDirsInternal(const QString &type) { QStringList aliases = d->aliases(type); dbgResources << type << aliases << d->mapTypeToQStandardPaths(type); QStringList dirs; QStringList standardDirs = QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), "", QStandardPaths::LocateDirectory); appendResources(&dirs, standardDirs, true); Q_FOREACH (const QString &alias, aliases) { QStringList aliasDirs = QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias + '/', QStandardPaths::LocateDirectory); appendResources(&dirs, aliasDirs, true); #ifdef Q_OS_OSX dbgResources << "MAC:" << getApplicationRoot(); QStringList bundlePaths; bundlePaths << getApplicationRoot() + "/share/krita/" + alias; bundlePaths << getApplicationRoot() + "/../share/krita/" + alias; dbgResources << "bundlePaths" << bundlePaths; appendResources(&dirs, bundlePaths, true); Q_ASSERT(!dirs.isEmpty()); #endif QStringList fallbackPaths; fallbackPaths << getApplicationRoot() + "/share/" + alias; fallbackPaths << getApplicationRoot() + "/share/krita/" + alias; appendResources(&dirs, fallbackPaths, true); } dbgResources << "findDirs: type" << type << "resource" << dirs; return dirs; } QStringList KoResourcePaths::findAllResourcesInternal(const QString &type, const QString &_filter, SearchOptions options) const { dbgResources << "====================================================="; dbgResources << type << _filter << QStandardPaths::standardLocations(d->mapTypeToQStandardPaths(type)); bool recursive = options & KoResourcePaths::Recursive; dbgResources << "findAllResources: type" << type << "filter" << _filter << "recursive" << recursive; QStringList aliases = d->aliases(type); QString filter = _filter; // In cases where the filter is like "color-schemes/*.colors" instead of "*.kpp", used with unregistered resource types if (filter.indexOf('*') > 0) { aliases << filter.split('*').first(); filter = '*' + filter.split('*')[1]; dbgResources << "Split up alias" << aliases << "filter" << filter; } QStringList resources; if (aliases.isEmpty()) { QStringList standardResources = QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), filter, QStandardPaths::LocateFile); dbgResources << "standardResources" << standardResources; appendResources(&resources, standardResources, true); dbgResources << "1" << resources; } QString extraResourceDirs = qgetenv("EXTRA_RESOURCE_DIRS"); dbgResources << "extraResourceDirs" << extraResourceDirs; if (!extraResourceDirs.isEmpty()) { Q_FOREACH(const QString &extraResourceDir, extraResourceDirs.split(':', QString::SkipEmptyParts)) { if (aliases.isEmpty()) { appendResources(&resources, filesInDir(extraResourceDir + '/' + type, filter, recursive), true); } else { Q_FOREACH (const QString &alias, aliases) { appendResources(&resources, filesInDir(extraResourceDir + '/' + alias + '/', filter, recursive), true); } } } } dbgResources << "\tresources from qstandardpaths:" << resources.size(); Q_FOREACH (const QString &alias, aliases) { dbgResources << "\t\talias:" << alias; QStringList dirs; QFileInfo dirInfo(alias); if (dirInfo.exists() && dirInfo.isDir() && dirInfo.isAbsolute()) { dirs << alias; } else { dirs << QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory) << getInstallationPrefix() + "share/" + alias + "/" << getInstallationPrefix() + "share/krita/" + alias + "/"; } Q_FOREACH (const QString &dir, dirs) { appendResources(&resources, filesInDir(dir, filter, recursive), true); } } dbgResources << "\tresources also from aliases:" << resources.size(); // if the original filter is "input/*", we only want share/input/* and share/krita/input/* here, but not // share/*. therefore, use _filter here instead of filter which was split into alias and "*". QFileInfo fi(_filter); QStringList prefixResources; prefixResources << filesInDir(getInstallationPrefix() + "share/" + fi.path(), fi.fileName(), false); prefixResources << filesInDir(getInstallationPrefix() + "share/krita/" + fi.path(), fi.fileName(), false); appendResources(&resources, prefixResources, true); dbgResources << "\tresources from installation:" << resources.size(); dbgResources << "====================================================="; return resources; } QStringList KoResourcePaths::resourceDirsInternal(const QString &type) { QStringList resourceDirs; QStringList aliases = d->aliases(type); Q_FOREACH (const QString &alias, aliases) { QStringList aliasDirs; aliasDirs << QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory); aliasDirs << getInstallationPrefix() + "share/" + alias + "/" << QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory); aliasDirs << getInstallationPrefix() + "share/krita/" + alias + "/" << QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory); appendResources(&resourceDirs, aliasDirs, true); } dbgResources << "resourceDirs: type" << type << resourceDirs; return resourceDirs; } QString KoResourcePaths::saveLocationInternal(const QString &type, const QString &suffix, bool create) { QStringList aliases = d->aliases(type); QString path; if (aliases.size() > 0) { path = QStandardPaths::writableLocation(d->mapTypeToQStandardPaths(type)) + '/' + aliases.first(); } else { path = QStandardPaths::writableLocation(d->mapTypeToQStandardPaths(type)); if (!path.endsWith("krita")) { path += "/krita"; } if (!suffix.isEmpty()) { path += "/" + suffix; } } QDir d(path); if (!d.exists() && create) { d.mkpath(path); } dbgResources << "saveLocation: type" << type << "suffix" << suffix << "create" << create << "path" << path; return path; } QString KoResourcePaths::locateInternal(const QString &type, const QString &filename) { QStringList aliases = d->aliases(type); QStringList locations; if (aliases.isEmpty()) { locations << QStandardPaths::locate(d->mapTypeToQStandardPaths(type), filename, QStandardPaths::LocateFile); } Q_FOREACH (const QString &alias, aliases) { locations << QStandardPaths::locate(d->mapTypeToQStandardPaths(type), (alias.endsWith('/') ? alias : alias + '/') + filename, QStandardPaths::LocateFile); } dbgResources << "locate: type" << type << "filename" << filename << "locations" << locations; if (locations.size() > 0) { return locations.first(); } else { return ""; } } QString KoResourcePaths::locateLocalInternal(const QString &type, const QString &filename, bool createDir) { QString path = saveLocationInternal(type, "", createDir); dbgResources << "locateLocal: type" << type << "filename" << filename << "CreateDir" << createDir << "path" << path; return path + '/' + filename; } diff --git a/libs/widgetutils/xmlgui/KisShortcutsDialog_p.cpp b/libs/widgetutils/xmlgui/KisShortcutsDialog_p.cpp index 27ab3cf590..a36644c5b4 100644 --- a/libs/widgetutils/xmlgui/KisShortcutsDialog_p.cpp +++ b/libs/widgetutils/xmlgui/KisShortcutsDialog_p.cpp @@ -1,93 +1,93 @@ /* * Copyright (c) 2015 Michael Abrahams * * 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 3 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KisShortcutsDialog_p.h" #include "kshortcutschemeshelper_p.h" #include "kxmlguiclient.h" #include #include "kactioncollection.h" #include "kxmlguifactory.h" #include #include #include #include "kis_action_registry.h" #include #include QKeySequence primarySequence(const QList &sequences) { return sequences.isEmpty() ? QKeySequence() : sequences.at(0); } QKeySequence alternateSequence(const QList &sequences) { return sequences.size() <= 1 ? QKeySequence() : sequences.at(1); } KisShortcutsDialog::KisShortcutsDialogPrivate::KisShortcutsDialogPrivate(KisShortcutsDialog *q) : q(q) { } void KisShortcutsDialog::KisShortcutsDialogPrivate::changeShortcutScheme(const QString &schemeName) { // KTreeWidgetSearchLine is unhappy if the contents of the tree change m_shortcutsEditor->clearSearch(); QString dialogText = i18n("The current shortcut scheme is modified. Save before switching to the new one?"); if (m_shortcutsEditor->isModified() && KMessageBox::questionYesNo( q,dialogText ) == KMessageBox::Yes) { m_shortcutsEditor->save(); } else { m_shortcutsEditor->undo(); } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); m_shortcutsEditor->clearCollections(); KConfigGroup cg = KSharedConfig::openConfig()->group("Shortcut Schemes"); cg.writeEntry("Current Scheme", schemeName); KisActionRegistry::instance()->loadShortcutScheme(schemeName); // Update actions themselves, and re-add to dialog box to refresh auto it = m_collections.constBegin(); while (it != m_collections.constEnd()) { it.value()->updateShortcuts(); // TODO: BAD m_shortcutsEditor->addCollection(it.value(), it.key()); it++; } QApplication::restoreOverrideCursor(); } void KisShortcutsDialog::KisShortcutsDialogPrivate::undo() { m_shortcutsEditor->undo(); } void KisShortcutsDialog::KisShortcutsDialogPrivate::save() { m_shortcutsEditor->save(); -}; +} #include "moc_KisShortcutsDialog_p.cpp" diff --git a/libs/widgetutils/xmlgui/kactioncollection.cpp b/libs/widgetutils/xmlgui/kactioncollection.cpp index 92972965e2..27e10bd13a 100644 --- a/libs/widgetutils/xmlgui/kactioncollection.cpp +++ b/libs/widgetutils/xmlgui/kactioncollection.cpp @@ -1,758 +1,758 @@ /* This file is part of the KDE libraries Copyright (C) 1999 Reginald Stadlbauer (C) 1999 Simon Hausmann (C) 2000 Nicolas Hadacek (C) 2000 Kurt Granroth (C) 2000 Michael Koch (C) 2001 Holger Freyther (C) 2002 Ellis Whitehead (C) 2002 Joseph Wenninger (C) 2005-2007 Hamish Rodda This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kactioncollection.h" #include "config-xmlgui.h" #include "kactioncategory.h" #include "kxmlguiclient.h" #include "kxmlguifactory.h" #include "kis_action_registry.h" #include #include #include #include #include #include #include #include #include #include #include #include #if defined(KCONFIG_BEFORE_5_24) # define authorizeAction authorizeKAction #endif class KActionCollectionPrivate { public: KActionCollectionPrivate() : m_parentGUIClient(0L), configGroup(QStringLiteral("Shortcuts")), connectTriggered(false), connectHovered(false), q(0) { } void setComponentForAction(QAction *action) { Q_UNUSED(action) } static QList s_allCollections; void _k_associatedWidgetDestroyed(QObject *obj); void _k_actionDestroyed(QObject *obj); bool writeKXMLGUIConfigFile(); QString m_componentName; QString m_componentDisplayName; //! Remove a action from our internal bookkeeping. Returns 0 if the //! action doesn't belong to us. QAction *unlistAction(QAction *); QMap actionByName; QList actions; const KXMLGUIClient *m_parentGUIClient; QString configGroup; bool configIsGlobal : 1; bool connectTriggered : 1; bool connectHovered : 1; KActionCollection *q; QList associatedWidgets; }; QList KActionCollectionPrivate::s_allCollections; KActionCollection::KActionCollection(QObject *parent, const QString &cName) : QObject(parent) , d(new KActionCollectionPrivate) { d->q = this; KActionCollectionPrivate::s_allCollections.append(this); setComponentName(cName); } KActionCollection::KActionCollection(const KXMLGUIClient *parent) : QObject(0) , d(new KActionCollectionPrivate) { d->q = this; KActionCollectionPrivate::s_allCollections.append(this); d->m_parentGUIClient = parent; d->m_componentName = parent->componentName(); } KActionCollection::~KActionCollection() { KActionCollectionPrivate::s_allCollections.removeAll(this); delete d; } QList KActionCollection::categories() const { return this->findChildren(); } KActionCategory *KActionCollection::getCategory(const QString &name) { KActionCategory *category = 0; foreach (KActionCategory *c, categories()) { if (c->text() == name) { category = c; } } if (category == 0) { category = new KActionCategory(name, this); } return category; -}; +} void KActionCollection::clear() { d->actionByName.clear(); qDeleteAll(d->actions); d->actions.clear(); } QAction *KActionCollection::action(const QString &name) const { QAction *action = 0L; if (!name.isEmpty()) { action = d->actionByName.value(name); } return action; } QAction *KActionCollection::action(int index) const { // ### investigate if any apps use this at all return actions().value(index); } int KActionCollection::count() const { return d->actions.count(); } bool KActionCollection::isEmpty() const { return count() == 0; } void KActionCollection::setComponentName(const QString &cName) { if (count() > 0) { // Its component name is part of an action's signature in the context of // global shortcuts and the semantics of changing an existing action's // signature are, as it seems, impossible to get right. // As of now this only matters for global shortcuts. We could // thus relax the requirement and only refuse to change the component data // if we have actions with global shortcuts in this collection. qWarning() << "this does not work on a KActionCollection containing actions!"; } if (!cName.isEmpty()) { d->m_componentName = cName; } else { d->m_componentName = QCoreApplication::applicationName(); } } QString KActionCollection::componentName() const { return d->m_componentName; } void KActionCollection::setComponentDisplayName(const QString &displayName) { d->m_componentDisplayName = displayName; } QString KActionCollection::componentDisplayName() const { if (!d->m_componentDisplayName.isEmpty()) { return d->m_componentDisplayName; } if (!QGuiApplication::applicationDisplayName().isEmpty()) { return QGuiApplication::applicationDisplayName(); } return QCoreApplication::applicationName(); } const KXMLGUIClient *KActionCollection::parentGUIClient() const { return d->m_parentGUIClient; } QList KActionCollection::actions() const { return d->actions; } const QList< QAction * > KActionCollection::actionsWithoutGroup() const { QList ret; Q_FOREACH (QAction *action, d->actions) if (!action->actionGroup()) { ret.append(action); } return ret; } const QList< QActionGroup * > KActionCollection::actionGroups() const { QSet set; Q_FOREACH (QAction *action, d->actions) if (action->actionGroup()) { set.insert(action->actionGroup()); } return set.toList(); } QAction *KActionCollection::addCategorizedAction(const QString &name, QAction *action, const QString &categoryName) { return getCategory(categoryName)->addAction(name, action); } QAction *KActionCollection::addAction(const QString &name, QAction *action) { if (!action) { return action; } const QString objectName = action->objectName(); QString indexName = name; if (indexName.isEmpty()) { // No name provided. Use the objectName. indexName = objectName; } else { // Set the new name action->setObjectName(indexName); } // No name provided and the action had no name. Make one up. This will not // work when trying to save shortcuts. if (indexName.isEmpty()) { indexName = indexName.sprintf("unnamed-%p", (void *)action); action->setObjectName(indexName); } // From now on the objectName has to have a value. Else we cannot safely // remove actions. Q_ASSERT(!action->objectName().isEmpty()); // look if we already have THIS action under THIS name ;) if (d->actionByName.value(indexName, 0) == action) { // This is not a multi map! Q_ASSERT(d->actionByName.count(indexName) == 1); return action; } if (!KAuthorized::authorizeAction(indexName)) { // Disable this action action->setEnabled(false); action->setVisible(false); action->blockSignals(true); } // Check if we have another action under this name if (QAction *oldAction = d->actionByName.value(indexName)) { takeAction(oldAction); } // Check if we have this action under a different name. // Not using takeAction because we don't want to remove it from categories, // and because it has the new name already. const int oldIndex = d->actions.indexOf(action); if (oldIndex != -1) { d->actionByName.remove(d->actionByName.key(action)); d->actions.removeAt(oldIndex); } // Add action to our lists. d->actionByName.insert(indexName, action); d->actions.append(action); Q_FOREACH (QWidget *widget, d->associatedWidgets) { widget->addAction(action); } connect(action, SIGNAL(destroyed(QObject*)), SLOT(_k_actionDestroyed(QObject*))); d->setComponentForAction(action); if (d->connectHovered) { connect(action, SIGNAL(hovered()), SLOT(slotActionHovered())); } if (d->connectTriggered) { connect(action, SIGNAL(triggered(bool)), SLOT(slotActionTriggered())); } emit inserted(action); return action; } void KActionCollection::addActions(const QList &actions) { Q_FOREACH (QAction *action, actions) { addAction(action->objectName(), action); } } void KActionCollection::removeAction(QAction *action) { delete takeAction(action); } QAction *KActionCollection::takeAction(QAction *action) { if (!d->unlistAction(action)) { return 0; } // Remove the action from all widgets Q_FOREACH (QWidget *widget, d->associatedWidgets) { widget->removeAction(action); } action->disconnect(this); emit removed(action); //deprecated return action; } QAction *KActionCollection::addAction(KStandardAction::StandardAction actionType, const QObject *receiver, const char *member) { QAction *action = KStandardAction::create(actionType, receiver, member, this); return action; } QAction *KActionCollection::addAction(KStandardAction::StandardAction actionType, const QString &name, const QObject *receiver, const char *member) { // pass 0 as parent, because if the parent is a KActionCollection KStandardAction::create automatically // adds the action to it under the default name. We would trigger the // warning about renaming the action then. QAction *action = KStandardAction::create(actionType, receiver, member, 0); // Give it a parent for gc. action->setParent(this); // Remove the name to get rid of the "rename action" warning above action->setObjectName(name); // And now add it with the desired name. return addAction(name, action); } QAction *KActionCollection::addAction(const QString &name, const QObject *receiver, const char *member) { QAction *a = new QAction(this); if (receiver && member) { connect(a, SIGNAL(triggered(bool)), receiver, member); } return addAction(name, a); } QKeySequence KActionCollection::defaultShortcut(QAction *action) const { const QList shortcuts = defaultShortcuts(action); return shortcuts.isEmpty() ? QKeySequence() : shortcuts.first(); } QList KActionCollection::defaultShortcuts(QAction *action) const { return action->property("defaultShortcuts").value >(); } void KActionCollection::setDefaultShortcut(QAction *action, const QKeySequence &shortcut) { setDefaultShortcuts(action, QList() << shortcut); } void KActionCollection::setDefaultShortcuts(QAction *action, const QList &shortcuts) { action->setShortcuts(shortcuts); action->setProperty("defaultShortcuts", QVariant::fromValue(shortcuts)); } bool KActionCollection::isShortcutsConfigurable(QAction *action) const { // Considered as true by default const QVariant value = action->property("isShortcutConfigurable"); return value.isValid() ? value.toBool() : true; } void KActionCollection::setShortcutsConfigurable(QAction *action, bool configurable) { action->setProperty("isShortcutConfigurable", configurable); } QString KActionCollection::configGroup() const { return d->configGroup; } void KActionCollection::setConfigGroup(const QString &group) { d->configGroup = group; } void KActionCollection::updateShortcuts() { auto actionRegistry = KisActionRegistry::instance(); for (QMap::ConstIterator it = d->actionByName.constBegin(); it != d->actionByName.constEnd(); ++it) { actionRegistry->updateShortcut(it.key(), it.value()); } } void KActionCollection::readSettings() { auto ar = KisActionRegistry::instance(); ar->loadCustomShortcuts(); for (QMap::ConstIterator it = d->actionByName.constBegin(); it != d->actionByName.constEnd(); ++it) { QAction *action = it.value(); if (!action) { continue; } if (isShortcutsConfigurable(action)) { QString actionName = it.key(); ar->updateShortcut(actionName, action); } } } bool KActionCollectionPrivate::writeKXMLGUIConfigFile() { const KXMLGUIClient *kxmlguiClient = q->parentGUIClient(); // return false if there is no KXMLGUIClient if (!kxmlguiClient || kxmlguiClient->xmlFile().isEmpty()) { return false; } QString attrShortcut = QStringLiteral("shortcut"); // Read XML file QString sXml(KXMLGUIFactory::readConfigFile(kxmlguiClient->xmlFile(), q->componentName())); QDomDocument doc; doc.setContent(sXml); // Process XML data // Get hold of ActionProperties tag QDomElement elem = KXMLGUIFactory::actionPropertiesElement(doc); // now, iterate through our actions for (QMap::ConstIterator it = actionByName.constBegin(); it != actionByName.constEnd(); ++it) { QAction *action = it.value(); if (!action) { continue; } QString actionName = it.key(); // If the action name starts with unnamed- spit out a warning and ignore // it. That name will change at will and will break loading writing if (actionName.startsWith(QLatin1String("unnamed-"))) { qCritical() << "Skipped writing shortcut for action " << actionName << "(" << action->text() << ")!"; continue; } bool bSameAsDefault = (action->shortcuts() == q->defaultShortcuts(action)); // now see if this element already exists // and create it if necessary (unless bSameAsDefault) QDomElement act_elem = KXMLGUIFactory::findActionByName(elem, actionName, !bSameAsDefault); if (act_elem.isNull()) { continue; } if (bSameAsDefault) { act_elem.removeAttribute(attrShortcut); if (act_elem.attributes().count() == 1) { elem.removeChild(act_elem); } } else { act_elem.setAttribute(attrShortcut, QKeySequence::listToString(action->shortcuts())); } } // Write back to XML file KXMLGUIFactory::saveConfigFile(doc, kxmlguiClient->localXMLFile(), q->componentName()); return true; } void KActionCollection::writeSettings(KConfigGroup *config, bool writeScheme, QAction *oneAction) const { // If the caller didn't provide a config group we try to save the KXMLGUI // Configuration file. (This will work if the parentGUI was set and has a // valid configuration file.) if (config == 0 && d->writeKXMLGUIConfigFile()) { return; } KConfigGroup cg(KSharedConfig::openConfig(), configGroup()); if (!config) { config = &cg; } QList writeActions; if (oneAction) { writeActions.append(oneAction); } else { writeActions = actions(); } for (QMap::ConstIterator it = d->actionByName.constBegin(); it != d->actionByName.constEnd(); ++it) { QAction *action = it.value(); if (!action) { continue; } QString actionName = it.key(); // If the action name starts with unnamed- spit out a warning and ignore // it. That name will change at will and will break loading writing if (actionName.startsWith(QLatin1String("unnamed-"))) { qCritical() << "Skipped saving shortcut for action without name " \ << action->text() << "!"; continue; } // Write the shortcut if (isShortcutsConfigurable(action)) { bool bConfigHasAction = !config->readEntry(actionName, QString()).isEmpty(); bool bSameAsDefault = (action->shortcuts() == defaultShortcuts(action)); // If the current shortcut differs from the default, we want to write. KConfigGroup::WriteConfigFlags flags = KConfigGroup::Persistent; if (writeScheme || !bSameAsDefault) { // We are instructed to write all shortcuts or the shortcut is // not set to its default value. Write it QString s = QKeySequence::listToString(action->shortcuts()); if (s.isEmpty()) { s = QStringLiteral("none"); } config->writeEntry(actionName, s, flags); } else if (bConfigHasAction) { // This key is the same as default but exists in config file. // Remove it. config->deleteEntry(actionName, flags); } } } config->sync(); } void KActionCollection::slotActionTriggered() { QAction *action = qobject_cast(sender()); if (action) { emit actionTriggered(action); } } void KActionCollection::slotActionHighlighted() { slotActionHovered(); } void KActionCollection::slotActionHovered() { QAction *action = qobject_cast(sender()); if (action) { emit actionHighlighted(action); emit actionHovered(action); } } void KActionCollectionPrivate::_k_actionDestroyed(QObject *obj) { // obj isn't really a QAction anymore. So make sure we don't do fancy stuff // with it. QAction *action = static_cast(obj); if (!unlistAction(action)) { return; } //HACK the object we emit is partly destroyed emit q->removed(action); //deprecated. remove in KDE5 } void KActionCollection::connectNotify(const QMetaMethod &signal) { if (d->connectHovered && d->connectTriggered) { return; } if (signal.methodSignature() == "actionHighlighted(QAction*)" || signal.methodSignature() == "actionHovered(QAction*)") { if (!d->connectHovered) { d->connectHovered = true; Q_FOREACH (QAction *action, actions()) { connect(action, SIGNAL(hovered()), SLOT(slotActionHovered())); } } } else if (signal.methodSignature() == "actionTriggered(QAction*)") { if (!d->connectTriggered) { d->connectTriggered = true; Q_FOREACH (QAction *action, actions()) { connect(action, SIGNAL(triggered(bool)), SLOT(slotActionTriggered())); } } } QObject::connectNotify(signal); } const QList< KActionCollection * > &KActionCollection::allCollections() { return KActionCollectionPrivate::s_allCollections; } void KActionCollection::associateWidget(QWidget *widget) const { Q_FOREACH (QAction *action, actions()) { if (!widget->actions().contains(action)) { widget->addAction(action); } } } void KActionCollection::addAssociatedWidget(QWidget *widget) { if (!d->associatedWidgets.contains(widget)) { widget->addActions(actions()); d->associatedWidgets.append(widget); connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(_k_associatedWidgetDestroyed(QObject*))); } } void KActionCollection::removeAssociatedWidget(QWidget *widget) { Q_FOREACH (QAction *action, actions()) { widget->removeAction(action); } d->associatedWidgets.removeAll(widget); disconnect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(_k_associatedWidgetDestroyed(QObject*))); } QAction *KActionCollectionPrivate::unlistAction(QAction *action) { // ATTENTION: // This method is called with an QObject formerly known as a QAction // during _k_actionDestroyed(). So don't do fancy stuff here that needs a // real QAction! // Get the index for the action int index = actions.indexOf(action); // Action not found. if (index == -1) { return 0; } // An action collection can't have the same action twice. Q_ASSERT(actions.indexOf(action, index + 1) == -1); // Get the actions name const QString name = action->objectName(); // Remove the action actionByName.remove(name); actions.removeAt(index); // Remove the action from the categories. Should be only one QList categories = q->findChildren(); Q_FOREACH (KActionCategory *category, categories) { category->unlistAction(action); } return action; } QList< QWidget * > KActionCollection::associatedWidgets() const { return d->associatedWidgets; } void KActionCollection::clearAssociatedWidgets() { Q_FOREACH (QWidget *widget, d->associatedWidgets) Q_FOREACH (QAction *action, actions()) { widget->removeAction(action); } d->associatedWidgets.clear(); } void KActionCollectionPrivate::_k_associatedWidgetDestroyed(QObject *obj) { associatedWidgets.removeAll(static_cast(obj)); } #include "moc_kactioncollection.cpp" diff --git a/plugins/tools/selectiontools/kis_selection_modifier_mapper.cc b/plugins/tools/selectiontools/kis_selection_modifier_mapper.cc index 8896faffc5..aafcbb4ce2 100644 --- a/plugins/tools/selectiontools/kis_selection_modifier_mapper.cc +++ b/plugins/tools/selectiontools/kis_selection_modifier_mapper.cc @@ -1,130 +1,130 @@ /* This file is part of the KDE project * Copyright (C) 2016 Michael Abrahams * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ /** * This is a basic template to create selection tools from basic path based drawing tools. * The template overrides the ability to execute alternate actions correctly. * Modifier keys are overridden with the following behavior: * * Shift: add to selection * Alt: subtract from selection * Shift+Alt: intersect current selection * Ctrl: replace selection * * Certain tools also use modifier keys to alter their behavior, e.g. forcing square proportions with the rectangle tool. * The template enables the following rules for forwarding keys: * 1) Any modifier keys held *when the tool is first activated* will determine the new selection method. * 2) If the underlying tool *does not take modifier keys*, pressing modifier keys in the middle of a stroke will change the selection method. This applies to the lasso tool and polygon tool. * 3) If the underlying tool *takes modifier keys,* they will always be forwarded to the underlying tool, and it is not possible to change the selection method in the middle of a stroke. */ #include "kis_selection.h" #include "kis_selection_modifier_mapper.h" #include "kis_config_notifier.h" #include "kis_config.h" -Q_GLOBAL_STATIC(KisSelectionModifierMapper, s_instance); +Q_GLOBAL_STATIC(KisSelectionModifierMapper, s_instance) // This numerically serializes modifier flags... let's keep it around for later. #if 0 #include QString QMOD_BINARY(Qt::KeyboardModifiers m) { return QString(std::bitset(m).to_string().c_str()); }; #endif struct Q_DECL_HIDDEN KisSelectionModifierMapper::Private { SelectionAction map(Qt::KeyboardModifiers m); void slotConfigChanged(); Qt::KeyboardModifiers replaceModifiers; Qt::KeyboardModifiers intersectModifiers; Qt::KeyboardModifiers addModifiers; Qt::KeyboardModifiers subtractModifiers; Qt::KeyboardModifiers symmetricdifferenceModifiers; }; KisSelectionModifierMapper::KisSelectionModifierMapper() : m_d(new Private) { connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotConfigChanged())); slotConfigChanged(); } KisSelectionModifierMapper::~KisSelectionModifierMapper() { } KisSelectionModifierMapper *KisSelectionModifierMapper::instance() { return s_instance; } void KisSelectionModifierMapper::slotConfigChanged() { m_d->slotConfigChanged(); } void KisSelectionModifierMapper::Private::slotConfigChanged() { KisConfig cfg(true); if (!cfg.switchSelectionCtrlAlt()) { replaceModifiers = Qt::ControlModifier; intersectModifiers = (Qt::KeyboardModifiers)(Qt::AltModifier | Qt::ShiftModifier); subtractModifiers = Qt::AltModifier; symmetricdifferenceModifiers = (Qt::KeyboardModifiers)(Qt::ControlModifier | Qt::AltModifier); } else { replaceModifiers = Qt::AltModifier; intersectModifiers = (Qt::KeyboardModifiers)(Qt::ControlModifier | Qt::ShiftModifier); subtractModifiers = Qt::ControlModifier; symmetricdifferenceModifiers = (Qt::KeyboardModifiers)(Qt::ShiftModifier | Qt::ControlModifier); } addModifiers = Qt::ShiftModifier; } SelectionAction KisSelectionModifierMapper::map(Qt::KeyboardModifiers m) { return s_instance->m_d->map(m); } SelectionAction KisSelectionModifierMapper::Private::map(Qt::KeyboardModifiers m) { SelectionAction newAction = SELECTION_DEFAULT; if (m == replaceModifiers) { newAction = SELECTION_REPLACE; } else if (m == intersectModifiers) { newAction = SELECTION_INTERSECT; } else if (m == addModifiers) { newAction = SELECTION_ADD; } else if (m == subtractModifiers) { newAction = SELECTION_SUBTRACT; } else if (m == symmetricdifferenceModifiers) { newAction = SELECTION_SYMMETRICDIFFERENCE; } return newAction; }