diff --git a/libs/flake/CMakeLists.txt b/libs/flake/CMakeLists.txt index c63e0821b8..aef106e243 100644 --- a/libs/flake/CMakeLists.txt +++ b/libs/flake/CMakeLists.txt @@ -1,225 +1,226 @@ project(kritaflake) include_directories( ${CMAKE_SOURCE_DIR}/libs/flake/commands ${CMAKE_SOURCE_DIR}/libs/flake/tools ${CMAKE_SOURCE_DIR}/libs/flake/svg ${CMAKE_BINARY_DIR}/libs/flake ) add_subdirectory(styles) add_subdirectory(tests) set(kritaflake_SRCS KoGradientHelper.cpp KoFlake.cpp KoCanvasBase.cpp KoResourceManager_p.cpp KoDerivedResourceConverter.cpp + KoResourceUpdateMediator.cpp KoCanvasResourceManager.cpp KoDocumentResourceManager.cpp KoCanvasObserverBase.cpp KoCanvasSupervisor.cpp KoDockFactoryBase.cpp KoDockRegistry.cpp KoDataCenterBase.cpp KoInsets.cpp KoPathShape.cpp KoPathPoint.cpp KoPathSegment.cpp KoSelection.cpp KoShape.cpp KoShapeAnchor.cpp KoShapeBasedDocumentBase.cpp KoShapeApplicationData.cpp KoShapeContainer.cpp KoShapeContainerModel.cpp KoShapeContainerDefaultModel.cpp KoShapeGroup.cpp KoShapeManagerPaintingStrategy.cpp KoShapeManager.cpp KoShapePaintingContext.cpp KoFrameShape.cpp KoUnavailShape.cpp KoMarkerData.cpp KoMarker.cpp KoMarkerCollection.cpp KoMarkerSharedLoadingData.cpp KoToolBase.cpp KoCanvasController.cpp KoCanvasControllerWidget.cpp KoCanvasControllerWidgetViewport_p.cpp KoShapeRegistry.cpp KoDeferredShapeFactoryBase.cpp KoToolFactoryBase.cpp KoPathShapeFactory.cpp KoShapeFactoryBase.cpp KoShapeUserData.cpp KoParameterShape.cpp KoPointerEvent.cpp KoShapeController.cpp KoToolSelection.cpp KoShapeLayer.cpp KoPostscriptPaintDevice.cpp KoInputDevice.cpp KoToolManager_p.cpp KoToolManager.cpp KoToolRegistry.cpp KoToolProxy.cpp KoShapeSavingContext.cpp KoShapeLoadingContext.cpp KoLoadingShapeUpdater.cpp KoPathShapeLoader.cpp KoShapeStrokeModel.cpp KoShapeStroke.cpp KoShapeBackground.cpp KoColorBackground.cpp KoGradientBackground.cpp KoOdfGradientBackground.cpp KoHatchBackground.cpp KoPatternBackground.cpp KoShapeConfigWidgetBase.cpp KoDrag.cpp KoDragOdfSaveHelper.cpp KoShapeOdfSaveHelper.cpp KoShapePaste.cpp KoConnectionPoint.cpp KoConnectionShape.cpp KoConnectionShapeLoadingUpdater.cpp KoConnectionShapeFactory.cpp KoConnectionShapeConfigWidget.cpp KoSnapGuide.cpp KoSnapProxy.cpp KoSnapStrategy.cpp KoSnapData.cpp KoShapeShadow.cpp KoSharedLoadingData.cpp KoSharedSavingData.cpp KoViewConverter.cpp KoInputDeviceHandler.cpp KoInputDeviceHandlerEvent.cpp KoInputDeviceHandlerRegistry.cpp KoImageData.cpp KoImageData_p.cpp KoImageCollection.cpp KoOdfWorkaround.cpp KoFilterEffect.cpp KoFilterEffectStack.cpp KoFilterEffectFactoryBase.cpp KoFilterEffectRegistry.cpp KoFilterEffectConfigWidgetBase.cpp KoFilterEffectRenderContext.cpp KoFilterEffectLoadingContext.cpp KoTextShapeDataBase.cpp KoTosContainer.cpp KoTosContainerModel.cpp KoClipPath.cpp KoCurveFit.cpp commands/KoShapeGroupCommand.cpp commands/KoShapeAlignCommand.cpp commands/KoShapeBackgroundCommand.cpp commands/KoShapeCreateCommand.cpp commands/KoShapeDeleteCommand.cpp commands/KoShapeDistributeCommand.cpp commands/KoShapeLockCommand.cpp commands/KoShapeMoveCommand.cpp commands/KoShapeShearCommand.cpp commands/KoShapeSizeCommand.cpp commands/KoShapeStrokeCommand.cpp commands/KoShapeUngroupCommand.cpp commands/KoShapeReorderCommand.cpp commands/KoShapeKeepAspectRatioCommand.cpp commands/KoPathBaseCommand.cpp commands/KoPathPointMoveCommand.cpp commands/KoPathControlPointMoveCommand.cpp commands/KoPathPointTypeCommand.cpp commands/KoPathPointRemoveCommand.cpp commands/KoPathPointInsertCommand.cpp commands/KoPathSegmentBreakCommand.cpp commands/KoPathBreakAtPointCommand.cpp commands/KoPathSegmentTypeCommand.cpp commands/KoPathCombineCommand.cpp commands/KoSubpathRemoveCommand.cpp commands/KoSubpathJoinCommand.cpp commands/KoParameterHandleMoveCommand.cpp commands/KoParameterToPathCommand.cpp commands/KoShapeTransformCommand.cpp commands/KoPathFillRuleCommand.cpp commands/KoConnectionShapeTypeCommand.cpp commands/KoShapeShadowCommand.cpp commands/KoPathReverseCommand.cpp commands/KoShapeRenameCommand.cpp commands/KoShapeRunAroundCommand.cpp commands/KoPathPointMergeCommand.cpp commands/KoShapeTransparencyCommand.cpp commands/KoShapeClipCommand.cpp commands/KoShapeUnclipCommand.cpp commands/KoPathShapeMarkerCommand.cpp commands/KoShapeConnectionChangeCommand.cpp tools/KoCreateShapeStrategy.cpp tools/KoPathToolFactory.cpp tools/KoPathTool.cpp tools/KoPathToolSelection.cpp tools/KoPathToolHandle.cpp tools/PathToolOptionWidget.cpp tools/KoPathPointRubberSelectStrategy.cpp tools/KoPathPointMoveStrategy.cpp tools/KoPathConnectionPointStrategy.cpp tools/KoPathControlPointMoveStrategy.cpp tools/KoParameterChangeStrategy.cpp tools/KoZoomTool.cpp tools/KoZoomToolFactory.cpp tools/KoZoomToolWidget.cpp tools/KoZoomStrategy.cpp tools/KoPanTool.cpp tools/KoPanToolFactory.cpp tools/KoInteractionTool.cpp tools/KoInteractionStrategy.cpp tools/KoCreateShapesTool.cpp tools/KoCreateShapesToolFactory.cpp tools/KoShapeRubberSelectStrategy.cpp tools/KoPathSegmentChangeStrategy.cpp svg/KoShapePainter.cpp svg/SvgUtil.cpp svg/SvgGraphicContext.cpp svg/SvgSavingContext.cpp svg/SvgWriter.cpp svg/SvgStyleWriter.cpp svg/SvgShape.cpp svg/SvgParser.cpp svg/SvgStyleParser.cpp svg/SvgGradientHelper.cpp svg/SvgPatternHelper.cpp svg/SvgFilterHelper.cpp svg/SvgCssHelper.cpp svg/SvgClipPathHelper.cpp svg/SvgLoadingContext.cpp svg/SvgShapeFactory.cpp FlakeDebug.cpp ) ki18n_wrap_ui(kritaflake_SRCS tools/PathToolOptionWidgetBase.ui KoConnectionShapeConfigWidget.ui tools/KoZoomToolWidget.ui ) add_library(kritaflake SHARED ${kritaflake_SRCS}) generate_export_header(kritaflake BASE_NAME kritaflake) target_include_directories(kritaflake PUBLIC $ $ $ ) target_link_libraries(kritaflake kritapigment kritawidgetutils kritaodf kritaundo2 KF5::WidgetsAddons Qt5::Svg) target_link_libraries(kritaflake LINK_INTERFACE_LIBRARIES kritapigment kritawidgetutils kritaodf kritaundo2 KF5::WidgetsAddons ) set_target_properties(kritaflake PROPERTIES VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION} ) install(TARGETS kritaflake ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/libs/flake/KoCanvasResourceManager.cpp b/libs/flake/KoCanvasResourceManager.cpp index da7b047f2e..45f2189de4 100644 --- a/libs/flake/KoCanvasResourceManager.cpp +++ b/libs/flake/KoCanvasResourceManager.cpp @@ -1,182 +1,197 @@ /* Copyright (c) 2006 Boudewijn Rempt (boud@valdyas.org) Copyright (C) 2007, 2010 Thomas Zander Copyright (c) 2008 Carlos Licea Copyright (c) 2011 Jan Hambrecht 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. */ #include "KoCanvasResourceManager.h" #include #include #include "KoShape.h" #include "KoShapeStroke.h" #include "KoResourceManager_p.h" #include class Q_DECL_HIDDEN KoCanvasResourceManager::Private { public: KoResourceManager manager; }; KoCanvasResourceManager::KoCanvasResourceManager(QObject *parent) : QObject(parent), d(new Private()) { const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8(); setForegroundColor(KoColor(Qt::black, cs)); setBackgroundColor(KoColor(Qt::white, cs)); setResource(ApplicationSpeciality, NoSpecial); connect(&d->manager, &KoResourceManager::resourceChanged, this, &KoCanvasResourceManager::canvasResourceChanged); } KoCanvasResourceManager::~KoCanvasResourceManager() { delete d; } void KoCanvasResourceManager::setResource(int key, const QVariant &value) { d->manager.setResource(key, value); } QVariant KoCanvasResourceManager::resource(int key) const { return d->manager.resource(key); } void KoCanvasResourceManager::setResource(int key, const KoColor &color) { QVariant v; v.setValue(color); setResource(key, v); } void KoCanvasResourceManager::setResource(int key, KoShape *shape) { QVariant v; v.setValue(shape); setResource(key, v); } void KoCanvasResourceManager::setResource(int key, const KoUnit &unit) { QVariant v; v.setValue(unit); setResource(key, v); } KoColor KoCanvasResourceManager::koColorResource(int key) const { return d->manager.koColorResource(key); } void KoCanvasResourceManager::setForegroundColor(const KoColor &color) { setResource(ForegroundColor, color); } KoColor KoCanvasResourceManager::foregroundColor() const { return koColorResource(ForegroundColor); } void KoCanvasResourceManager::setBackgroundColor(const KoColor &color) { setResource(BackgroundColor, color); } KoColor KoCanvasResourceManager::backgroundColor() const { return koColorResource(BackgroundColor); } KoShape *KoCanvasResourceManager::koShapeResource(int key) const { return d->manager.koShapeResource(key); } KoUnit KoCanvasResourceManager::unitResource(int key) const { return resource(key).value(); } void KoCanvasResourceManager::setActiveStroke(const KoShapeStroke &stroke) { QVariant v; v.setValue(stroke); setResource(ActiveStroke, v); } KoShapeStroke KoCanvasResourceManager::activeStroke() const { if (!d->manager.hasResource(ActiveStroke)) { KoShapeStroke empty; return empty; } return resource(ActiveStroke).value(); } bool KoCanvasResourceManager::boolResource(int key) const { return d->manager.boolResource(key); } int KoCanvasResourceManager::intResource(int key) const { return d->manager.intResource(key); } QString KoCanvasResourceManager::stringResource(int key) const { return d->manager.stringResource(key); } QSizeF KoCanvasResourceManager::sizeResource(int key) const { return d->manager.sizeResource(key); } bool KoCanvasResourceManager::hasResource(int key) const { return d->manager.hasResource(key); } void KoCanvasResourceManager::clearResource(int key) { d->manager.clearResource(key); } void KoCanvasResourceManager::addDerivedResourceConverter(KoDerivedResourceConverterSP converter) { d->manager.addDerivedResourceConverter(converter); } bool KoCanvasResourceManager::hasDerivedResourceConverter(int key) { return d->manager.hasDerivedResourceConverter(key); } void KoCanvasResourceManager::removeDerivedResourceConverter(int key) { d->manager.removeDerivedResourceConverter(key); } + +void KoCanvasResourceManager::addResourceUpdateMediator(KoResourceUpdateMediatorSP mediator) +{ + d->manager.addResourceUpdateMediator(mediator); +} + +bool KoCanvasResourceManager::hasResourceUpdateMediator(int key) +{ + return d->manager.hasResourceUpdateMediator(key); +} + +void KoCanvasResourceManager::removeResourceUpdateMediator(int key) +{ + d->manager.removeResourceUpdateMediator(key); +} diff --git a/libs/flake/KoCanvasResourceManager.h b/libs/flake/KoCanvasResourceManager.h index 96fc90bd03..9060cdb3d1 100644 --- a/libs/flake/KoCanvasResourceManager.h +++ b/libs/flake/KoCanvasResourceManager.h @@ -1,271 +1,288 @@ /* Copyright (c) 2006, 2011 Boudewijn Rempt (boud@valdyas.org) Copyright (C) 2007, 2009, 2010 Thomas Zander Copyright (c) 2008 Carlos Licea 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 KO_CANVASRESOURCEMANAGER_H #define KO_CANVASRESOURCEMANAGER_H #include #include "kritaflake_export.h" #include "KoDerivedResourceConverter.h" +#include "KoResourceUpdateMediator.h" class KoShape; class KoShapeStroke; class KoColor; class KoUnit; class QVariant; class QSizeF; /** * The KoCanvasResourceManager contains a set of per-canvas * properties, like current foreground color, current background * color and more. All tools belonging to the current canvas are * notified when a Resource changes (is set). * * The manager can contain all sorts of variable types and there are accessors * for the most common ones. All variables are always stored inside a QVariant * instance internally and you can always just use the resource() method to get * that directly. * The way to store arbitairy data objects that are stored as pointers you can use * the following code snippets; * @code * QVariant variant; * variant.setValue(textShapeData->document()); * resourceManager->setResource(KoText::CurrentTextDocument, variant); * // and get it out again. * QVariant var = resourceManager->resource(KoText::CurrentTextDocument); * document = static_cast(var.value()); * @endcode */ class KRITAFLAKE_EXPORT KoCanvasResourceManager : public QObject { Q_OBJECT public: /** * This enum holds identifiers to the resources that can be stored in here. */ enum CanvasResource { ForegroundColor, ///< The active forground color selected for this canvas. BackgroundColor, ///< The active background color selected for this canvas. ActiveStroke, ///< The active stroke selected for this canvas PageSize, ///< The size of the (current) page in postscript points. Unit, ///< The unit of this canvas CurrentPage, ///< The current page number ActiveStyleType, ///< the actual active style type see KoFlake::StyleType for valid values ActiveRange, ///< The area where the rulers should show white ShowTextShapeOutlines, ///< Paint of text shape outlines ? ShowFormattingCharacters, ///< Paint of formatting characters ? ShowTableBorders, ///< Paint of table borders (when not really there) ? ShowSectionBounds, ///< Paint of sections bounds ? ShowInlineObjectVisualization, ///< paint a different background for inline objects ApplicationSpeciality, ///< Special features and limitations of the application KarbonStart = 1000, ///< Base number for Karbon specific values. KexiStart = 2000, ///< Base number for Kexi specific values. FlowStart = 3000, ///< Base number for Flow specific values. PlanStart = 4000, ///< Base number for Plan specific values. StageStart = 5000, ///< Base number for Stage specific values. KritaStart = 6000, ///< Base number for Krita specific values. SheetsStart = 7000, ///< Base number for Sheets specific values. WordsStart = 8000, ///< Base number for Words specific values. KoPageAppStart = 9000 ///< Base number for KoPageApp specific values. }; enum ApplicationSpecial { NoSpecial = 0, NoAdvancedText = 1 }; /** * Constructor. * @param parent the parent QObject, used for memory management. */ explicit KoCanvasResourceManager(QObject *parent = 0); virtual ~KoCanvasResourceManager(); public Q_SLOTS: /** * Set a resource of any type. * @param key the integer key * @param value the new value for the key. * @see KoCanvasResourceManager::CanvasResource */ void setResource(int key, const QVariant &value); /** * Set a resource of type KoColor. * @param key the integer key * @param color the new value for the key. * @see KoCanvasResourceManager::CanvasResource */ void setResource(int key, const KoColor &color); /** * Set a resource of type KoShape*. * @param key the integer key * @param id the new value for the key. * @see KoCanvasResourceManager::CanvasResource */ void setResource(int key, KoShape *shape); /** * Set a resource of type KoUnit * @param key the integer key * @param id the new value for the key. * @see KoCanvasResourceManager::CanvasResource */ void setResource(int key, const KoUnit &unit); public: /** * Returns a qvariant containing the specified resource or a standard one if the * specified resource does not exist. * @param key the key * @see KoCanvasResourceManager::CanvasResource */ QVariant resource(int key) const; /** * Set the foregroundColor resource. * @param color the new foreground color */ void setForegroundColor(const KoColor &color); /** * Return the foregroundColor */ KoColor foregroundColor() const; /** * Set the backgroundColor resource. * @param color the new background color */ void setBackgroundColor(const KoColor &color); /** * Return the backgroundColor */ KoColor backgroundColor() const; /// Sets the stroke resource void setActiveStroke(const KoShapeStroke &stroke); /// Returns the stroke resource KoShapeStroke activeStroke() const; /** * Return the resource determined by param key as a boolean. * @param key the indentifying key for the resource * @see KoCanvasResourceManager::CanvasResource */ bool boolResource(int key) const; /** * Return the resource determined by param key as an integer. * @param key the indentifying key for the resource * @see KoCanvasResourceManager::CanvasResource */ int intResource(int key) const; /** * Return the resource determined by param key as a KoColor. * @param key the indentifying key for the resource * @see KoCanvasResourceManager::CanvasResource */ KoColor koColorResource(int key) const; /** * Return the resource determined by param key as a pointer to a KoShape. * @param key the indentifying key for the resource * @see KoCanvasResourceManager::CanvasResource */ KoShape *koShapeResource(int key) const; /** * Return the resource determined by param key as a QString . * @param key the indentifying key for the resource * @see KoCanvasResourceManager::CanvasResource */ QString stringResource(int key) const; /** * Return the resource determined by param key as a QSizeF. * @param key the indentifying key for the resource * @see KoCanvasResourceManager::CanvasResource */ QSizeF sizeResource(int key) const; /** * Return the resource determined by param key as a KoUnit. * @param key the indentifying key for the resource * @see KoCanvasResourceManager::CanvasResource */ KoUnit unitResource(int key) const; /** * Returns true if there is a resource set with the requested key. * @param key the indentifying key for the resource * @see KoCanvasResourceManager::CanvasResource */ bool hasResource(int key) const; /** * Remove the resource with @p key from the provider. * @param key the key that will be used to remove the resource * There will be a signal emitted with a variable that will return true on QVariable::isNull(); * @see KoCanvasResourceManager::CanvasResource */ void clearResource(int key); /** * @see KoReosurceManager::addDerivedResourceConverter() */ void addDerivedResourceConverter(KoDerivedResourceConverterSP converter); /** * @see KoReosurceManager::hasDerivedResourceConverter() */ bool hasDerivedResourceConverter(int key); /** * @see KoReosurceManager::removeDerivedResourceConverter() */ void removeDerivedResourceConverter(int key); + /** + * @see KoReosurceManager::addResourceUpdateMediator + */ + void addResourceUpdateMediator(KoResourceUpdateMediatorSP mediator); + + /** + * @see KoReosurceManager::hasResourceUpdateMediator + */ + bool hasResourceUpdateMediator(int key); + + /** + + * @see KoReosurceManager::removeResourceUpdateMediator + */ + void removeResourceUpdateMediator(int key); + Q_SIGNALS: /** * This signal is emitted every time a resource is set that is either * new or different from the previous set value. * @param key the indentifying key for the resource * @param value the variants new value. * @see KoCanvasResourceManager::CanvasResource */ void canvasResourceChanged(int key, const QVariant &value); private: KoCanvasResourceManager(const KoCanvasResourceManager&); KoCanvasResourceManager& operator=(const KoCanvasResourceManager&); class Private; Private *const d; }; #endif diff --git a/libs/flake/KoDerivedResourceConverter.cpp b/libs/flake/KoDerivedResourceConverter.cpp index 1ae9f1c111..93b59c88d0 100644 --- a/libs/flake/KoDerivedResourceConverter.cpp +++ b/libs/flake/KoDerivedResourceConverter.cpp @@ -1,52 +1,93 @@ /* * 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. */ #include "KoDerivedResourceConverter.h" #include "QVariant" - +#include "kis_assert.h" struct KoDerivedResourceConverter::Private { Private(int _key, int _sourceKey) : key(_key), sourceKey(_sourceKey) {} int key; int sourceKey; + + QVariant lastKnownValue; }; KoDerivedResourceConverter::KoDerivedResourceConverter(int key, int sourceKey) : m_d(new Private(key, sourceKey)) { } KoDerivedResourceConverter::~KoDerivedResourceConverter() { } int KoDerivedResourceConverter::key() const { return m_d->key; } int KoDerivedResourceConverter::sourceKey() const { return m_d->sourceKey; } +bool KoDerivedResourceConverter::notifySourceChanged(const QVariant &sourceValue) +{ + const QVariant newValue = fromSource(sourceValue); + + const bool valueChanged = m_d->lastKnownValue != newValue; + m_d->lastKnownValue = newValue; + + return valueChanged; +} + +QVariant KoDerivedResourceConverter::readFromSource(const QVariant &sourceValue) +{ + const QVariant result = fromSource(sourceValue); + + KIS_SAFE_ASSERT_RECOVER_NOOP(m_d->lastKnownValue.isNull() || + result == m_d->lastKnownValue); + + m_d->lastKnownValue = result; + + return m_d->lastKnownValue; +} + +QVariant KoDerivedResourceConverter::writeToSource(const QVariant &value, + const QVariant &sourceValue, + bool *changed) +{ + if (changed) { + *changed = m_d->lastKnownValue != value; + } + + QVariant newSourceValue = sourceValue; + + if (*changed || value != fromSource(sourceValue)) { + m_d->lastKnownValue = value; + newSourceValue = toSource(value, sourceValue); + } + + return newSourceValue; +} diff --git a/libs/flake/KoDerivedResourceConverter.h b/libs/flake/KoDerivedResourceConverter.h index ffffbc212d..8cf03b9f34 100644 --- a/libs/flake/KoDerivedResourceConverter.h +++ b/libs/flake/KoDerivedResourceConverter.h @@ -1,71 +1,79 @@ /* * 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 __KO_DERIVED_RESOURCE_CONVERTER_H #define __KO_DERIVED_RESOURCE_CONVERTER_H #include #include #include "kritaflake_export.h" class QVariant; /** * \class KoDerivedResourceConverter * * Defines the abstraction of a derived resource. It should be * uploaded to the KoResourceManager during loading phase. The manager * will use it to convert values to/from the source resource. */ class KRITAFLAKE_EXPORT KoDerivedResourceConverter { public: /** * \param key the unique id of the resource defined by this * converter * * \param sourceKey the id of the parent resource, i.e. where the * values are really loaded/saved. */ KoDerivedResourceConverter(int key, int sourceKey); virtual ~KoDerivedResourceConverter(); int key() const; int sourceKey() const; + QVariant readFromSource(const QVariant &value); + QVariant writeToSource(const QVariant &value, + const QVariant &sourceValue, + bool *changed); + + virtual bool notifySourceChanged(const QVariant &sourceValue); + +protected: /** * Converts the \p value of the source resource into the space of * the "derived" resource. E.g. preset -> opacity. */ virtual QVariant fromSource(const QVariant &value) = 0; /** * Converts the value of the "derived" resource into the space of the * original ("source") resource. E.g. opacity -> preset. */ virtual QVariant toSource(const QVariant &value, const QVariant &sourceValue) = 0; private: struct Private; const QScopedPointer m_d; }; typedef QSharedPointer KoDerivedResourceConverterSP; #endif /* __KO_DERIVED_RESOURCE_CONVERTER_H */ diff --git a/libs/flake/KoResourceManager_p.cpp b/libs/flake/KoResourceManager_p.cpp index ad8b11d50f..eeca376054 100644 --- a/libs/flake/KoResourceManager_p.cpp +++ b/libs/flake/KoResourceManager_p.cpp @@ -1,196 +1,239 @@ /* Copyright (c) 2006, 2011 Boudewijn Rempt (boud@valdyas.org) Copyright (C) 2007, 2010 Thomas Zander Copyright (c) 2008 Carlos Licea Copyright (c) 2011 Jan Hambrecht 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. */ #include "KoResourceManager_p.h" #include #include #include "KoShape.h" +#include "kis_assert.h" +#include "kis_debug.h" -void KoResourceManager::setResource(int key, const QVariant &value) +void KoResourceManager::slotResourceInternalsChanged(int key) { - QVariant realValue = value; - int realKey = key; - QVariant currentValue = m_resources.value(key, QVariant()); + KIS_SAFE_ASSERT_RECOVER_RETURN(m_resources.contains(key)); + notifyDerivedResourcesChanged(key, m_resources[key]); +} +void KoResourceManager::setResource(int key, const QVariant &value) +{ KoDerivedResourceConverterSP converter = m_derivedResources.value(key, KoDerivedResourceConverterSP()); if (converter) { - realKey = converter->sourceKey(); - currentValue = m_resources.value(realKey, QVariant()); - realValue = converter->toSource(value, currentValue); - } + const int sourceKey = converter->sourceKey(); + const QVariant oldSourceValue = m_resources.value(sourceKey, QVariant()); + + bool valueChanged = false; + const QVariant newSourceValue = converter->writeToSource(value, oldSourceValue, &valueChanged); + + if (valueChanged) { + notifyResourceChanged(key, value); + } + + if (oldSourceValue != newSourceValue) { + m_resources[sourceKey] = newSourceValue; + notifyResourceChanged(sourceKey, newSourceValue); + } - if (m_resources.contains(realKey)) { - if (!converter && currentValue == realValue) - return; - m_resources[realKey] = realValue; } else { - m_resources.insert(realKey, realValue); - } + const QVariant oldValue = m_resources.value(key, QVariant()); + m_resources[key] = value; - notifyResourceChanged(key, value); + if (m_updateMediators.contains(key)) { + m_updateMediators[key]->connectResource(value); + } + + if (oldValue != value) { + notifyResourceChanged(key, value); + } + } } void KoResourceManager::notifyResourceChanged(int key, const QVariant &value) { emit resourceChanged(key, value); + notifyDerivedResourcesChanged(key, value); +} +void KoResourceManager::notifyDerivedResourcesChanged(int key, const QVariant &value) +{ QMultiHash::const_iterator it = m_derivedFromSource.constFind(key); QMultiHash::const_iterator end = m_derivedFromSource.constEnd(); while (it != end && it.key() == key) { KoDerivedResourceConverterSP converter = it.value(); - notifyResourceChanged(converter->key(), converter->fromSource(value)); + + if (converter->notifySourceChanged(value)) { + notifyResourceChanged(converter->key(), converter->readFromSource(value)); + } + it++; } } QVariant KoResourceManager::resource(int key) const { KoDerivedResourceConverterSP converter = m_derivedResources.value(key, KoDerivedResourceConverterSP()); const int realKey = converter ? converter->sourceKey() : key; QVariant value = m_resources.value(realKey, QVariant()); - return converter ? converter->fromSource(value) : value; + return converter ? converter->readFromSource(value) : value; } void KoResourceManager::setResource(int key, const KoColor &color) { QVariant v; v.setValue(color); setResource(key, v); } void KoResourceManager::setResource(int key, KoShape *shape) { QVariant v; v.setValue(shape); setResource(key, v); } void KoResourceManager::setResource(int key, const KoUnit &unit) { QVariant v; v.setValue(unit); setResource(key, v); } KoColor KoResourceManager::koColorResource(int key) const { if (! m_resources.contains(key)) { KoColor empty; return empty; } return resource(key).value(); } KoShape *KoResourceManager::koShapeResource(int key) const { if (! m_resources.contains(key)) return 0; return resource(key).value(); } KoUnit KoResourceManager::unitResource(int key) const { return resource(key).value(); } bool KoResourceManager::boolResource(int key) const { if (! m_resources.contains(key)) return false; return m_resources[key].toBool(); } int KoResourceManager::intResource(int key) const { if (! m_resources.contains(key)) return 0; return m_resources[key].toInt(); } QString KoResourceManager::stringResource(int key) const { if (! m_resources.contains(key)) { QString empty; return empty; } return qvariant_cast(resource(key)); } QSizeF KoResourceManager::sizeResource(int key) const { if (! m_resources.contains(key)) { QSizeF empty; return empty; } return qvariant_cast(resource(key)); } bool KoResourceManager::hasResource(int key) const { KoDerivedResourceConverterSP converter = m_derivedResources.value(key, KoDerivedResourceConverterSP()); const int realKey = converter ? converter->sourceKey() : key; return m_resources.contains(realKey); } void KoResourceManager::clearResource(int key) { // we cannot remove a derived resource if (m_derivedResources.contains(key)) return; if (m_resources.contains(key)) { m_resources.remove(key); notifyResourceChanged(key, QVariant()); } } void KoResourceManager::addDerivedResourceConverter(KoDerivedResourceConverterSP converter) { - Q_ASSERT(!m_derivedResources.contains(converter->key())); + KIS_SAFE_ASSERT_RECOVER_NOOP(!m_derivedResources.contains(converter->key())); m_derivedResources.insert(converter->key(), converter); m_derivedFromSource.insertMulti(converter->sourceKey(), converter); } bool KoResourceManager::hasDerivedResourceConverter(int key) { return m_derivedResources.contains(key); } void KoResourceManager::removeDerivedResourceConverter(int key) { Q_ASSERT(m_derivedResources.contains(key)); KoDerivedResourceConverterSP converter = m_derivedResources.value(key); m_derivedResources.remove(key); m_derivedFromSource.remove(converter->sourceKey(), converter); } + +void KoResourceManager::addResourceUpdateMediator(KoResourceUpdateMediatorSP mediator) +{ + KIS_SAFE_ASSERT_RECOVER_NOOP(!m_updateMediators.contains(mediator->key())); + m_updateMediators.insert(mediator->key(), mediator); + connect(mediator.data(), SIGNAL(sigResourceChanged(int)), SLOT(slotResourceInternalsChanged(int))); +} + +bool KoResourceManager::hasResourceUpdateMediator(int key) +{ + return m_updateMediators.contains(key); +} + +void KoResourceManager::removeResourceUpdateMediator(int key) +{ + KIS_SAFE_ASSERT_RECOVER_RETURN(m_updateMediators.contains(key)); + m_updateMediators.remove(key); +} diff --git a/libs/flake/KoResourceManager_p.h b/libs/flake/KoResourceManager_p.h index d58fc52b9d..98afb0d582 100644 --- a/libs/flake/KoResourceManager_p.h +++ b/libs/flake/KoResourceManager_p.h @@ -1,192 +1,220 @@ /* Copyright (c) 2006, 2011 Boudewijn Rempt (boud@valdyas.org) Copyright (C) 2007, 2009, 2010 Thomas Zander Copyright (c) 2008 Carlos Licea 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 KO_RESOURCEMANAGER_P_H #define KO_RESOURCEMANAGER_P_H #include #include #include #include "kritaflake_export.h" #include #include #include "KoDerivedResourceConverter.h" +#include "KoResourceUpdateMediator.h" + class KoShape; class QVariant; class KRITAFLAKE_EXPORT KoResourceManager : public QObject { Q_OBJECT public: KoResourceManager() {} /** * Set a resource of any type. * @param key the integer key * @param value the new value for the key. * @see KoCanvasResourceManager::CanvasResource KoDocumentResourceManager::DocumentResource */ void setResource(int key, const QVariant &value); /** * Set a resource of type KoColor. * @param key the integer key * @param color the new value for the key. * @see KoCanvasResourceManager::CanvasResource KoDocumentResourceManager::DocumentResource */ void setResource(int key, const KoColor &color); /** * Set a resource of type KoShape*. * @param key the integer key * @param id the new value for the key. * @see KoCanvasResourceManager::CanvasResource KoDocumentResourceManager::DocumentResource */ void setResource(int key, KoShape *shape); /** * Set a resource of type KoUnit * @param key the integer key * @param id the new value for the key. * @see KoCanvasResourceManager::CanvasResource KoDocumentResourceManager::DocumentResource */ void setResource(int key, const KoUnit &unit); /** * Returns a qvariant containing the specified resource or a standard one if the * specified resource does not exist. * @param key the key * @see KoCanvasResourceManager::CanvasResource KoDocumentResourceManager::DocumentResource */ QVariant resource(int key) const; /** * Return the resource determined by param key as a boolean. * @param key the indentifying key for the resource * @see KoCanvasResourceManager::CanvasResource KoDocumentResourceManager::DocumentResource */ bool boolResource(int key) const; /** * Return the resource determined by param key as an integer. * @param key the indentifying key for the resource * @see KoCanvasResourceManager::CanvasResource KoDocumentResourceManager::DocumentResource */ int intResource(int key) const; /** * Return the resource determined by param key as a KoColor. * @param key the indentifying key for the resource * @see KoCanvasResourceManager::CanvasResource KoDocumentResourceManager::DocumentResource */ KoColor koColorResource(int key) const; /** * Return the resource determined by param key as a pointer to a KoShape. * @param key the indentifying key for the resource * @see KoCanvasResourceManager::CanvasResource KoDocumentResourceManager::DocumentResource */ KoShape *koShapeResource(int key) const; /** * Return the resource determined by param key as a QString . * @param key the indentifying key for the resource * @see KoCanvasResourceManager::CanvasResource KoDocumentResourceManager::DocumentResource */ QString stringResource(int key) const; /** * Return the resource determined by param key as a QSizeF. * @param key the indentifying key for the resource * @see KoCanvasResourceManager::CanvasResource KoDocumentResourceManager::DocumentResource */ QSizeF sizeResource(int key) const; /** * Return the resource determined by param key as a KoUnit. * @param key the indentifying key for the resource * @see KoCanvasResourceManager::CanvasResource KoDocumentResourceManager::DocumentResource */ KoUnit unitResource(int key) const; /** * Returns true if there is a resource set with the requested key. * @param key the indentifying key for the resource * @see KoCanvasResourceManager::CanvasResource KoDocumentResourceManager::DocumentResource */ bool hasResource(int key) const; /** * Remove the resource with @p key from the provider. * @param key the key that will be used to remove the resource * @see KoCanvasResourceManager::CanvasResource KoDocumentResourceManager::DocumentResource */ void clearResource(int key); /** - * Some of the resources may be "derive" from the other. For + * Some of the resources may be "derived" from the others. For * example opacity, composite op and erase mode properties are * contained inside a paintop preset, so we need not create a * separate resource for them. Instead we created a derived resource, * that loads/saves values from/to another resource, but has its own * "resource changed" signal (via a different key). * * When a parent resource changes, the resource manager emits - * update signals for all its derived resources. + * update signals for all its derived resources. */ void addDerivedResourceConverter(KoDerivedResourceConverterSP converter); /** * @return true if the resource with \p key is a derived resource * (has a converter installed) * * @see addDerivedResourceConverter() */ bool hasDerivedResourceConverter(int key); /** * Removes a derived resource converter. If you rty to add a * resource with \p key it will be treated as a usual resource. * * @see addDerivedResourceConverter() */ void removeDerivedResourceConverter(int key); + /** + * Some resources can "mutate", that is they value doesn't change + * (a pointer), whereas the contents changes. But we should still + * notify all the derived resources subscribers that the resource + * has changed. For that purpose we use a special mediator class + * that connects the resource (which is not a QObject at all) and + * the resource manager controls that connection. + */ + void addResourceUpdateMediator(KoResourceUpdateMediatorSP mediator); + + /** + * \see addResourceUpdateMediator() + */ + bool hasResourceUpdateMediator(int key); + + /** + * \see addResourceUpdateMediator() + */ + void removeResourceUpdateMediator(int key); + Q_SIGNALS: void resourceChanged(int key, const QVariant &value); private: void notifyResourceChanged(int key, const QVariant &value); + void notifyDerivedResourcesChanged(int key, const QVariant &value); + +private Q_SLOTS: + void slotResourceInternalsChanged(int key); private: KoResourceManager(const KoResourceManager&); KoResourceManager& operator=(const KoResourceManager&); QHash m_resources; QHash m_derivedResources; QMultiHash m_derivedFromSource; + + QHash m_updateMediators; }; #endif diff --git a/libs/flake/KoDerivedResourceConverter.cpp b/libs/flake/KoResourceUpdateMediator.cpp similarity index 62% copy from libs/flake/KoDerivedResourceConverter.cpp copy to libs/flake/KoResourceUpdateMediator.cpp index 1ae9f1c111..1a641be458 100644 --- a/libs/flake/KoDerivedResourceConverter.cpp +++ b/libs/flake/KoResourceUpdateMediator.cpp @@ -1,52 +1,41 @@ /* * 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. */ -#include "KoDerivedResourceConverter.h" +#include "KoResourceUpdateMediator.h" -#include "QVariant" - -struct KoDerivedResourceConverter::Private +struct KoResourceUpdateMediator::Private { - Private(int _key, int _sourceKey) - : key(_key), sourceKey(_sourceKey) {} - + Private(int _key) : key(_key) {} int key; - int sourceKey; }; -KoDerivedResourceConverter::KoDerivedResourceConverter(int key, int sourceKey) - : m_d(new Private(key, sourceKey)) +KoResourceUpdateMediator::KoResourceUpdateMediator(int key) + : m_d(new Private(key)) { } -KoDerivedResourceConverter::~KoDerivedResourceConverter() +KoResourceUpdateMediator::~KoResourceUpdateMediator() { } -int KoDerivedResourceConverter::key() const +int KoResourceUpdateMediator::key() const { return m_d->key; } - -int KoDerivedResourceConverter::sourceKey() const -{ - return m_d->sourceKey; -} - diff --git a/libs/flake/KoResourceUpdateMediator.h b/libs/flake/KoResourceUpdateMediator.h new file mode 100644 index 0000000000..602df7443d --- /dev/null +++ b/libs/flake/KoResourceUpdateMediator.h @@ -0,0 +1,57 @@ +/* + * 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 __KO_RESOURCE_UPDATE_MEDIATOR_H +#define __KO_RESOURCE_UPDATE_MEDIATOR_H + +#include +#include +#include "kritaflake_export.h" + +/** + * A special mediator class that connects the resource and the + * resource manager. The resource manager connects to a + * sigResourceChanged() changed and when a resource changes, the + * manager calls connectResource() for this resource. After that, the + * mediator should notify the manager about every change that happens + * to the resource by emitting the corresponding signal. + * + * There is only one mediator for one type (key) of the resource. + */ + +class KRITAFLAKE_EXPORT KoResourceUpdateMediator : public QObject +{ + Q_OBJECT +public: + KoResourceUpdateMediator(int key); + virtual ~KoResourceUpdateMediator(); + + int key() const; + virtual void connectResource(QVariant sourceResource) = 0; + +Q_SIGNALS: + void sigResourceChanged(int key); + +private: + struct Private; + const QScopedPointer m_d; +}; + +typedef QSharedPointer KoResourceUpdateMediatorSP; + +#endif /* __KO_RESOURCE_UPDATE_MEDIATOR_H */ diff --git a/libs/flake/tests/TestResourceManager.cpp b/libs/flake/tests/TestResourceManager.cpp index 9f9d2b5bf5..bd31773b43 100644 --- a/libs/flake/tests/TestResourceManager.cpp +++ b/libs/flake/tests/TestResourceManager.cpp @@ -1,144 +1,389 @@ /* This file is part of the KDE project Copyright (C) 2008 Thorsten Zachmann 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. */ #include "TestResourceManager.h" #include "KoCanvasResourceManager.h" #include "KoResourceManager_p.h" #include "KoPathShape.h" #include "KoUnit.h" #include #include +#include "kis_debug.h" + void TestResourceManager::koShapeResource() { KoPathShape * shape = new KoPathShape(); int key = 9001; KoCanvasResourceManager rp( 0 ); rp.setResource( key, shape ); QVERIFY( shape == rp.koShapeResource( key ) ); } void TestResourceManager::testUnitChanged() { KoCanvasResourceManager rm(0); QSignalSpy spy(&rm, SIGNAL(canvasResourceChanged(int, const QVariant &))); KoUnit a; rm.setResource(KoCanvasResourceManager::Unit, a); QCOMPARE(spy.count(), 1); KoUnit b(KoUnit::Millimeter); rm.setResource(KoCanvasResourceManager::Unit, b); QCOMPARE(spy.count(), 2); } #include "kis_global.h" struct DerivedResource : public KoDerivedResourceConverter { DerivedResource(int key, int sourceKey) : KoDerivedResourceConverter(key, sourceKey) {} QVariant fromSource(const QVariant &value) { return value.toInt() + 10; } QVariant toSource(const QVariant &value, const QVariant &sourceValue) { Q_UNUSED(sourceValue); return value.toInt() - 10; } }; void TestResourceManager::testConverters() { KoResourceManager m; const int key1 = 1; const int key2 = 2; const int derivedKey = 3; m.setResource(key1, 1); m.setResource(key2, 2); QCOMPARE(m.resource(key1).toInt(), 1); QCOMPARE(m.resource(key2).toInt(), 2); QVERIFY(!m.hasResource(derivedKey)); m.addDerivedResourceConverter(toQShared(new DerivedResource(derivedKey, key2))); QCOMPARE(m.resource(derivedKey).toInt(), 12); QVERIFY(m.hasResource(derivedKey)); m.setResource(derivedKey, 15); QCOMPARE(m.resource(key2).toInt(), 5); QCOMPARE(m.resource(derivedKey).toInt(), 15); QVERIFY(m.hasResource(derivedKey)); m.clearResource(derivedKey); QVERIFY(m.hasResource(derivedKey)); m.clearResource(key2); QVERIFY(!m.hasResource(derivedKey)); } void TestResourceManager::testDerivedChanged() { // const int key1 = 1; const int key2 = 2; const int derivedKey = 3; const int otherDerivedKey = 4; KoCanvasResourceManager m(0); m.addDerivedResourceConverter(toQShared(new DerivedResource(derivedKey, key2))); m.addDerivedResourceConverter(toQShared(new DerivedResource(otherDerivedKey, key2))); m.setResource(derivedKey, 15); QCOMPARE(m.resource(key2).toInt(), 5); QCOMPARE(m.resource(derivedKey).toInt(), 15); QSignalSpy spy(&m, SIGNAL(canvasResourceChanged(int, const QVariant &))); m.setResource(derivedKey, 16); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.count(), 3); QList args; args = spy[0]; QCOMPARE(args[0].toInt(), derivedKey); QCOMPARE(args[1].toInt(), 16); + args = spy[1]; + QCOMPARE(args[0].toInt(), key2); + QCOMPARE(args[1].toInt(), 6); + + args = spy[2]; + QCOMPARE(args[0].toInt(), otherDerivedKey); + QCOMPARE(args[1].toInt(), 16); + + spy.clear(); + m.setResource(key2, 7); - QCOMPARE(spy.count(), 4); + QCOMPARE(spy.count(), 3); - args = spy[1]; + args = spy[0]; QCOMPARE(args[0].toInt(), key2); QCOMPARE(args[1].toInt(), 7); - args = spy[2]; + args = spy[1]; QCOMPARE(args[0].toInt(), otherDerivedKey); QCOMPARE(args[1].toInt(), 17); - args = spy[3]; + args = spy[2]; QCOMPARE(args[0].toInt(), derivedKey); QCOMPARE(args[1].toInt(), 17); } +struct ComplexResource { + QHash m_resources; +}; + +typedef QSharedPointer ComplexResourceSP; +Q_DECLARE_METATYPE(ComplexResourceSP); + +struct ComplexConverter : public KoDerivedResourceConverter +{ + ComplexConverter(int key, int sourceKey) : KoDerivedResourceConverter(key, sourceKey) {} + + QVariant fromSource(const QVariant &value) { + KIS_ASSERT(value.canConvert()); + ComplexResourceSP res = value.value(); + + return res->m_resources[key()]; + } + + QVariant toSource(const QVariant &value, const QVariant &sourceValue) { + KIS_ASSERT(sourceValue.canConvert()); + ComplexResourceSP res = sourceValue.value(); + + res->m_resources[key()] = value; + return QVariant::fromValue(res); + } +}; + +struct ComplexMediator : public KoResourceUpdateMediator +{ + ComplexMediator(int key) : KoResourceUpdateMediator(key) {} + + void connectResource(QVariant sourceResource) { + m_res = sourceResource; + } + + void forceNotify() { + emit sigResourceChanged(key()); + } + + QVariant m_res; +}; +typedef QSharedPointer ComplexMediatorSP; + +void TestResourceManager::testComplexResource() +{ + const int key = 2; + const int complex1 = 3; + const int complex2 = 4; + + KoCanvasResourceManager m(0); + m.addDerivedResourceConverter(toQShared(new ComplexConverter(complex1, key))); + m.addDerivedResourceConverter(toQShared(new ComplexConverter(complex2, key))); + + ComplexMediatorSP mediator(new ComplexMediator(key)); + m.addResourceUpdateMediator(mediator); + + QSignalSpy spy(&m, SIGNAL(canvasResourceChanged(int, const QVariant &))); + + ComplexResourceSP r1(new ComplexResource()); + r1->m_resources[complex1] = 10; + r1->m_resources[complex2] = 20; + + ComplexResourceSP r2(new ComplexResource()); + r2->m_resources[complex1] = 15; + r2->m_resources[complex2] = 25; + + + // #################################################### + // Initial assignment + // #################################################### + m.setResource(key, QVariant::fromValue(r1)); + + QCOMPARE(mediator->m_res.value(), r1); + QCOMPARE(m.resource(key).value(), r1); + QCOMPARE(m.resource(complex1).toInt(), 10); + QCOMPARE(m.resource(complex2).toInt(), 20); + + QCOMPARE(spy[0][0].toInt(), key); + QCOMPARE(spy[0][1].value(), r1); + QCOMPARE(spy[1][0].toInt(), complex2); + QCOMPARE(spy[1][1].toInt(), 20); + QCOMPARE(spy[2][0].toInt(), complex1); + QCOMPARE(spy[2][1].toInt(), 10); + spy.clear(); + + // #################################################### + // Change the whole resource + // #################################################### + m.setResource(key, QVariant::fromValue(r2)); + + QCOMPARE(mediator->m_res.value(), r2); + QCOMPARE(m.resource(key).value(), r2); + QCOMPARE(m.resource(complex1).toInt(), 15); + QCOMPARE(m.resource(complex2).toInt(), 25); + + QCOMPARE(spy[0][0].toInt(), key); + QCOMPARE(spy[0][1].value(), r2); + QCOMPARE(spy[1][0].toInt(), complex2); + QCOMPARE(spy[1][1].toInt(), 25); + QCOMPARE(spy[2][0].toInt(), complex1); + QCOMPARE(spy[2][1].toInt(), 15); + spy.clear(); + + // #################################################### + // Change a derived resource + // #################################################### + m.setResource(complex1, 16); + + QCOMPARE(mediator->m_res.value(), r2); + QCOMPARE(m.resource(key).value(), r2); + QCOMPARE(m.resource(complex1).toInt(), 16); + QCOMPARE(m.resource(complex2).toInt(), 25); + + QCOMPARE(spy[0][0].toInt(), complex1); + QCOMPARE(spy[0][1].toInt(), 16); + spy.clear(); + + // #################################################### + // Change another derived resource + // #################################################### + m.setResource(complex2, 26); + + QCOMPARE(mediator->m_res.value(), r2); + QCOMPARE(m.resource(key).value(), r2); + QCOMPARE(m.resource(complex1).toInt(), 16); + QCOMPARE(m.resource(complex2).toInt(), 26); + + QCOMPARE(spy[0][0].toInt(), complex2); + QCOMPARE(spy[0][1].toInt(), 26); + spy.clear(); + + // #################################################### + // Switch back the whole source resource + // #################################################### + m.setResource(key, QVariant::fromValue(r1)); + + QCOMPARE(mediator->m_res.value(), r1); + QCOMPARE(m.resource(key).value(), r1); + QCOMPARE(m.resource(complex1).toInt(), 10); + QCOMPARE(m.resource(complex2).toInt(), 20); + + QCOMPARE(spy[0][0].toInt(), key); + QCOMPARE(spy[0][1].value(), r1); + QCOMPARE(spy[1][0].toInt(), complex2); + QCOMPARE(spy[1][1].toInt(), 20); + QCOMPARE(spy[2][0].toInt(), complex1); + QCOMPARE(spy[2][1].toInt(), 10); + spy.clear(); + + // #################################################### + // The value keep unchanged case! + // #################################################### + m.setResource(complex1, 10); + + QCOMPARE(mediator->m_res.value(), r1); + QCOMPARE(m.resource(key).value(), r1); + QCOMPARE(m.resource(complex1).toInt(), 10); + QCOMPARE(m.resource(complex2).toInt(), 20); + + QCOMPARE(spy.size(), 0); + spy.clear(); + + // #################################################### + // While switching a complex resource one derived value + // is kept unchanged + // #################################################### + r2->m_resources[complex1] = 10; + m.setResource(key, QVariant::fromValue(r2)); + + QCOMPARE(mediator->m_res.value(), r2); + QCOMPARE(m.resource(key).value(), r2); + QCOMPARE(m.resource(complex1).toInt(), 10); + QCOMPARE(m.resource(complex2).toInt(), 26); + + QCOMPARE(spy[0][0].toInt(), key); + QCOMPARE(spy[0][1].value(), r2); + QCOMPARE(spy[1][0].toInt(), complex2); + QCOMPARE(spy[1][1].toInt(), 26); + spy.clear(); + + // #################################################### + // No devived values are changed! + // #################################################### + *r1 = *r2; + m.setResource(key, QVariant::fromValue(r1)); + + QCOMPARE(mediator->m_res.value(), r1); + QCOMPARE(m.resource(key).value(), r1); + QCOMPARE(m.resource(complex1).toInt(), 10); + QCOMPARE(m.resource(complex2).toInt(), 26); + + QCOMPARE(spy[0][0].toInt(), key); + QCOMPARE(spy[0][1].value(), r1); + spy.clear(); + + // #################################################### + // Try to set the same pointer. No signals emitted! + // #################################################### + m.setResource(key, QVariant::fromValue(r1)); + + QCOMPARE(mediator->m_res.value(), r1); + QCOMPARE(m.resource(key).value(), r1); + QCOMPARE(m.resource(complex1).toInt(), 10); + QCOMPARE(m.resource(complex2).toInt(), 26); + + QCOMPARE(spy.size(), 0); + spy.clear(); + + + // #################################################### + // Internals 'officially' changed, but the values not + // #################################################### + mediator->forceNotify(); + + QCOMPARE(spy.size(), 0); + spy.clear(); + + // #################################################### + // We changed the values, but didn't notify anyone :) + // #################################################### + r1->m_resources[complex1] = 11; + r1->m_resources[complex2] = 21; + + mediator->forceNotify(); + + QCOMPARE(spy[0][0].toInt(), complex2); + QCOMPARE(spy[0][1].toInt(), 21); + QCOMPARE(spy[1][0].toInt(), complex1); + QCOMPARE(spy[1][1].toInt(), 11); + spy.clear(); +} + + QTEST_MAIN(TestResourceManager) diff --git a/libs/flake/tests/TestResourceManager.h b/libs/flake/tests/TestResourceManager.h index a0ef6826ae..947361db43 100644 --- a/libs/flake/tests/TestResourceManager.h +++ b/libs/flake/tests/TestResourceManager.h @@ -1,35 +1,36 @@ /* This file is part of the KDE project Copyright (C) 2008 Thorsten Zachmann 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 TESTRESOURCEMANAGER_H #define TESTRESOURCEMANAGER_H #include class TestResourceManager : public QObject { Q_OBJECT private Q_SLOTS: void koShapeResource(); void testUnitChanged(); void testConverters(); void testDerivedChanged(); + void testComplexResource(); }; #endif // TESTRESOURCEMANAGER_H diff --git a/libs/global/kis_global.h b/libs/global/kis_global.h index af079e3217..785cd338bf 100644 --- a/libs/global/kis_global.h +++ b/libs/global/kis_global.h @@ -1,282 +1,323 @@ /* * Copyright (c) 2000 Matthias Elter * Copyright (c) 2002 Patrick Julien * * 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 KISGLOBAL_H_ #define KISGLOBAL_H_ #include #include #include "kis_assert.h" #include #include const quint8 quint8_MAX = UCHAR_MAX; const quint16 quint16_MAX = 65535; const qint32 qint32_MAX = (2147483647); const qint32 qint32_MIN = (-2147483647 - 1); const quint8 MAX_SELECTED = UCHAR_MAX; const quint8 MIN_SELECTED = 0; const quint8 SELECTION_THRESHOLD = 1; enum OutlineStyle { OUTLINE_NONE = 0, OUTLINE_CIRCLE, OUTLINE_FULL, OUTLINE_TILT, OUTLINE_COLOR, N_OUTLINE_STYLE_SIZE }; enum CursorStyle { CURSOR_STYLE_NO_CURSOR = 0, CURSOR_STYLE_TOOLICON, CURSOR_STYLE_POINTER, CURSOR_STYLE_SMALL_ROUND, CURSOR_STYLE_CROSSHAIR, CURSOR_STYLE_TRIANGLE_RIGHTHANDED, CURSOR_STYLE_TRIANGLE_LEFTHANDED, CURSOR_STYLE_BLACK_PIXEL, CURSOR_STYLE_WHITE_PIXEL, N_CURSOR_STYLE_SIZE }; enum OldCursorStyle { OLD_CURSOR_STYLE_TOOLICON = 0, OLD_CURSOR_STYLE_CROSSHAIR = 1, OLD_CURSOR_STYLE_POINTER = 2, OLD_CURSOR_STYLE_OUTLINE = 3, OLD_CURSOR_STYLE_NO_CURSOR = 4, OLD_CURSOR_STYLE_SMALL_ROUND = 5, OLD_CURSOR_STYLE_OUTLINE_CENTER_DOT = 6, OLD_CURSOR_STYLE_OUTLINE_CENTER_CROSS = 7, OLD_CURSOR_STYLE_TRIANGLE_RIGHTHANDED = 8, OLD_CURSOR_STYLE_TRIANGLE_LEFTHANDED = 9, OLD_CURSOR_STYLE_OUTLINE_TRIANGLE_RIGHTHANDED = 10, OLD_CURSOR_STYLE_OUTLINE_TRIANGLE_LEFTHANDED = 11 }; /* * Most wacom pads have 512 levels of pressure; Qt only supports 256, and even * this is downscaled to 127 levels because the line would be too jittery, and * the amount of masks take too much memory otherwise. */ const qint32 PRESSURE_LEVELS = 127; const double PRESSURE_MIN = 0.0; const double PRESSURE_MAX = 1.0; const double PRESSURE_DEFAULT = PRESSURE_MAX; const double PRESSURE_THRESHOLD = 5.0 / 255.0; // copy of lcms.h #define INTENT_PERCEPTUAL 0 #define INTENT_RELATIVE_COLORIMETRIC 1 #define INTENT_SATURATION 2 #define INTENT_ABSOLUTE_COLORIMETRIC 3 #include #include #ifndef M_PI #define M_PI 3.14159265358979323846 #endif // converts \p a to [0, 2 * M_PI) range inline qreal normalizeAngle(qreal a) { if (a < 0.0) { a = 2 * M_PI + fmod(a, 2 * M_PI); } return a > 2 * M_PI ? fmod(a, 2 * M_PI) : a; } // converts \p a to [0, 360.0) range inline qreal normalizeAngleDegrees(qreal a) { if (a < 0.0) { a = 360.0 + fmod(a, 360.0); } return a > 360.0 ? fmod(a, 360.0) : a; } inline qreal shortestAngularDistance(qreal a, qreal b) { qreal dist = fmod(qAbs(a - b), 2 * M_PI); if (dist > M_PI) dist = 2 * M_PI - dist; return dist; } inline qreal incrementInDirection(qreal a, qreal inc, qreal direction) { qreal b1 = a + inc; qreal b2 = a - inc; qreal d1 = shortestAngularDistance(b1, direction); qreal d2 = shortestAngularDistance(b2, direction); return d1 < d2 ? b1 : b2; } template inline PointType snapToClosestAxis(PointType P) { if (qAbs(P.x()) < qAbs(P.y())) { P.setX(0); } else { P.setY(0); } return P; } template inline T pow2(const T& x) { return x * x; } template inline T kisDegreesToRadians(T degrees) { return degrees * M_PI / 180.0; } template inline T kisRadiansToDegrees(T radians) { return radians * 180.0 / M_PI; } template inline T kisGrowRect(const T &rect, U offset) { return rect.adjusted(-offset, -offset, offset, offset); } inline qreal kisDistance(const QPointF &pt1, const QPointF &pt2) { return std::sqrt(pow2(pt1.x() - pt2.x()) + pow2(pt1.y() - pt2.y())); } inline qreal kisSquareDistance(const QPointF &pt1, const QPointF &pt2) { return pow2(pt1.x() - pt2.x()) + pow2(pt1.y() - pt2.y()); } #include inline qreal kisDistanceToLine(const QPointF &m, const QLineF &line) { const QPointF &p1 = line.p1(); const QPointF &p2 = line.p2(); qreal distance = 0; if (qFuzzyCompare(p1.x(), p2.x())) { distance = qAbs(m.x() - p2.x()); } else if (qFuzzyCompare(p1.y(), p2.y())) { distance = qAbs(m.y() - p2.y()); } else { qreal A = 1; qreal B = - (p1.x() - p2.x()) / (p1.y() - p2.y()); qreal C = - p1.x() - B * p1.y(); distance = qAbs(A * m.x() + B * m.y() + C) / std::sqrt(pow2(A) + pow2(B)); } return distance; } inline QPointF kisProjectOnVector(const QPointF &base, const QPointF &v) { const qreal prod = base.x() * v.x() + base.y() * v.y(); const qreal lengthSq = pow2(base.x()) + pow2(base.y()); qreal coeff = prod / lengthSq; return coeff * base; } #include inline QRect kisEnsureInRect(QRect rc, const QRect &bounds) { if(rc.right() > bounds.right()) { rc.translate(bounds.right() - rc.right(), 0); } if(rc.left() < bounds.left()) { rc.translate(bounds.left() - rc.left(), 0); } if(rc.bottom() > bounds.bottom()) { rc.translate(0, bounds.bottom() - rc.bottom()); } if(rc.top() < bounds.top()) { rc.translate(0, bounds.top() - rc.top()); } return rc; } #include template inline QSharedPointer toQShared(T* ptr) { return QSharedPointer(ptr); } template class List> List> listToQShared(const List list) { List> newList; Q_FOREACH(A* value, list) { newList.append(toQShared(value)); } return newList; } + +/** + * Convert a list of strong pointers into a list of weak pointers + */ +template